2024年2月19日发(作者:)
1.窗口最大最小化按纽的控制
①怎样在程序开始的时候让它最大化?
②vC 做出来的exe文件在窗体的右上方是没有最大化和最小化按钮的,怎样实现这一功能?
③如何在显示窗口时,使最大化按钮变灰?
①在App类里的C…App::InitInstance()中把m_pMainWnd->ShowWindow(SW_SHOW)改成m_pMainWnd->ShowWindow(SW_MAXIMIZE);
②在CreateWidnow时用WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX 风格.
③ 第一种方法:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
// disable the maxmini box
&= ~WS_MAXIMIZEBOX;
return TRUE;
}
第二种方法:
CMenu *pMenu=AfxGetApp()->m_pMainWnd->GetSystemMenu(FALSE);
int x=pMenu->GetMenuItemCount( );
UINT pID=pMenu->GetMenuItemID(x-1);
pMenu->EnableMenuItem(pID, MF_DISABLED);
第三种方法:
ModifyStyle(WS_MAXIMIZEBOX, 0);
这个函数也可以是最大化按钮失效!
并且可以在程序中动态的改变窗口的风格
2.创建动态菜单
void CMainFrame::OnSelectState(NMTOOLBAR* pnmtb, LRESULT *plr)
{
//
}
CMenu menu;
if(!Menu())
return;
Menu(MF_STRING,0,"开始");
Menu(MF_STRING,0,"结束");
CRect rc;
m_ssage(TB_GETRECT, pnmtb->iItem, (LPARAM)&rc);
m_ToScreen(&rc);
enu( TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL,
, , this, &rc);
yMenu();
();
3.如何禁止对话框关闭按钮和浮动工具条上的系统菜单
1、禁止对话框中的关闭按钮有二种方法。
第一种方法,用ModiftMenu()涵数来实现:
CMenu* pMenu = this->GetSystemMenu(FALSE);
pMenu->ModifyMenu(SC_CLOSE,MF_BYCOMMAND | MF_GRAYED );
第二种方法,用EnableMenuItem()涵数来实现:
CMenu* pMenu = this->GetSystemMenu(FALSE);
pMenu->EnableMenuItem( SC_CLOSE, MF_BYCOMMAND|MF_GRAYED);
2、禁止浮动工具条上的系统菜单。
新建一个CToolBar的派生类CxxToolBar,在新类中的左键双击(CxxToolBar::OnLButtonDblClk(...))
和左键单击(CxxToolBar:: OnLButtonDown(...))涵数中分别加入下面代码既可:
if (IsFloating()) //工具条正在浮动状态中
{
CWnd* pMiniFrame;
CWnd* pDockBar;
pDockBar = GetParent();
pMiniFrame = pDockBar->GetParent();
//去除其上系统菜单
pMiniFrame->ModifyStyle(WS_SYSMENU, NULL);
//重绘工具条
pMiniFrame->ShowWindow(SW_HIDE);
pMiniFrame->ShowWindow(SW_SHOW);
}
3、禁止窗口最大化按钮
在PreCreateWindow()涵数中去掉WS_MAXIMIZEBOX风格显示既可。
BOOL CxxFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
{
&= ~WS_MAXIMIZEBOX;
return CFrameWnd::PreCreateWindow(cs);
}
4.如何将标题栏上的右键菜单屏蔽掉?
[解决方法]
右键菜单是系统菜单,只要将其WS_SYSMENU的属性去掉即可.
[程序实现]
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
........
long style = GetWindowLong(m_hWnd, GWL_STYLE);
style &= ~WS_SYSMENU;
SetWindowLong(m_hWnd, GWL_STYLE, style);
return 0;
}
5.修改标题栏高度
NONCLIENTMETRICS nm
调用SystemParametersInfo(SPI_GETNONCLIENTMETRICS,sizeof(nm),&nm,0)
重设SystemParametersInfo(SPI_SETNONCLIENTMETRICS,sizeof(nm),&nm,0)
6.窗口最大化、最小化及关闭的消息是什么?如何截获?
最大化、最小化将发送WM_SYSCOMMAND消息。要处理该消息,可以这么做:
1、在Form的头文件中添加:
void __fastcall RestrictMinimizeMaximize(TMessage &Msg);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_SYSCOMMAND, TMessage, RestrictMinimizeMaximize)
END_MESSAGE_MAP(TForm)
2、在Form的单元文件中添加:
void __fastcall TForm1::RestrictMinimizeMaximize(TMessage& Msg)
{
if ( == SC_MINIMIZE)
{
//
}
else if ( == SC_MAXIMIZE)
{
//
}
TForm::Dispatch(&Msg);
// or "else TForm::Dispatch(&Msg)" to trap
}
关闭窗口的消息为WM_CLOSE,C Builder提供了OnClose事件。
7.如何改变窗口标题?
[问题提出]
在应用程序的不同运行时期,要反映当前状态往往会修改应用程序标题.
[解决方法]
在MFC类库中提供了CWnd::SetWindowText函数,通过该函数可以改变任何窗体(包括控件)的标题.
改变主窗体的标题:
CWnd *m_pMainWnd;
m_pMainWnd=AfxGetMainWnd();
m_pMainWnd->SetWindowText(_T("改变标题"));
当改变多视MDI的子窗口的标题时,用:
GetParentFrame()->SetWindowText(_T("MDI Child改变标题"));
当改变按钮的标题时(假设按钮的ID=IDC_BUTTON1):
GetDlgItem(IDC_BUTTON1)->SetWindowText(_T("Button 改变标题"));
运行看看.
8.如何用VC 动态修改应用程序菜单
[问题提出]
本文将介绍一些使用CMenu的方法,如查找指定菜单,在指定选项前添加菜单项.....
[解决方法]
使用CWnd::GetMenu( )访问主菜单,GetMenu( )返回指向CMenu对象的指针,它有一些成员函数,答应我们修改一个菜单。
1) 如何实现找到一个菜单项:
步骤如下:
{
//动态修改菜单:
// Get the Main Menu
CMenu* pMainMenu = AfxGetMainWnd()->GetMenu();
CMenu* pSubMenu = NULL;
int i;
for (i=0; i<(int)pMainMenu->GetMenuItemCount(); i )
{
pSubMenu = pMainMenu->GetSubMenu(i);
if (pSubMenu && pSubMenu->GetMenuItemID(0) == ID_FILE_NEW)
break;
}
CString s;
("%d",i);//菜单项的位数.
AfxMessageBox(s);
ASSERT(pSubMenu);
}
2) 动态编辑菜单:
步骤如下(可以用上例的pSubMenu,要加的菜单你自己定义.):
1) 添加一个称为Wzd2,命令ID为IDC_NAME_NEW1的菜单命令到该菜单中,可以用:
pSubMenu->AppendMenu(0,IDC_NAME_NEW1,"New&1");
2) 在New1前插入New2,可以用:
pSubMenu->InsertMenu(IDC_NAME_NEW1,MF_BYCOMMAND,IDC_NAME_NEW2,
"New&2");
3) 把New1改变成New3,可以用:
pSubMenu->ModifyMenu(IDC_NAME_NEW1,MF_BYCOMMAND,IDC_NAME_NEW3,
"New&3");
4) 删除该菜单中第二项,可以用:
pSubMenu->RemoveMenu(1,MF_BYPOSITION);
9.屏蔽掉子框架的右上角的关闭按钮
int CChildFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMDIChildWnd::OnCreate(lpCreateStruct) == -1)
return -1;
。。。
CMenu* pSysMenu = GetSystemMenu(FALSE);
pSysMenu->EnableMenuItem(SC_CLOSE,MF_BYCOMMAND
|MF_DISABLED|MF_GRAYED);
return 0;
}
10.隐藏标题栏和菜单栏
隐藏标题栏 ModifyStyle(WS_CAPTION,0)
隐藏菜单栏 SetMenu(NULL)
11.动态增加或删除菜单
1、 增加菜单
添加
CMenu *mainmenu;
mainmenu=AfxGetMainWnd()->GetMenu(); //得到主菜单
(mainmenu->GetSubMenu (0))->AppendMenu (MF_SEPARATOR);//添加分隔符
(mainmenu->GetSubMenu (0))->AppendMenu(MF_STRING,ID_APP_ABOUT,
_T("Always on &Top")); //添加新的菜单项
DrawMenuBar(); //重画菜单
2、 删除菜单
删除
CMenu *mainmenu;
mainmenu=AfxGetMainWnd()->GetMenu(); //得到主菜单
CString str ;
for(int i=(mainmenu->GetSubMenu (0))->GetMenuItemCount()-1;i>=0;i--) //取得菜单的项数。
{
(mainmenu->GetSubMenu (0))->GetMenuString(i,str,MF_BYPOSITION);
//将指定菜单项的标签拷贝到指定的缓冲区。MF_BYPOSITION的解释见上。
if(str=="Always on &Top") //假如是刚才我们增加的菜单项,则删除。
{
(mainmenu->GetSubMenu (0))->DeleteMenu(i,MF_BYPOSITION);
break;
}
}
12.另一种改变窗口标题的方法
使用语句 CWnd* m_pCWnd = AfxGetMainWnd( ),然后,再以如下形式调用SetWindowText()函数:
SetWindowText( *m_pCWnd,(LPCTSTR)m_WindowText);// m_WindowText可以是一个CString类的变量。
13.上下文菜单事件触发事件
OnContextMenu事件
14.显示和隐藏程序菜单
CWnd *pWnd=AfxGetMainWnd();
if(b_m) //隐藏菜单
{
pWnd->SetMenu(NULL);
pWnd->DrawMenuBar();
b_m=false;
}
else
{
CMenu menu;
nu(IDR_MAINFRAME); ////显示菜单 也可改变菜单项
pWnd->SetMenu(&menu);
pWnd->DrawMenuBar();
b_m=true;
();
}
去掉最大化按钮
1.
BOOL MyDlg::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Add your specialized code here and/or call the base class
&= ~WS_MAXIMIZEBOX;
return CDialog::PreCreateWindow(cs);
}
Style(WS_MAXIMIZEBOX,0);
VC6.0中如何改变对话框的背景颜色
---- 方法一:调用CWinApp类的成员函数SetDialogBkColor来实现。
---- 其中函数的第一个参数指定了背景颜色,第二个参数指定了文本颜色。下面的例子是将应用程序对话框设置为蓝色背景和红色文本,步骤如下:
---- ① 新建一个基于Dialog的MFC AppWizard应用程序ExampleDlg。
---- ② 在CExampleDlgApp ::InitInstance()中添加如下代码:
BOOL CExampleDlgApp: : InitInstance ( )
{
...
CExampleDlgDlg dlg;
m_pMainWnd = &dlg;
//先于DoModal()调用,将对话框设置为蓝色背景、红色文本
SetDialogBkColor(RGB(0,0,255),RGB(255,0,0));
int nResponse = l();
...
}
---- 编译并运行,此时对话框的背景色和文本色已发生了改变。值得注意的是:在调用DoModal()之前必须先调用SetDialogBkColor,且此方法是将改变应用程序中所有的对话框颜色,并不能针对某一个指定的对话框。
---- 方法二:重载OnPaint(),即WM_PAINT消息。有关代码如下(以上例工程为准):
void CExampleDlgDlg::OnPaint()
{
if (IsIconic())
...
else
{
CRect rect;
CPaintDC dc(this);
GetClientRect(rect);
lidRect(rect,RGB(0,255,0)); //设置为绿色背景
CDialog::OnPaint();
}
---- 方法三:重载OnCtlColor (CDC* pDC, CWnd* pWnd, UINT nCtlColor),即WM_CTLCOLOR消息。具体步骤如下(以上例工程为准):
---- ①在CExampleDlgDlg的头文件中,添加一CBrush的成员变量:
class CExampleDlgDlg : public CDialog
{
...
protected:
CBrush m_brush;
...
};
---- ②在OnInitDialog()函数中添加如下代码:
BOOL CExampleDlgDlg::OnInitDialog()
{
...
// TODO: Add extra initialization here
m_SolidBrush(RGB(0, 255, 0)); // 生成一绿色刷子
...
}
---- ③利用ClassWizard重载OnCtlColor(...),即WM_CTLCOLOR消息:
HBRUSH CExampleDlgDlg::OnCtlColor
(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
/*
** 这里不必编写任何代码!
**下行代码要注释掉
** HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
*/
return m_brush; //返加绿色刷子
}
---- 方法四:还是重载OnCtlColor (CDC* pDC, CWnd* pWnd, UINT nCtlColor),即WM_CTLCOLOR消息。具体步骤如下(以上例工程为准):
---- 步骤①、②同上方法三中的步骤①、②。
---- 步骤③利用ClassWizard重载OnCtlColor(...)(即WM_CTLCOLOR消息)时则有些不同:
HBRUSH CExampleDlgDlg::OnCtlColor
(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
//在这加一条是否为对话框的判断语句
if(nCtlColor ==CTLCOLOR_DLG)
return m_brush; //返加绿色刷子
return hbr;
}
1、隐藏鼠标
int i = ShowCursor(FALSE);
for ( i; i >= 0 ;i-- )
{
ShowCursor(FALSE);
}
2、显示鼠标
int i = ShowCursor(TRUE);
for ( i;i<= 0;i++ )
{
ShowCursor(TRUE);
}
在MFC程序中显示JPG/GIF图像
如果你是一个使用VB编程的程序员,要在程序中显示JPG或者GIF图像简直易如反掌,将图像控件拖到Form中,分分钟即可搞掂。但是C++程序员要显示同样的图形却没有那么轻松,那么是不是要自己编写JPG解压缩代码呢?当然不用那么复杂啦!本文将针对这个问题讨论如何在MFC中显示JPG或者GIF图像。
用VB写图像显示程序之所以如此轻松,完全是利用了琳琅满目的图像处理控件,把你想要做的事情都一一搞掂。而C++程序员为了实现相同的功能必须忙乎半天。其实,C/C++程序员也能使用那些VB程序员所用的(或者说几乎一样的)图像控件。VB用的图像控件实际上都基于一个系统级COM类——IPicture。下面是有关 IPicture 的方法描述:
方法
get_Handle
get_Hpal
get_Type
get_Width
get_Height
Render
描述
返回图像对象的Windows GDI句柄
返回图像对象当前使用的调色板拷贝
返回当前图像对象的的图像类型
返回当前图像对象的图像宽度
返回当前图像对象的图像高度
在指定的位置、指定的设备上下文上绘制指定的图像部分
set_Hpal
get_CurDC
SelectPicture
设置当前图像的调色板
返回当前选中这个图像的设备上下文
将一个位图图像选入给定的设备上下文,返回选中图像的设备上下文和图像的GDI句柄
返回图像对象KeepOriginalFormat 属性的当前值
get_KeepOriginalForma
put_KeepOriginalFormat
设置图像对象的KeepOriginalFormat 属性
PictureChanged
SaveAsFile
get_Attributes
通知图像对象它的图像资源改变了
将图像数据存储到流中,格式与存成文件格式相同
返回图像位属性当前的设置
从上面这个表可以看出,IPicture操纵着图像对象及其属性。图像对象提供对位图的抽象,而Windows负责BMP、JPG和GIF位图的标准实现。程序员要做的只是实例化IPicture,然后调用其Render函数。与通常使用接口的方式不同,这里实例的创建我们不用CoCreateInstance函数,而是用一个专门的函数OleLoadPicture。
IStream* pstm = // 需要一个流(stream)
IPicture* pIPicture;
hr = OleLoadPicture(pstm, 0, FALSE, IID_IPicture, (void**)&pIPicture);
OleLoadPicture从流中加载图像并创建一个可用来显示图像的新IPicture对象。
rc = // 显示图像的矩形
// 将rc 转换为 HIMETRIC
spIPicture->Render(pDC, rc);
IPicture 负责处理所有琐事,以便确定图形之格式,如 Windows 位图、JPEG或者GIF文件——甚至是图标和元文件(metafiles)。当然啦,所有这些的实现细节是需要技巧的,为此我写了一个Demo程序Myimgapp(如图二)来示范这些IPicture的使用方法。
图一 Myimgapp的运行画面
Myimgapp是个典型的MFC文档/视图程序,在编写这个程序之前,我首先对 IPicture COM接口进行封装,之所以要这么做,主要是考虑到并不是每一个程序员都能熟练运用COM接口进行编程,另外将IPicture的主要功能封装在C++类中可以使我们的问题更容易解决,我封装的这个C++类名字叫做CPicture。它的定义和实现细节请参考本文提供的源代码。
我在这个类中将复杂而陌生的COM风格的参数映射成MFC程序员更为熟悉的类型。例如,CPicture可以让你直接从文件名加载一幅图像,CFile或者CArchive,而不用去处理流,CPicture::Render替你完成了IPicture中所有令人讨厌的但又是必须的HIMETRIC平滑转换工作。CPicture甚至具备了一个Load函数,它可以从资源数据中加载图像,所以你只要用下面的代码就可以显示资源中的图像:
CPicture pic(ID_MYPIC); // 加载图像
CRect rc(0,0,0,0); // 使用缺省的rc
(pDC, rc); // 显示图像
CPicture::Render提供一个显示图片的矩形。IPicture 对图像进行延伸处理。如果传递一个空矩形,则CPicture用图像本身的大小--不进行延伸处理。对于图像本身而言,CPicture查找"IMAGE"类型的资源,所以在资源文件中你必须要加入下面的代码:
IDR_MYPIC IMAGE MOVEABLE PURE ""
CPicture是个很棒的傻瓜类,它具备一个 ATL 智能指针CComQIPtr指向IPicture接口,通过调用OleLoadPicture来初始化不同的Load函数。CPicture提供了常用的打包函数来调用底层的IPicture。CPicture只封装了那些在Demo例子程序中要用到的方法。如果你需要调用IPicture::get_Handle或其它一些很少用到的IPicture方法,你可以自己尝试编写相应的打包代码。 另外,在编写完CPicture之后,我发现了一个现成的MFC类——CPictureHolder,这个类的功能几乎与CPicture完全一样,你可以在afxctl.h文件中找到它的定义。 前面说过,Demo例子是个典型的MFC文档/视图应用程序,因此它肯定少不了与文档和视图类相对应的CPictureDoc 和CPictureView:
CPictureDoc类没有什么特别的处理代码,它用CPicture对象存储图像:
class CPictureDoc : public CDocument {
protected:
CPicture m_pict; // the picture
};
并且CPictureDoc::Serialize 调用CPicture::Load 从MFC存档的数据中读取图像。
void CPictureDoc::Serialize(CArchive& ar)
{
if (ing()) {
m_(ar);
}
}
为了使Myimgapp程序更实用,CPictureDoc::OnNewDocument从程序资源数据加载了一幅图像。为了显示这幅图像,CPictureView::OnDraw要调用CPicture::Render。这样程序一启动便会显示一幅默认的图像。
void CPictureView::OnDraw(CDC* pDC)
{
CPictureDoc* pDoc = GetDocument();
CPicture* ppic = pDoc->GetPicture();
CRect rc;
GetImageRect(rc);
ppic->Render(pDC,rc);
}
GetImageRect是CPictureView类的一个成员函数,作用是根据当前Myimgapp的缩放比率(可用25%、33%、50%、75%、100%或自适应方式)获取图像矩形。GetImageRect调用CPicture::GetImageSize来获得真正的图像大小,然后根据比率显示。 CPictureView其余的部分完全和CScrollView的做法差不多,初始化视图并设置滚动大小,处理命令等等。唯一让人操心的是IPicture::Render中HIMETRIC的处理问题,因为标准的MFC应用程序都使用MM_TEXT映射模型。不用担心,CPicture::Render和CPicture::GetImageSize会将这一切转换过来,所以你不必为这些事情伤神。 CPictureView有一个消息处理器值得一提:它就是OnEraseBkgnd,当要显示的图像比客户区小的时候,这个函数必须绘制空白区域,如图二,OnEraseBkgnd创建一个与图像大小相等的切边(clip)矩形,然后将客户区填成黑色。之所以要创建切边矩形,主要是避免当改变窗口大小时出现的抖动——FillRect不绘制切边矩形内的区域,此乃Windows图形处理的常识。
图二 OnEraseBkgnd 填充修剪的图像
IPicture/CPicture简化了图像的显示。它甚至可以实现调色板的识别这样复杂的处理。你完全
可以抛开老式DIB 图像绘制方法,如加载调色板、BitBlts、StretchBlts等等——这一切IPicture全都可以搞掂。如果你未曾用IPicture显示过图像,那么现在试试吧。 CPictureView完成图像浏览的任务看来不是什么难事了。但是如果要把一幅图像添加到一个对话框或者其它的什么窗口中怎么办呢?为此我创建了另外一个类——CPictureCtrl。
CPictureCtrl 使你可以在任何对话框或窗口中把图像作为子窗口显示。例如:
class CAboutDialog : public CDialog {
protected:
CPictureCtrl m_wndPict;
virtual BOOL OnInitDialog();
};
BOOL CAboutDialog::OnInitDialog()
{
m_ssDlgItem(IDC_MYIMAGE,this);
return CDialog::OnInitDialog();
}
假设你的对话框中有一个静态控制,它的ID=IDC_IMAGE,并且有一幅IMAGE资源的ID与之相同。则从CStaticLink派生出的CPictureCtrl还可以指定一个URL超链接(或者创建一个ID与此控制或图像的ID相同的串资源)。如果你指定了一个URL,则在图像上单击鼠标将启动默认浏览器访问URL。真是酷呆了。CPicture控制着CPicture对象并改写WM_PAINT消息处理例程,调用CPicture::Render代替通常的静态控制处理例程。处理细节请参见代码。打开Myimgapp程序的“关于”对话框就知道了。
VC6中图形显示技巧
随着计算机信息表示及实现的多媒体化,在许多学习软件、游戏软件,以及多媒体课件制作软件中,经常使用各种图形显示技巧,如图形的推拉、交错、雨滴状、百页窗、积木随机堆叠等显示模式。这样使画面变得更为生动活泼,更能吸引用户,也为更好地发挥软件的功能奠定了基础。本文就Visual C++ 6.0中实现图形的各种显示技巧的原理及具体方法做些探讨。基本原理
在Visual C++6.0中,显示位图的方法及过程如下:
1. 显示程序资源中的位图(位图的所有数据均存在于可执行文件中)
(1)从资源中装入位图
● 定义位图对象数据成员CBitmap m_Bitmap;
● 调用CBitmap成员函数LoadBitmap(),如m_tmap(IDB_BITMAP1);
● 传入LoadBitmap的参数是位图在图形编辑器中生成或从位图文件中引入时赋予的识别符。
(2)生成与位图相联系的内存设备情境对象
CDC MemDC;
CompatibleDC(NULL);
Object(&m_Bitmap);
(3)显示位图
CClientDC ClientDC(this);
BITMAP BM;
m_ect(sizeof(BM),&BM);
( X,Y, //目标设备逻辑横、纵坐标
h, ht, //显示位图的像素宽、高度
&MemDC,
//待显示位图数据的设备情境对象
0,0, //源数据中的横、纵坐标
SRCCOPY); //位操作方式
这种方法显示位图速度快,但不是很灵活,而且会使可执行文件增大。
2. 显示独立文件方式的位图(位图的所有数据独立于可执行文件)
HBITMAP *hBitmap; //定义位图对象句柄
BITMAP BM;
CDC MemDC;
CClientDC ClientDC(this);
CompatibleDC(&ClientDC);
hBitmap=(HBITMAP*):: LoadImage
( AfxGetInstanceHandle(),
//取得应用程序句柄
“”,
//位图文件名
IMAGE_BITMAP,
//类型为Windows位图
0,0,
LR_LOADFROMFILE);
//从文件中取位图数据
Object(hBitmap);
:: GetObject(hBitmap,sizeof(BM),&BM);
(……)
//使用格式与方法一同
这种方法显示位图速度较之前一种慢了一点,但其灵活性较大,可以任意变换位图文件,而无需重新编译源程序, 也减小了可执行文件的大小。
实现方法
下面介绍各种图形显示技巧的具体实现原理及方法。以下所有程序算法的实现均可放在视类(CView,也可视自己的需要放在其他类)中处理,且有必要进行如下的相关操作:
增加如下类成员变量:
BITMAP m_Bm;
//保存位图的宽、高度等数据
HBITMAP *m_hBitmap;
//保存位图数据句柄
CDC m_MemDC; //内存设备情境对象
在类构造函数中加入如下代码:
m_CompatibleDC(NULL); //产生内存设备情境对象
m_hBitmap=(HBITMAP *)::LoadImage(
//从文件中装入位图数据
AfxGetInstanceHandle(),
“”,
IMAGE_BITMAP,
0,0,
LR_LOADFROMFILE );
m_Object(m_hBitmap); //将位图选入内存设备情境对象
::GetObject(m_hBitmap,sizeof(m_Bm),&m_Bm);
1. 水平交错效果
原理:将内存设备情境对象(如MemDC)中的位图数据拆分成奇、偶扫描线两部分,其中奇数条扫描线由上往下移动,偶数条扫描线则由下往上移动,且两者同时进行。屏幕上的效果为分别由上下两端出现的较淡栅栏图形,逐渐相互靠近,直至整个位图完全清楚。垂直交错效果的实现原理与之类似。
程序算法:
int i,j;
for ( i=0; i<=m_ht; i+=2 )
{j = i;
while ( j>0 )
{hBlt(
//奇数,由上至下
0,j-1,
//目标设备逻辑横、纵坐标
m_h,1,
//显示位图的像素宽、高度
&m_MemDC,
//源位图设备情境对象
0,m_ht-(i-j-1),
//源位图的起始横、纵坐标
m_h,1,
//源位图的像素宽、高度
SRCCOPY);
hBlt(
//偶数,由下至上
0,m_ht-j,
//目标设备逻辑横、纵坐标
m_h,1,
//显示位图的像素宽、高度
&m_MemDC,
//源位图设备情境对象
0,i-j,
//源位图的起始横、纵坐标
m_h,1,
//源位图的像素宽、高度
SRCCOPY);
j-=2; }
// while ( j>0 )
Sleep(10);
}
//for ( i=0; i<=m_ht; i+ =2 )
2. 雨滴效果
原理:将内存设备情境对象(如MemDC)中位图数据的最后一条扫描线,顺序地从目标设备(如ClientDC)中待显示位图的第一条扫描线所在位置移动至最后一条处,并保留此条扫描线在屏幕上移动时留下的轨迹。接着再把MemDC中位图数据的倒数第二条扫描线,顺序地从目标设备(如ClientDC)中待显示位图的第一条扫描线所在位置移动至倒数第二条处。其余的扫描线依此类推。
程序算法:
int i,j;
for ( i=0; i<=m_ht; i++ )
{for ( j=0; j<=m_ht-i; j++ )
hBlt(
0,j,
//目标设备逻辑横、纵坐标
m_h,1,
//显示位图的像素宽、高度
&m_MemDC,
//源位图设备情境对象
0,m_ht-i,
//源位图的起始横、纵坐标
m_h,1,
//源位图的像素宽、高度
SRCCOPY);
Sleep(20);
}
//for ( i=0; i<=m_ht; i++ )
3. 百叶窗效果
原理:将内存设备情境对象(如MemDC)中的位图数据分成若干组,然后分别从第一组到最后一组进行搬移,第一次搬移每组中第一条扫描线到目标设备(如ClientDC)中待显示位图的相应位置,第二次搬移每组中第二条扫描线,接着第三条、第四条扫描线。
程序算法:
int i,stepi,j;
stepi=m_ht/10;
for ( i=0; i<=stepi; i++ )
{for ( j=0; j<10; j++ )
hBlt(
0,j*stepi+i,
//目标设备逻辑横、纵坐标
m_h,1,
//显示位图的像素宽、高度
&m_MemDC,
//源位图设备情境对象
0,j*stepi+i,
//源位图的起始横、纵坐标
m_h,1,
//源位图的像素宽、高度
SRCCOPY);
Sleep(20);
} //for ( i=0; i<=stepi; i++ )
4. 随机积木效果
原理:将内存设备情境对象(如MemDC)中的位图数据分成纵横十等份共一百组数据,然后随机地取出这一百组数据中的某一组显示到目标设备(如ClientDC)中待显示位图的相应位置,如此反复直到所有一百组数据均显示完毕为止。
程序算法:
int i,j,stepx,stepy,dispnum,x,y;
int pxy[10][10];
//使用本数组记录已显示过的数据组
for ( i=0; i<10; i++ )
for ( j=0; j<10; j++ )
pxy[i][j]=0;
stepx=m_h/10;
stepy=m_ht/10;
srand( (unsigned)time( NULL ) );
dispnum=0;
//记录已显示过的数据组的个数
while(1)
{ x=rand() % 10;
y=rand() % 10;
if ( pxy[x][y] )
//本组x,y所代表的数据组是否已显示过?
continue;
pxy[x][y]=1;
//表明本组x,y所代表的数据组已显示过
hBlt(
x*stepx, y*stepy,
//目标设备逻辑横、纵坐标
stepx,stepy,
//显示位图的像素宽、高度
&m_MemDC,
//源位图设备情境对象
x*stepx, y*stepy,
//源位图的起始横、纵坐标
stepx,stepy,
//源位图的像素宽、高度
SRCCOPY);
dispnum++;
if ( dispnum >=100 )
break;
Sleep(30);
} // while(1)
结 语
以上程序代码均在Visual C++ 6.0中调试通过,所有片断均可编写成独立的函数,灵活使用。如果对以上几种显示效果进行变换,我们还可以实现多种其他特技效果。


发布评论