CREATSTRUCT结构Word文档下载推荐.docx
《CREATSTRUCT结构Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《CREATSTRUCT结构Word文档下载推荐.docx(18页珍藏版)》请在冰豆网上搜索。
lpszClass指向一个以null结尾的字符串,指定了新窗口的Windows类名(一个WNDCLASS结构;
更多的信息参见Win32SDK文档)
dwExStyle指定了新窗口的扩展风格
C++是一种面向对象的可视化编程工具,它提供的AppWizard能自动生成应用程序的标准框架,大大减轻了编程的工作量。
本文主要介绍如下的编程技巧:
修改主窗口风格、创建不规则形状窗口、用鼠标单击窗口标题条以外区域移动窗口、使用上下文菜单、使应用程序只能运行一个实例、使应用程序显示为任务条通知区中的图标和显示旋转文本等。
1.修改主窗口风格
AppWizard生成的应用程序框架的主窗口具有缺省的窗口风格,比如在窗口标题条中自动添加文档名、窗口是叠加型的、可改变窗口大小等。
要修改窗口的缺省风格,需要重载CWnd:
:
PreCreateWindow(CREATESTRUCT&
cs)函数,并在其中修改CREATESTRUCT型参数cs。
CWnd:
PreCreateWindow函数先于窗口创建函数执行。
如果该函数被重载,则窗口创建函数将使用CWnd:
PreCreateWindow函数返回的CREATESTRUCTcs参数所定义的窗口风格来创建窗口;
否则使用预定义的窗口风格。
CREATESTRUCT结构定义了创建函数创建窗口所用的初始参数,其定义如下:
typedefstructtagCREATESTRUCT{
LPVOIDlpCreateParams;
//创建窗口的基本参数
HANDLEhInstance;
//拥有将创建的窗口的模块实例句柄
HMENUhMenu;
//新窗口的菜单句柄
HWNDhwndParent;
//新窗口的父窗口句柄
intcy;
//新窗口的高度
intcx;
//新窗口的宽度
inty;
//新窗口的左上角Y坐标
intx;
//新窗口的左上角X坐标
LONGstyle;
//新窗口的风格
LPCSTRlpszName;
//新窗口的名称
LPCSTRlpszClass;
//新窗口的窗口类名
DWORDdwExStyle;
//新窗口的扩展参数
}CREATESTRUCT;
CREATESTRUCT结构的style域定义了窗口的风格。
比如,缺省的MDI主窗口的风格中就包括FWS_ADDTOTITLE(在标题条中显示当前的工作文档名)、FWS_PREFIXTITLE(把文档名放在程序标题的前面)、WS_THICKFRAME(窗口具有可缩放的边框)等风格。
由于多种风格参数由逻辑或(“|”)组合在一起的,因此添加某种风格,就只需用“|”把对应的参数加到CREATESTRUCT结构的style域中;
删除已有的风格,则需用“&
”连接CREATESTRUCT结构的style域与该风格的逻辑非值。
CREATESTRUCT结构的x、y、cx、cy域分别定义了窗口的初始位置和大小,因此,在CWnd:
PreCreateWindow函数中给它们赋值,将能定义窗口的初始显示位置和大小。
下例中的代码将主框窗口的大小将固定为1/4屏幕,标题条中仅显示窗口名,不显示文档名。
BOOLCMainFrame:
cs)
{
//TODO:
ModifytheWindowclassorstylesherebymodifying
//theCREATESTRUCTcs
//修改主窗风格
cs.style&
=~FWS_ADDTOTITLE;
//去除标题条中的文档名
=~WS_THICKFRAME;
//去除可改变大小的边框
cs.style|=WS_DLGFRAME;
//增加不能改变大小的边框
//确定主窗的大小和初始位置
intcxScreen=:
GetSystemMetrics(SM_CXSCREEN);
//获得屏幕宽
intcyScreen=:
GetSystemMetrics(SM_CYSCREEN);
//获得屏幕高
cs.x=0;
//主窗位于左上角
cs.y=0;
cs.cx=cxScreen/2;
//主窗宽为1/2屏幕宽
cs.cy=cxScreen/2;
//主窗高为1/2屏幕高
returnCMDIFrameWnd:
PreCreateWindow(cs);
}
2.创建不规则形状窗口
标准的Windows窗口是矩形的,但在有些时候我们需要非矩形的窗口,比如圆形的、甚至是不规则的。
借助CWnd类的SetWindowRgn函数可以创建不规则形状窗口。
SetWindowRgn的函数原型如下:
intSetWindowRgn(HRGNhRgn,//窗口区域句柄
BOOLbRedraw);
//是否重画窗口
CRgn类封装了关于区域的数据和操作。
通过(HRGN)强制操作可以从CRgn类中取得其HRGN值。
CRgn提供了CreateRectRgn、CreateEllipticRgn和CreatePolygonRgn成员函数,分别用以创建矩形、(椭)圆形和多边形区域。
创建非矩形窗口的方法如下:
首先,在窗口类中定义区域类成员数据(如CRgnm_rgnWnd);
其次,在窗口的OnCreate函数或对话框的OnInitDialog函数中调用CRgn类的CreateRectRgn、CreateEllipticRgn或CreatePolygonRgn函数创建所需的区域,并调用SetWindowRgn函数。
下例将生成一个椭圆窗口。
1.在DeveloperStudio中选取File菜单中的New命令,在出现的New对话框中选择创建MFCAppWizard(exe)框架应用程序,并输入项目名为EllipseWnd。
设定应用程序类型为基于对话框(Dialogbased),其它选项按缺省值创建项目源文件。
2.使用资源编辑器从主对话框(ID为IDD_ELLIPSEWND_DIALOG)删除其中的所有控制,并从其属性对话框(DialogProperties)中设定其风格为Popup、无标题条和边框。
3.在EllipseWndDlg.h源文件中给主对话框类CEllipseWndDlg增加一个CRgn类保护型数据成员m_rgnWnd,它将定义窗口的区域。
4.在EllipseWndDlg.cpp源文件中修改主对话框类CEllipseWndDlg的OnInitDialog()函数,增加m_rgnWnd的创建,并将其定义为窗口区域。
粗体语句为新增部分。
BOOLCEllipseWndDlg:
OnInitDialog()
CDialog:
OnInitDialog();
//Add"
About..."
menuitemtosystemmenu.
//IDM_ABOUTBOXmustbeinthesystemcommandrange.
ASSERT((IDM_ABOUTBOX&
0xFFF0)==IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX<
0xF000);
CMenu*pSysMenu=GetSystemMenu(FALSE);
if(pSysMenu!
=NULL)
CStringstrAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if(!
strAboutMenu.IsEmpty())
pSysMenu->
AppendMenu(MF_SEPARATOR);
AppendMenu(MF_STRING,IDM_ABOUTBOX,
strAboutMenu);
//Settheiconforthisdialog.Theframeworkdoesthisautomatically
//whentheapplication'
smainwindowisnotadialog
SetIcon(m_hIcon,TRUE);
//Setbigicon
SetIcon(m_hIcon,FALSE);
//Setsmallicon
//设置窗口标题为“椭圆窗口”,虽然对话框没有标题条,
//但在任务条的按钮中仍需要标题
SetWindowText(_T("
椭圆窗口"
));
//取得屏幕宽、高
//设置椭圆X、Y方向的半径
intnEllipseWidth=cxScreen/8;
intnEllipseHeight=cyScreen/8;
//将窗口大小设为宽nEllipseWidth,高nEllipseHeight
//并移至左上角
MoveWindow(0,0,nEllipseWidth,nEllipseHeight);
//创建椭圆区域m_rgnWnd
m_rgnWnd.CreateEllipticRgn(0,0,nEllipseWidth,nEllipseHeight);
//将m_rgnWnd设置为窗口区域
SetWindowRgn((HRGN)m_rgnWnd,TRUE);
returnTRUE;
//returnTRUEunlessyousetthefocustoacontrol
3.用鼠标单击窗口标题条以外区域移动窗口
移动标准窗口是通过用鼠标单击窗口标题条来实现的,但对于没有标题条的窗口,就需要用鼠标单击窗口标题条以外区域来移动窗口。
有两种方法可以达到这一目标。
方法一:
当窗口确定鼠标位置时,Windows向窗口发送WM_NCHITTEST消息,可以处理该消息,使得只要鼠标在窗口内,Windows便认为鼠标在标题条上。
这需要重载CWnd类处理WM_NCHITTEST消息的OnNcHitTest函数,在函数中调用父类的该函数,如果返回HTCLIENT,说明鼠标在窗口客户区内,使重载函数返回HTCAPTION,使Windows误认为鼠标处于标题条上。
下例是使用该方法的实际代码:
UINTCEllipseWndDlg:
OnNcHitTest(CPointpoint)
//取得鼠标所在的窗口区域
UINTnHitTest=CDialog:
OnNcHitTest(point);
//如果鼠标在窗口客户区,则返回标题条代号给Windows
//使Windows按鼠标在标题条上类进行处理,即可单击移动窗口
return(nHitTest==HTCLIENT)?
HTCAPTION:
nHitTest;
方法二:
当用户在窗口客户区按下鼠标左键时,使Windows认为鼠标是在标题条上,即在处理WM_LBUTTONDOWN消息的处理函数OnLButtonDown中发送一个wParam参数为HTCAPTION,lParam为当前坐标的WM_NCLBUTTONDOWN消息。
下面是使用该方法的实际代码:
voidCEllipseWndDlg:
OnLButtonDown(UINTnFlags,CPointpoint)
//调用父类处理函数完成基本操作
OnLButtonDown(nFlags,point);
//发送WM_NCLBUTTONDOWN消息
//使Windows认为鼠标在标题条上
PostMessage(WM_NCLBUTTONDOWN,
HTCAPTION,
MAKELPARAM(point.x,point.y));
4.使用上下文菜单
Windows95应用程序支持单击鼠标右键弹出上下文菜单的功能,这可通过处理WM_CONTEXTMENU消息来实现。
当在窗口内单击鼠标右键时,窗口将接收到WM_CONTEXTMENU消息,在该消息的处理函数内装载上下文菜单,并调用CMenu:
TrackPopupMenu函数便可显示上下文菜单。
CMenu:
TrackPopupMenu函数的原型如下:
BOOLTrackPopupMenu(UINTnFlags,//显示和选取方式标志
intx,inty,//显示菜单的左上角坐标
CWnd*pWnd,//接收菜单操作的窗口对象
LPCRECTlpRect=NULL);
//敏感区域
为了使用上下文菜单,首先应在资源编辑器中编制好上下文菜单,假设上下文菜单名为IDR_MENU_CONTEXT;
其次,用ClassWizard给窗口增加处理消息WM_CONTEXTMENU的函数OnContextMenu,以及各菜单命令的处理函数;
然后编写相应的代码。
下面的是OnContextMenu函数的代码实例:
OnContextMenu(CWnd*pWnd,CPointpoint)
CMenumenu;
//装入菜单
menu.LoadMenu(IDR_MENU_CONTEXT);
//显示菜单
menu.GetSubMenu(0)->
TrackPopupMenu(
TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON,
point.x,point.y,this);
5.使应用程序只能运行一个实例
Windows是多进程操作系统,框架生成的应用程序可以多次运行,形成多个运行实例。
但在有些情况下为保证应用程序的安全运行,要求程序只能运行一个实例,比如程序要使用只能被一个进程单独使用的特殊硬件(例如调制解调器)时,必须限制程序只运行一个实例。
这里涉及两个基本的问题,一是在程序的第二个实例启动时,如何发现该程序已有一个实例在运行,而是如何将第一个实例激活,而第二个实例退出。
对于第一个问题,可以通过给应用程序设置信号量,实例启动时首先检测该信号量,如已存在,则说明程序已运行一个实例。
第二个问题的难点是获取第一个实例的主窗对象指针或句柄,然后便可用SetForegroundWindow来激活。
虽然FindWindow函数能寻找正运行着的窗口,但该函数要求指明所寻找窗口的标题或窗口类名,不是实现通用方法的途径。
我们可以用Win32SDK函数SetProp来给应用程序主窗设置一个特有的标记。
用GetDesktopWindow可以获取Windows系统主控窗口对象指针或句柄,所有应用程序主窗都可看成该窗口的子窗口,即可用GetWindow函数来获得它们的对象指针或句柄。
用Win32SDK函数GetProp查找每一应用程序主窗是否包含有我们设置的特定标记便可确定它是否我们要寻找的第一个实例主窗。
使第二个实例退出很简单,只要让其应用程序对象的InitInstance函数返回FALSE即可。
此外,当主窗口退出时,应用RemoveProp函数删除我们为其设置的标记。
下面的InitInstance、OnCreate和OnDestroy函数代码将实现上述的操作:
BOOLCEllipseWndApp:
InitInstance()
//用应用程序名创建信号量
HANDLEhSem=CreateSemaphore(NULL,1,1,m_pszExeName);
//信号量已存在?
//信号量存在,则程序已有一个实例运行
if(GetLastError()==ERROR_ALREADY_EXISTS)
//关闭信号量句柄
CloseHandle(hSem);
//寻找先前实例的主窗口
HWNDhWndPrevious=:
GetWindow(:
GetDesktopWindow(),
GW_CHILD);
while(:
IsWindow(hWndPrevious))
//检查窗口是否有预设的标记?
//有,则是我们寻找的主窗
if(:
GetProp(hWndPrevious,m_pszExeName))
//主窗口已最小化,则恢复其大小
IsIconic(hWndPrevious))
ShowWindow(hWndPrevious,
SW_RESTORE);
//将主窗激活
SetForegroundWindow(hWndPrevious);
//将主窗的对话框激活
SetForegroundWindow(
GetLastActivePopup(hWndPrevious));
//退出本实例
returnFALSE;
//继续寻找下一个窗口
hWndPrevious=:
GetWindow(hWndPrevious,
GW_HWNDNEXT);
//前一实例已存在,但找不到其主窗
//可能出错了
AfxEnableControlContainer();
//Standardinitialization
//Ifyouarenotusingthesefeaturesandwishtoreducethesize
//ofyourfinalexecutable,youshouldremovefromthefollowing
//thespecificinitializationroutinesyoudonotneed.
#ifdef_AFXDLL
Enable3dControls();
//CallthiswhenusingMFCinasharedDLL
#else
Enable3dControlsStatic();
//CallthiswhenlinkingtoMFCstatically
#endif
CEllipseWndDlgdlg;
m_pMainWnd=&
dlg;
intnResponse=dlg.DoModal();
if(nResponse==IDOK)
Placecodeheretohandlewhenthedialogis
//dismissedwithOK
elseif(nResponse==IDCANCEL)
//dismissedwithCancel
//Sincethedialoghasbeenclosed,returnFALSEsothatweexitthe
//application,ratherthanstarttheapplication'
smessagepump.
intCEllipseWndDlg:
OnCreate(LPCREATESTRUCTlpCreateStruct)
if(CDialog:
OnCreate(lpCreateStruct)==-1)
return-1;
//设置寻找标记
SetProp(m_hWnd,AfxGetApp()->
m_pszExeName,(HANDLE)1);
return0;
OnDestroy()
OnDestroy();
//删除寻找标记
RemoveProp(m_hWnd,AfxGetApp()->
m_pszExeName);
6.使应用程序显示为任务条通知区中的图标
在Windows95任务条的右边有一个区域被称为通知区域,在其中可以显示一些应用程序的图标,用鼠标单击其中的图标一般能弹出应用程序的菜单,双击则能显示应用程序的完整窗口界面。
时钟和音量控制是任务条通知区最常见的图标。
任务条通知区编程可以通过Windows95外壳编程接口函数Shell_NotifyIcon来实现,该函数在shellapi.h头文件中声明,其原型如下:
WINSHELLAPIBOOLWINAPIShell_NotifyIcon(DWORDdwMessage,
PNOTIFYICONDATApnid);
dwMessage是对通知区图标进行操作的消息,主要有三中,如下表所示。
Shell_NotifyIcon使用的消息
消息
说明
NIM_ADD
在任务条通知区插入一个图标
NIM_DELETE
在任务条通知区删除一个图标
NIM_MODIFY
对任务条通知区的图标进行修改
pnid传入一个NOTIFYICONDATA结构的指针。
NOTIFYICONDATA结构声明及各域的意义表示如下:
typedefstruct_NOTIFYICONDATA{//nid
DWORDcbSize;
//NOTIFYICONDATA结构的字节数
HWNDhWnd;
//处理通知区图标消息的窗口句柄
UINTuID;
//通知区图标的ID
UINTuFlags;
//表示下述三项是否有意义的标志