我想我们现在已经解决大部分界面的问题了,但是我还想说说主窗口和菜单的问题。
我在程序中主窗口使用的是一个对话框。真个程序界面是一个对话框和放在对话框上面的控件(Combo Box,静态文本框等),我们把对话框称做父窗口,把上面的空间称做子窗口,其实不管对话框,各种控件等等都是窗口,他们都有自己的窗口过程,和应用程序的窗口过程一样,处理windows发送给这些窗口的消息,只不过,那些控件等的窗口过程都在windows内部,不需要你的程序去为他们写代码,也就是说,我们按下按钮这个窗口,windows内部的按钮窗口过程通过显示不同的图象使我们视觉以为按钮按了下去。
一般子窗口的消息除了发送给自己的窗口过程外也发送个父窗口,我们可以在父窗口过程中处理消息,一般是WM_COMMAND消息,在WM_COMMAND消息的参数中,我们可以提取出发送这个消息的子窗口的ID值和我们对子窗口进行操作的操作码,对应不同的控件有不同的操作码。
好了,既然对话框也是窗口,那么我们创建主窗口本质上也是调用CreateWindow函数。虽然我们可以简单的用CreateDialog和DialogBox函数来创建对话框,在这之前,我们还必须在资源编辑器中创建一个对话框模板以及设置一些你想要的属性。
就我自己的这个程序来看,我想具体谈谈CreateDialog函数。
HWND CreateDialog(
HINSTANCE hInstance, // handle to application instance
LPCTSTR lpTemplate, // identifies dialog box template name
HWND hWndParent, // handle to owner window
DLGPROC lpDialogFunc // pointer to dialog box procedure
);
hInstance参数是应用程序实例句柄。LpTemplate参数是对话框的模板名,也就是在资源编辑器中创建的对话框的名字,可以用LPSTR()强制类型转换一个ID值。HWndParent是父窗口的句柄。LpDialogFunc是对话框过程(注意不是对话框窗口过程)的函数入口地址,在我的程序中我将其设为NULL。函数返回对话框窗口句柄,在我的程序中也就是主窗口的窗口句柄。表面上看我们是用CreateDialog函数创建对话框,但是CreateDialog这个函数实际上利用上面的参数和模板中设置的属性调用CreateWindow函数创建一个窗口,细心的人应该发现,要调用CreateWindow函数应该还少了一个参数就是LPCTSTR lpClassName,这个参数指定窗口的窗口类,进而才能窗口过程联系起来。在资源编辑器中,不支持指定创建的对话框所属的窗口类,但是我们一样有办法指定,用文本编辑器打开工程的资源文件 *.rc文件,下面红色显示的就是我加的一句,其它都是资源编辑自动生成的。
SDKAUTOOFF DIALOG DISCARDABLE 0, 0, 318, 21
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
CLASS "SDKAutoOff"
用这个方法就可以指定对话框类,大家可以看到我指定的窗口类就是我程序中定义的窗口类,也就是说以后所有发送给对话框的消息都由我的程序定义的窗口过程来处理。在后面分别调用ShowWindow和UpdateWindow函数。至此应用程序的主窗口也就是对话框窗口创建完毕。
初看界面可能认为此程序没有菜单,实际上这个程序用到了两个菜单,一个是系统菜单,一个是点击右键时的弹出菜单。对于系统菜单我们可以加入下面的代码。
hMenu=GetSystemMenu(hwnd,FALSE);//得到系统菜单的的菜单句柄。 AppendMenu(hMenu,MF_STRING,IDM_SYS_ABOUT,"关于..."); //向系统菜单中加入一个项目,字串为"关于...",ID号为IDM_SYS_ABOUT。
对于右键点击的弹出菜单,我们可以加入下面的代码:
htaskmenu=LoadMenu(hInstance,szAppName);//读入菜单,获得菜单句柄。 htaskmenu=GetSubMenu(htaskmenu,0); //设置为点击弹出菜单
之后为了实现右键点击弹出菜单我们还必须加入下面的代码。
case WM_NOTIFYICON: //当对任务栏的图标操作时windows发送WM_NOTIFYICON消息
uID=wParam;//图标的ID值
uMsg=lParam;//用户对任务栏图标进行的是什么操作
if(uID==ID_NOTIFYICON)
{
switch(uMsg)
{
case WM_RBUTTONDOWN://如果是单击右键
GetCursorPos(&point);//获得单击的坐标位置
TrackPopupMenuEx(htaskmenu,TPM_VERTICAL|TPM_LEFTALIGN,point.x,point.y,hwnd,NULL);
//在单击的位置上显示弹出菜单
break;
}
}
return 0;
关于上面的消息和ID都在上一节说明过了,这里说说TrackPopupMenuEx函数,第一个参数是弹出的菜单句柄,第二个是一组标志,我们不必太关心它。后面分别是弹出的坐标值和包含这个菜单的窗口句柄。最后一个参数不需要太关心。这个函数在单击的位置上显示菜单。我在前面说的Bug也是出在这儿,前几天发个小朱的程序上面的代码是这样的
case WM_RBUTTONDOWN:
point.x=LOWORD(lParam);
point.y=HIWORD(lParam);
TrackPopupMenuEx(htaskmenu,TPM_VERTICAL|TPM_LEFTALIGN,point.x+250,point.y+570,hwnd,NULL);
break;
这段代码是很不科学的体现在point.x+250,point.y+570,开始我用的是point.x,point.y但是总不能在右下角显示出菜单,我也不知道为什么,现在也还是不知道,后来没办法只好加上估计值250,570后差不多能在我预想的地方显示了,但是只要我一点击系统菜单的"About…"菜单项后,即使右击任务栏图标后也不能显示菜单,我很奇怪,开始以为是MessageBox出了问题,后来测试了一下也不是,最后我想到了可能是点击菜单项后在右击任务栏图标,其中的lParam值变了,导致x和y的坐标值变了,再加上我那个估计值后超出了屏幕范围自然不会显示出来,后来证明确实是这样。我的那个同学后来提醒了我用函数来确定右击的位置,这确实是个好注意,于是我找到了GetCursorPos函数得到了正确的坐标值,于是问题消失。 至此,界面这个部分已经全部讲完了。