开发流程:
1 定义一个窗口处理函数
2 注册窗口类
3 创建窗口
4 显示窗口
5 更新窗口
6 消息循环
窗口类的分类
-系统窗口类
系统已经定义好的窗口类,所有应用程序都可以直接使用。
-应用程序全局窗口类
由用户自己定义,当前应用程序所有模块都可以使用。
-应用程序局部窗口类
由用户自己定义,当前应用程序中本模块可以使用
不需要注册,直接使用窗口类即可。系统
已经定义好相应名称,例如:
按钮 - BUTTON
编辑框 - EDIT
应用程序全局窗口类的注册
RegisterClass/RegisterClassEx
ATOM RegisterClass(
CONST WNDCLASS *lpWndClass //窗口类的数据
); 注册成功后,返回一个数字标识。
ATOM RegisterClassEx(
CONST WNDCLASSEX *lpwcx //窗口类的数据
);
加强版的注册窗口类
typedef struct _WNDCLASSEX {UINT cbSize; //结构体的大小,之所以有这个成员是因为不同的平台大小不一样,对齐补齐问题造成
UINT style; //窗口类的风格
WNDPROC lpfnWndProc; //窗口处理函数,自己定义的窗口处理函数名字
int cbClsExtra; //窗口类的附加数据buff的大小
int cbWndExtra; //窗口的附加数据buff的大小
HINSTANCE hInstance; //当前模块的实例句柄
HICON hIcon; //窗口图标句柄
HCURSOR hCursor; //鼠标的句柄
HBRUSH hbrBackground; //绘制窗口背景的画刷句柄
LPCTSTR lpszMenuName; //窗口菜单的资源ID字符串
LPCTSTR lpszClassName; //窗口类的名称
HICON hIconSm; //窗口的小图标句柄,比WNDCLASS多出来的成员
} WNDCLASSEX, *PWNDCLASSEX;
应用程序全局窗口类的注册,需要在窗口类的风格中增加 CS_GLOBALCLASS,例如:
WNDCLASSEX wce = {0};
wce.style = ….|CS_GLOBALCLASS;
应用程序局部窗口类
在注册窗口类时,不添加CS_GLOBALCLASS风格。
窗口类的风格
CS_GLOBALCLASS - 应用程序全局窗口类
CS_BYTEALIGNCLIENT - 窗口客户区的水平位置8倍数对齐
CS_BYTEALIGNWINDOW - 窗口的水平位置8倍数对齐
CS_HREDRAW - 当窗口水平变化时,窗口重新绘制
CS_VREDRAW - 当窗口垂直变化时,窗口重新绘制
CS_CLASSDC - 该类型的窗口,都是有同一个绘图(DC)设备
CS_PARENTDC - 该类型的窗口,使用它的父窗口的绘图(DC)设备
CS_OWNDC - 该类型的窗口,每个窗口都使用自己的绘图(DC)设备
CS_SAVEBITS - 允许窗口保存成图(位图),提高窗口的绘图效率,但是耗费内存资源
CS_DBLCLKS - 允许窗口接收鼠标双击
CS_NOCLOSE - 窗口没有关闭按钮
void SystemReg()
{
HWND hWnd = CreateWindow("BUTTON","搜狗",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,g_hInstance,NULL); //创建一个窗口
ShowWindow(hWnd,SW_SHOW); // 显示窗口
UpdateWindow(hWnd); // 更新窗口
MSG nMsg = {0};
while (GetMessage(&nMsg,NULL,0,0)) // GetMessage()函数从操作系统的消息队列中抓取消息
{
TranslateMessage(&nMsg); // 翻译消息
DispatchMessage(&nMsg); // 派发消息
}
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
g_hInstance = hInstance;
SystemReg();
return 0;
}
窗口的创建
CreateWindow/CreateWindowEx
HWND CreateWindowEx(
DWORD dwExStyle, //窗口的扩展风格
LPCTSTR lpClassName, //已经注册的窗口类名称
LPCTSTR lpWindowName, //窗口标题栏的名字
DWORD dwStyle, //窗口的基本风格
int x, //窗口左上角水平坐标位置
int y, //窗口左上角垂直坐标位置
int nWidth, //窗口的宽度
int nHeight,//窗口的高度
HWND hWndParent,//窗口的父窗口句柄
HMENU hMenu,//窗口菜单句柄
HINSTANCE hInstance, //应用程序实例句柄
LPVOID lpParam //窗口创建时附加参数
); 创建成功返回窗口句柄
一个完整的窗口创建代码
#include "stdafx.h"
HINSTANCE g_hInstance = 0;
/*
1 定义自己的窗口消息处理函数
* 如果点击了鼠标,鼠标消息首先进入操作系统,操作系统会调用我们定义的消息处理函数
* CALLBACK是回调,就是我们定义的函数,我们自己并不调用,交给操作系统调用,是一种调用约定
* APIENTRY和CALLBACK一样都属于回调函数
<span style="white-space:pre"> * 当这个函数收到WM_DESTROY消息时,进程就会终止,否则进程不会终止。也就事点击关闭按钮的时候会发送这个消息</span>
*/
LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
<span style="white-space:pre"> </span>switch(msg)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>case WM_DESTROY:
<span style="white-space:pre"> </span>PostQuitMessage(0);
<span style="white-space:pre"> </span>break;
<span style="white-space:pre"> </span>}
return DefWindowProc(hWnd,msg,wParam,lParam);
}
/*
2 注册窗口类
*/
BOOL Register(LPSTR lpClassName,WNDPROC wndProc)
{
WNDCLASSEX wce = {0};
wce.cbSize = sizeof(wce);
wce.cbClsExtra = 0;
wce.cbWndExtra = 0;
wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wce.hCursor = NULL;
wce.hIcon = NULL;
wce.hIconSm = NULL;
wce.hInstance = g_hInstance;
wce.lpfnWndProc = wndProc;
wce.lpszClassName = lpClassName;
wce.lpszMenuName = NULL;
wce.style = CS_HREDRAW|CS_VREDRAW;
ATOM nAtom = RegisterClassEx(&wce);
if(nAtom == 0)
{
return FALSE;
}
return TRUE;
}
/*
3 创建主窗口
*/
HWND CreateMain(LPSTR lpClassName,LPSTR lpWndName)
{
HWND hWnd = CreateWindowEx(0,lpClassName,lpWndName,WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,g_hInstance,NULL);
return hWnd;
}
/*
4 显示窗口和更新窗口
*/
void DisplayWindow(HWND hWnd)
{
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
}
/*
5 消息循环
*/
void Message()
{
MSG nMsg = {0};
while(GetMessage(&nMsg,NULL,0,0))
{
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
g_hInstance = hInstance;
Register("Main",WndProc);
HWND hwnd = CreateMain("Main","速度与激情");
DisplayWindow(hwnd);
Message();
return 0;
}
二、创建一个子窗口
创建时要设置父窗口句柄(必备)
创建风格要增加 WS_CHILD|WS_VISIBLE(必备)
一个完整的创建子窗口的代码
</pre><pre name="code" class="html">#include "stdafx.h"
HINSTANCE g_hInstance = 0;
/*
1 定义自己的窗口消息处理函数
* 如果点击了鼠标,鼠标消息首先进入操作系统,操作系统会调用我们定义的消息处理函数
* CALLBACK是回调,就是我们定义的函数,我们自己并不调用,交给操作系统调用,是一种调用约定
* APIENTRY和CALLBACK一样都属于回调函数
* 当这个函数收到WM_DESTROY消息时,进程就会终止,否则进程不会终止。也就事点击关闭按钮的时候会发送这个消息
*/
LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hWnd,msg,wParam,lParam);
}
/*
2 注册窗口类
*/
BOOL Register(LPSTR lpClassName,WNDPROC wndProc)
{
WNDCLASSEX wce = {0};
wce.cbSize = sizeof(wce);
wce.cbClsExtra = 0;
wce.cbWndExtra = 0;
wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wce.hCursor = NULL;
wce.hIcon = NULL;
wce.hIconSm = NULL;
wce.hInstance = g_hInstance;
wce.lpfnWndProc = wndProc;
wce.lpszClassName = lpClassName;
wce.lpszMenuName = NULL;
wce.style = CS_HREDRAW|CS_VREDRAW;
ATOM nAtom = RegisterClassEx(&wce);
if(nAtom == 0)
{
return FALSE;
}
return TRUE;
}
/*
3 创建主窗口
*/
HWND CreateMain(LPSTR lpClassName,LPSTR lpWndName)
{
HWND hWnd = CreateWindowEx(0,lpClassName,lpWndName,WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,g_hInstance,NULL);
return hWnd;
}
/*
3.1 创建一个子窗口
*/
HWND CreateChild(LPSTR lpClassName,LPSTR lpWndName,HWND hParent)
{
HWND hChild = CreateWindowEx(0,lpClassName,lpWndName,WS_CHILD|WS_VISIBLE|WS_OVERLAPPEDWINDOW,150,150,200,200,hParent,NULL,g_hInstance,NULL);
return hChild;
}
/*
4 显示窗口和更新窗口
*/
void DisplayWindow(HWND hWnd)
{
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
}
/*
5 消息循环
*/
void Message()
{
MSG nMsg = {0};
while(GetMessage(&nMsg,NULL,0,0))
{
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
g_hInstance = hInstance;
Register("Main",WndProc);
HWND hwnd = CreateMain("Main","速度与激情");
DisplayWindow(hwnd);
Register("Child",DefWindowProc);
HWND hChild1 = CreateChild("Child","保尔",hwnd);
MoveWindow(hChild1,120,120,100,100,TRUE);
Register("Child2",DefWindowProc);
HWND hChild2 = CreateChild("Child2","丽萨",hwnd);
MoveWindow(hChild2,300,120,100,100,TRUE);
Message();
return 0;
}
int cbClsExtra; //窗口类的附加数据BUFF大小
int cbWndExtra; //窗口的附加数据BUFF大小
窗口类附加数据缓冲区的用法:
int cbClsExtra; //窗口类的附加数据BUFF大小
1 申请缓冲区,赋值就可以申请下来,int cbClsExtra - 一般赋4的倍数
2 写入数据的函数 SetClassLong()3 读取数据的函数 GetClassLong()
窗口附加数据缓冲区的用法:
1 申请缓冲区,赋值就可以申请下来,int cbWndExtra - 一般为4的倍数
2 写入数据的函数 SetWindowLong()
3 读取数据的函数 GetWindowLong()
两者的区别:
窗口类附加数据缓冲区:是所有基于该窗口类创建出来的共享的缓冲区
窗口附加数据缓冲区:是窗口自己私有的缓冲区,即便是基于同一个窗口类创建出来的窗口,之间不共享