前阵子不造什么原因,空间发日志被限制,索性就开了个博客,点我进入,以后文章会同步到博客。
这节核心:掌握窗口的创建,还有其他的一些知识,教材依旧用我们的“圣经”。
我们能用MessageBox来向使用者输出文字,但我们还不知道,MessageBox实现的信息框实际上也是窗口的一种,只不过这种窗口不能显示图形、不能添加菜单。但现在,我们要建立自己的第一个真正的窗口。我们不可能凭空写出一个窗口,因此首先我采用的方法,是先分析程序,代码如下:
#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("MyWindows"); //定义一个静态的扩展字符名
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("这个程序需要在 Windows NT 才能执行!"), szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow( //创建窗口
szAppName, //窗口类名,面向程序员
TEXT("与窗口的第一次"), //窗口名,面向用户
WS_OVERLAPPEDWINDOW, //窗口风格
CW_USEDEFAULT, //指定窗口的初始水平位置
CW_USEDEFAULT, //指定窗口的初始垂直位置
CW_USEDEFAULT, //指明窗口的宽度
CW_USEDEFAULT, //指明窗口的高度
NULL, //指向被创建窗口的父窗口或所有者窗口的句柄
NULL, //菜单句柄
hInstance, //与窗口相关联的模块事例的句柄
NULL); //暂忽略
ShowWindow(hwnd, iCmdShow); //设置指定窗口的显示状态
UpdateWindow(hwnd); //暂忽略
while (GetMessage(&msg, NULL, 0, 0)) //从消息队列中获取消息并放在msg结构中
{
TranslateMessage(&msg); //将虚拟键消息转换为字符消息
DispatchMessage(&msg); //调度一个消息给窗口程序
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect);
DrawText(hdc, TEXT("这是我的第一个窗口程序!"), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
在看我下面的内容之前,希望您能先亲自利用Win32 API大全自己试着分析。
分析:
第一句:static TCHAR szAppName[] = TEXT("MyWindows"); 定义了一个静态的扩展字符串,其中的TCHAR是宏定义,我们一步一步“转到定义”,最终能看到的是wchar_t,这是Windows程序设计中的一个扩展数据类型吧,用wchar_t能表示的字符要远远多于char。
HWND是用来定义句柄的,句柄是什么?句柄就是一个窗口、控件或者文件等对象唯一的标识符,句柄是整个Windows编程的基础不理解不行,这个我们先搁着,只需要知道它是用来标识对象,我们能通过句柄来对相应的对象进行引用就行了。
MSG是用来定义消息结构的,相信大多数人都知道Windows有一个叫消息处理的机制,现在打个比喻让大家理解,当我们对一个窗口点击鼠标左键的时候,产生的这个事件会被转换成一个消息,Windows会将这个消息放入一个叫消息循环的××中,然后应用程序利用GetMessage来检索这个消息,如果是自己的消息,GetMessage就会将这个消息投到自己的窗口过程中。而这里的MSG就是用来定义这个消息的,是什么在处理这个消息呢?我们等下谈,现在先往下看。
WNDCLASS是用来定义一个窗口类的,什么是窗口类?打个形象的比喻,我们平时做饼干的时候,大多数都会用到一个模子,我们将材料弄到只要放入这个模子,烤出来的饼干就是这个模子的样子了。窗口类就跟模子一样,我们要做一个窗口出来,首先我们就要先定义一个窗口的类型,然后通过这个窗口类去刻出这个窗口。那有些人就钻牛尖的说,我们也可以不用模子就做出饼干,这也是可以的。但是在Windows程序设计中,我们想要创建的许多窗口实际上都是一样的,如果没有窗口类这个东西,我们想要创建五个一模一样的窗口就要一个一个去定义窗口应该用什么风格需要什么按钮····那样会很繁琐。接下来的wndclass.是用来给这个窗口类结构的各个成员赋值,需要用什么风格、回调函数是哪个、窗口的句柄是什么····这样我们就做出了一个模子,当我们需要创建同样的窗口时,只需要再定义一个句柄即可。
接下来谈谈什么叫回调函数,每个窗口类都会有一个回调函数,这个回调函数主要是用来“响应消息”的,前面讲到我们单击一个鼠标左键、右键或者单击哪个键的时候,这些消息会被投入到该窗口类对应的回调函数(窗口过程),这个函数负责处理对应的消息。
在定义好窗口类的各种成员时,我们接下来就要注册这个窗口了,注册窗口在这里用的是RegisterClass函数,在创建的时候我们顺便测试是否符合创建的条件。判断这个窗口类是否能在NT下运行,若不能就返回NULL结束程序,若能就返回唯一标识已注册的类的一个原子。
当注册窗口类成功后,我们就能利用句柄引用这个唯一的对象,利用CreateWindows创建这个窗口,GreateWindows函数需要的参数,参数包括窗口类名、窗口名、初始化的位置等。利用ShowWindow来设置窗口的显示状态,UpdateWindow是用来更新这个窗口。
接下来的那个循环是用来处理消息的,也就是消息机制,这个会在下篇文章中写出来。
关于HWND结构和MSG结构还有一些API内容,这里挂个地址:点我进入