本篇文章讲如何创建一个基本的窗口。
MessageBox弹出来的消息框就是一个窗口,但是窗口是怎样创建的呢?其实很简单,只要几个固定的步骤就行。而只要我们的窗口创建出来之后,只要把需要的函数填进去就能得到一个有功能的窗口。所以我觉得学习Windows就是学习API函数而已,懂得如何调用,各个参数的意思就行。说到参数,其类型都是从C语言的基本数据类型演变而来的,并不难。
现在开始创建第一个窗口,该窗口并无功能,只是一个空的框架。
代码如下:
#include <windows.h>
//声明窗口过程函数
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("MyClass") ;
HWND hwnd ; //窗口句柄
MSG msg ; //消息结构
WNDCLASS wndclass ;//窗口类结构
//类风格
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;//窗口过程函数指针
wndclass.cbClsExtra = 0 ;//窗口类需要的额外空间
wndclass.cbWndExtra = 0 ;//窗口实例需要的额外空间
wndclass.hInstance = hInstance ;//程序应用实例句柄
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;//加载图标供程序使用。
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;//加载鼠标光标供程序使用。
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;//取得一个图形对象
//(在这个例子中,是取得绘制窗口背景的画刷对象)。
wndclass.lpszMenuName = NULL ; //窗口菜单
wndclass.lpszClassName = szAppName ;//窗口类名
//注册窗口类
if (!RegisterClass (&wndclass))
{
//显示消息框。
MessageBox (NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ;
return 0 ;
}
//根据窗口类别建立一个窗口。
hwnd = CreateWindow (szAppName, // 窗口类名
TEXT ("MyWin"), // 窗口标题
WS_OVERLAPPEDWINDOW|WS_VSCROLL|WS_HSCROLL,//窗口风格
CW_USEDEFAULT, // 窗口的x坐标,相对于屏幕左上角
CW_USEDEFAULT, // 窗口的x坐标,相对于屏幕左上角
CW_USEDEFAULT, // 窗口宽度(像素为单位)
CW_USEDEFAULT, // 窗口高度(像素为单位)
NULL, // 父窗口句柄
NULL, // 窗口菜单
hInstance, // 程序实例句柄
NULL) ; // (请看注释1)
//在屏幕上显示窗口
ShowWindow (hwnd, iCmdShow) ;
//指示窗口自我更新。
UpdateWindow (hwnd) ;
//从消息队列中取得消息
while (GetMessage (&msg, NULL, 0, 0))
{
//转译某些键盘消息。
TranslateMessage (&msg) ;
//将消息发送给系统,系统再将消息发送给窗口过程处理消息。
DispatchMessage (&msg) ;
}
// msg.wParam 来自一条表示退出的消息,返回这个值给系统,从而退出。
return msg.wParam ;
}
//窗口过程函数 //窗口句柄 //窗口消息 //第一个额外附加消息 //第二个额外附加消息
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc ;//设备环境
PAINTSTRUCT ps ;//绘画结构
//通常定义为静态变量是为了在不断的调用这个函数时该值不会改变
static int cxClient,cyClient;//客户区宽和高
//筛选消息,如果没有需要关注的消息,则有系统自动处理
switch (message)
{
//窗口创建消息,创建窗口时会有此消息
//注:创建窗口之前还会有很多消息进来,可以自己在
//switc中加断点调试看看有哪些消息进来
case WM_CREATE:
return 0;
//当客户区改变的时候,也就是发生大小变化
//就会传进来这个消息,然后两个参数会被改变
case WM_SIZE:
cxClient=LOWORD(lParam);
cyClient=HIWORD(lParam);
return 0;
//垂直滚动条信息
//记得在窗口风格中添加这两个风格
case WM_VSCROLL:
return 0 ;
//水平滚动条信息
case WM_HSCROLL:
return 0;
//重绘窗口消息
//每当窗口改变大小或者移动时都会发送重绘
case WM_PAINT:
//开始绘制窗口。
hdc = BeginPaint (hwnd, &ps) ;
//获取设备环境的方法不只这一种
//结束绘制窗口。
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY:
//在消息队列中插入一个「退出程序」消息
//该消息是WM_QUIT
PostQuitMessage (0) ;
return 0 ;
}
//除了需要关注的消息,其它消息都经由系统自动处理。
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
总结一下创建窗口的步骤:
1.创建并初始化窗口类
看过很多好文章,里面都会把创建窗口类比作一个品牌汽车的模板
2.注册窗口类
然后去为这个品牌注册登记
3.创建窗口
再然后用这个模板来创建同样品牌不同样式的汽车
4.显示、更新窗口
造好车后就要拿出去展示,并时不时的更新车辆信息
5.从消息循环队列中获取消息
把车卖出去后(显示窗口),会有客户把用户体验或者车辆问题反馈回来(消息),这肯定是需要排队的(队列),如果很紧急也可以插队。然后公司就会获取他们反馈的信息(系统),然后叫各种部门处理(窗口过程).
如此循环就是窗口了
HWND hwnd;//窗口句柄
UINT message;//一个无符号整形消息
WPARAM wParam;//16位(双字节(在16位系统的时间))的消息参数。
//值的款式和意思取决于重要的事件消息类型。
//注:在我的VS2008编译器中定义是64位的。
LPARAM lParam;//32位(长整型)的消息参数。这个参数的值和意思取决于主事件消息类型。
//注:在我的VS2008编译器中定义是64位的。
其在头文件中的定义如下:
typedef UINT_PTR WPARAM;
typedef LONG_PTR LPARAM;
typedef LONG_PTR LRESULT;
typedef _W64 unsigned int UINT_PTR, *PUINT_PTR;
typedef _W64 long LONG_PTR, *PLONG_PTR;
DefWindowProc:(解释转自百科)
函数功能:该函数调用缺省的窗口过程来为应用程序没有处理的任何窗口
消息提供缺省的处理。该函数确保每一个消息得到处理。
调用DefWindowProc函数时使用窗口过程接收的相同参数。
函数原型:LRESULT DefWindowProc(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);
参数:
hWnd:指向接收消息的窗口过程的句柄。
Msg:指定消息类型。
wParam:指定其余的、消息特定的信息。该参数的内容与Msg参数值有关。
IParam:指定其余的、消息特定的信息。该参数的内容与Msg参数值有关。
返回值:返回值就是消息处理结果,它与发送的消息有关。
现在窗口已经创建好了,骨架搭好了就剩下五脏六腑了,只要一步步完善这个骨架,最后就能写出一个界面程序了。
这里不详细解释每个结构体的参数是什么意思,因为没用到说了也白说,用了再去了解它,这样学习负担就不会很大。
看了这个那么长的代码也只是创建出一个空白的窗口,心里可能会有些失望,感觉好像很难,这是刚开始学习Windows程序设计都会遇到的坎坷。但是以后你写多了这个框架,你就会对里面各个参数有一点的理解,并且不之不觉中闭着眼睛都能写出这100多行代码。正所谓,都没有会走怎么可能会跑?所以还是慢慢走吧,总有一天会跑得飞起。
注释1:
lpParam:
指向一个值的指针,该值传递给窗口WM_CREATE消息。该值通过在IParam参数中的CREATESTRUCT结构传递。如果应用程序调用CreateWindow创建一个MDI客户窗口,则lpParam必须指向一个CLIENTCREATESTRUCT结构。