Windows 图形界面笔记(1) - 窗口的显示
2013-12-30 17:49
399 查看
Windows 消息驱动
当Windows 向程序发送消息时,它调用程序中的一个函数,这个函数的参数精确地描述了Windows 发送的消息。在程序中称这个函数为窗口函数(Window Procedure)或消息处理函数。它是一个自定义的回调函数,原形如下。
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
CALLBACK 宏是__stdcall 的意思,
hWnd 参数标识了消息到达的窗口;
uMsg 参数是一个被命名的常量(消息ID 号)
wParam 和lParam 是消息的两个参数,其值取决于uMsg
在桌面上显示一个窗口的具体步骤,这就是主程序的结构流程。
(1)注册窗口类(RegisterClassEx)
(2)创建窗口(CreateWindowEx)
(3)在桌面显示窗口(ShowWindow)
(4)更新窗口客户区(UpdateWindow)
(5)进入无限的消息获取和处理的循环。首先是获取消息(GetMessage),如果有消息到达,则将消息分派到回调函数处理(DispatchMessage),如果消息是WM_QUIT,则 GetMessage 函数返回 FALSE,整个消息循环结束。消息具体的处理过程是在 MainWndProc 函数中进行的。
一个 Windows 基本窗口的实现
详细说明:
注册窗口类
注册窗口类的API 函数是RegisterClassEx,最后的“Ex”是扩展的意思,因为它是Win16 的RegisterClass 函数的扩展。一个窗口类定义了窗口的一些主要属性,如:图标、光标、背景色和负责处理消息的窗口函数等。这些属性定义在WNDCLASSEX
结构中。
typedef struct _WNDCLASSEX {UINT cbSize; //
WNDCLASSEX 结构的大小
UINT style; // 从这个窗口类派生的窗口具有的风格
WNDPROC lpfnWndProc;// 即 window procedure,
窗口消息处理函数指针
int cbClsExtra; // 指定紧跟在窗口类结构后的附加字节数
int cbWndExtra; // 指定紧跟在窗口事例后的附加字节数
HANDLE hInstance; // 本模块的实例句柄
HICON hIcon; // 窗口左上角图标的句柄
HCURSOR hCursor; // 光标的句柄
HBRUSH hbrBackground;// 背景画刷的句柄
LPCTSTR lpszMenuName;// 菜单名
LPCTSTR lpszClassName;// 该窗口类的名称
HICON hIconSm; // 小图标句柄
} WNDCLASSEX;
wndclass.lpfnWndProc = MainWndProc; // 窗口函数指针
lpfnWndProc 指定了基于此类的窗口的窗口函数,当窗口收到消息时Windows 即自动调用这个函数通知应用程序。
hIcon 和hCursor 为要装载的图标和光标的句柄。
wndclass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH); // 使用白色背景画刷
WHITE_BRUSH 是一个Windows 预定义的画刷对象类型,也可以自定义
::RegisterClassEx(&wndclass); // 注册窗口类,失败返回0
创建窗口
用注册的窗口类的类名调用 CreateWindowEx 函数即可,失败返回NULL
第四个参数dwStyle 的值是 WS_OVERLAPPEDWINDOW,即重叠式窗口(Overlapped Window)。其他类型:
WS_BORDER 创建一个单边框的窗口
WS_CAPTION 创建一个有标题框的窗口(包括WS_BODER 风格)
WS_CHIlD 创建一个子窗口。这个风格不能与WS_POPVP 风格合用
WS_DISABLED 创建一个初始状态为禁止的子窗口。一个禁止状态的窗日不能接受来自用户的输人信息
WS_DLGFRAME 创建一个带对话框边框风格的窗口。这种风格的窗口不能带标题条
WS_HSCROLL 创建一个有水平滚动条的窗口
WS_VSCROLL 创建一个有垂直滚动条的窗口
WS_ICONIC 创建一个初始状态为最小化状态的窗口。与WS_MINIMIZE 风格相同
WS_MAXIMIZE 创建一个具有最大化按钮的窗口。该风格不能和WS_EX_CONTEXTHELP 风格同时出现,同时必须指定WS_SYSMENU 风格
WS_OVERLAPPED 产生一个层叠的窗口。一个层叠的窗口有一个标题条和一个边框。与WS_TILED风格相同
WS_OVERLAPPEDWINDOW 创建一个具有 WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU ,WS_THICKFRAME,WS_MINIMIZEBOX,WS_MAXMIZEBOX风格的层叠窗口
WS_POPUP 创建一个弹出式窗口。该风格不能与WS_CHLD 风格同时使用
WS_POPUPWINDOW 创建一个具有WS_BORDER,WS_POPUP,WS_SYSMENU 风格的窗口,WS_CAPTION 和WS_POPUPWINDOW 必须同时设定才能使窗口某单可见
WS_SIZEBOX 创建一个可调边框的窗口,与WS_THICKFRAME 风格相同
WS_SYSMENU 创建一个在标题条上带有窗口菜单的窗口,必须同时设定 WS_CAPTION 风格
WS_THICKFRAME 创建一个具有可调边框的窗口,与WS_SIZEBOX 风格相同
WS_VISIBLE 创建一个初始状态为可见的窗口
在桌面显示窗口
::ShowWindow(hwnd, nCmdShow);
更新窗口客户区
::UpdateWindow(hwnd);
如果指定窗口的更新区域不为空的话,UpdateWindow 函数通过向这个窗口发送一个 WM_PAINT 消息更新它的客户区。当窗口显示在屏幕上时,窗口的客户区被在 WNDCLASSEX 中指定的刷子擦去了,调用 UpdateWindow 函数将促使客户区重画,以显示其内容。
进入无限的消息循环
在调用UpdateWindow 函数之后,整个窗口已经显示在桌面上,程序必须准备从用户接收键盘和鼠标输入了。Windows 为每个线程维护了一个消息队列,每当有一个输入发生,Windows 就把用户的输入翻译成消息放在消息队列中。利用 GetMessage 函数可以从调用线程的消息队列中取出一个消息来填充MSG 结构。如果消息队列中没有消息(即没有用户输入),这个函数会一直等待下去,直到有消息进入到消息队列为止。
::GetMessage(&msg, NULL, 0, 0);
GetMessage 函数从消息队列中取得的消息如果不是WM_QUIT,则返回非零值。一个 WM_QUIT 消息会促使GetMessage 函数返回 0,从而结束消息循环。
MSG 结构类型
typedef struct tagMSG {
HWND hwnd; // 消息要发向的窗口句柄
UINT message; // 消息标识符,以WM_ 开头的预定义值(意为Window Message)
WPARAM wParam;
// 消息的参数之一
LPARAM lParam; // 消息的参数之二
DWORD time; // 消息放入消息队列的时间
POINT pt; // 这是一个POINT 数据结构,表示消息放入消息队列时的鼠标位置
} MSG, *PMSG ;
DispatchMessage 函数分发一个消息到对应窗口的窗口函数。在上面的例子中,窗口函数是MainWndProc。MainWndProc 处理消息后把控制权交给Windows,此时 DispatchMessage 函数仍然在继续工作,当它返回时,消息循环从调用GetMessage 函数开始进入下一轮循环。
当Windows 向程序发送消息时,它调用程序中的一个函数,这个函数的参数精确地描述了Windows 发送的消息。在程序中称这个函数为窗口函数(Window Procedure)或消息处理函数。它是一个自定义的回调函数,原形如下。
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
CALLBACK 宏是__stdcall 的意思,
hWnd 参数标识了消息到达的窗口;
uMsg 参数是一个被命名的常量(消息ID 号)
wParam 和lParam 是消息的两个参数,其值取决于uMsg
在桌面上显示一个窗口的具体步骤,这就是主程序的结构流程。
(1)注册窗口类(RegisterClassEx)
(2)创建窗口(CreateWindowEx)
(3)在桌面显示窗口(ShowWindow)
(4)更新窗口客户区(UpdateWindow)
(5)进入无限的消息获取和处理的循环。首先是获取消息(GetMessage),如果有消息到达,则将消息分派到回调函数处理(DispatchMessage),如果消息是WM_QUIT,则 GetMessage 函数返回 FALSE,整个消息循环结束。消息具体的处理过程是在 MainWndProc 函数中进行的。
一个 Windows 基本窗口的实现
// 窗口函数的函数原形 LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM); int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { char szClassName[] = "MainWClass"; WNDCLASSEX wndclass; // 用描述主窗口的参数填充WNDCLASSEX结构 wndclass.cbSize = sizeof(wndclass); // 结构的大小 wndclass.style = CS_HREDRAW|CS_VREDRAW; // 指定如果大小改变就重画 wndclass.lpfnWndProc = MainWndProc; // 窗口函数指针 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 = szClassName ; // 窗口类的名称 wndclass.hIconSm = NULL; // 没有类的小图标 // 注册这个窗口类 ::RegisterClassEx(&wndclass); // 创建主窗口 HWND hwnd = ::CreateWindowEx( 0, // dwExStyle,扩展样式 szClassName, // lpClassName,类名 "My first Window!", // lpWindowName,标题 WS_OVERLAPPEDWINDOW, // dwStyle,窗口风格 CW_USEDEFAULT, // X,初始 X 坐标 CW_USEDEFAULT, // Y,初始 Y 坐标 CW_USEDEFAULT, // nWidth,宽度 CW_USEDEFAULT, // nHeight,高度 NULL, // hWndParent,父窗口句柄 NULL, // hMenu,菜单句柄 hInstance, // hlnstance,程序实例句柄 NULL) ; // lpParam,用户数据 if(hwnd == NULL) { ::MessageBox(NULL, "创建窗口出错!", "error", MB_OK); return -1; } // 显示窗口,刷新窗口客户区 ::ShowWindow(hwnd, nCmdShow); ::UpdateWindow(hwnd); // 从消息堆中取出消息 MSG msg; while(::GetMessage(&msg, NULL, 0, 0)) { // 转化键盘消息 ::TranslateMessage(&msg); // 将消息发送到相应的窗口函数 ::DispatchMessage(&msg); } // 当GetMessage返回0时程序结束 return msg.wParam; } LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { char szText[] = "最简单的窗口程序!"; switch (message) { case WM_PAINT: // 窗口客户区需要重画 { HDC hdc; PAINTSTRUCT ps; // 使无效的客户区变的有效,并取得设备环境句柄 hdc = ::BeginPaint (hwnd, &ps) ; // 显示文字 ::TextOut(hdc, 10, 10, szText, strlen(szText)); ::EndPaint(hwnd, &ps); return 0; } case WM_DESTROY: // 正在销毁窗口 // 向消息队列投递一个WM_QUIT消息,促使GetMessage函数返回0,结束消息循环 ::PostQuitMessage(0) ; return 0 ; } // 将我们不处理的消息交给系统做默认处理 return ::DefWindowProc(hwnd, message, wParam, lParam); }
详细说明:
注册窗口类
注册窗口类的API 函数是RegisterClassEx,最后的“Ex”是扩展的意思,因为它是Win16 的RegisterClass 函数的扩展。一个窗口类定义了窗口的一些主要属性,如:图标、光标、背景色和负责处理消息的窗口函数等。这些属性定义在WNDCLASSEX
结构中。
typedef struct _WNDCLASSEX {UINT cbSize; //
WNDCLASSEX 结构的大小
UINT style; // 从这个窗口类派生的窗口具有的风格
WNDPROC lpfnWndProc;// 即 window procedure,
窗口消息处理函数指针
int cbClsExtra; // 指定紧跟在窗口类结构后的附加字节数
int cbWndExtra; // 指定紧跟在窗口事例后的附加字节数
HANDLE hInstance; // 本模块的实例句柄
HICON hIcon; // 窗口左上角图标的句柄
HCURSOR hCursor; // 光标的句柄
HBRUSH hbrBackground;// 背景画刷的句柄
LPCTSTR lpszMenuName;// 菜单名
LPCTSTR lpszClassName;// 该窗口类的名称
HICON hIconSm; // 小图标句柄
} WNDCLASSEX;
wndclass.lpfnWndProc = MainWndProc; // 窗口函数指针
lpfnWndProc 指定了基于此类的窗口的窗口函数,当窗口收到消息时Windows 即自动调用这个函数通知应用程序。
hIcon 和hCursor 为要装载的图标和光标的句柄。
wndclass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH); // 使用白色背景画刷
WHITE_BRUSH 是一个Windows 预定义的画刷对象类型,也可以自定义
::RegisterClassEx(&wndclass); // 注册窗口类,失败返回0
创建窗口
用注册的窗口类的类名调用 CreateWindowEx 函数即可,失败返回NULL
第四个参数dwStyle 的值是 WS_OVERLAPPEDWINDOW,即重叠式窗口(Overlapped Window)。其他类型:
WS_BORDER 创建一个单边框的窗口
WS_CAPTION 创建一个有标题框的窗口(包括WS_BODER 风格)
WS_CHIlD 创建一个子窗口。这个风格不能与WS_POPVP 风格合用
WS_DISABLED 创建一个初始状态为禁止的子窗口。一个禁止状态的窗日不能接受来自用户的输人信息
WS_DLGFRAME 创建一个带对话框边框风格的窗口。这种风格的窗口不能带标题条
WS_HSCROLL 创建一个有水平滚动条的窗口
WS_VSCROLL 创建一个有垂直滚动条的窗口
WS_ICONIC 创建一个初始状态为最小化状态的窗口。与WS_MINIMIZE 风格相同
WS_MAXIMIZE 创建一个具有最大化按钮的窗口。该风格不能和WS_EX_CONTEXTHELP 风格同时出现,同时必须指定WS_SYSMENU 风格
WS_OVERLAPPED 产生一个层叠的窗口。一个层叠的窗口有一个标题条和一个边框。与WS_TILED风格相同
WS_OVERLAPPEDWINDOW 创建一个具有 WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU ,WS_THICKFRAME,WS_MINIMIZEBOX,WS_MAXMIZEBOX风格的层叠窗口
WS_POPUP 创建一个弹出式窗口。该风格不能与WS_CHLD 风格同时使用
WS_POPUPWINDOW 创建一个具有WS_BORDER,WS_POPUP,WS_SYSMENU 风格的窗口,WS_CAPTION 和WS_POPUPWINDOW 必须同时设定才能使窗口某单可见
WS_SIZEBOX 创建一个可调边框的窗口,与WS_THICKFRAME 风格相同
WS_SYSMENU 创建一个在标题条上带有窗口菜单的窗口,必须同时设定 WS_CAPTION 风格
WS_THICKFRAME 创建一个具有可调边框的窗口,与WS_SIZEBOX 风格相同
WS_VISIBLE 创建一个初始状态为可见的窗口
在桌面显示窗口
::ShowWindow(hwnd, nCmdShow);
更新窗口客户区
::UpdateWindow(hwnd);
如果指定窗口的更新区域不为空的话,UpdateWindow 函数通过向这个窗口发送一个 WM_PAINT 消息更新它的客户区。当窗口显示在屏幕上时,窗口的客户区被在 WNDCLASSEX 中指定的刷子擦去了,调用 UpdateWindow 函数将促使客户区重画,以显示其内容。
进入无限的消息循环
在调用UpdateWindow 函数之后,整个窗口已经显示在桌面上,程序必须准备从用户接收键盘和鼠标输入了。Windows 为每个线程维护了一个消息队列,每当有一个输入发生,Windows 就把用户的输入翻译成消息放在消息队列中。利用 GetMessage 函数可以从调用线程的消息队列中取出一个消息来填充MSG 结构。如果消息队列中没有消息(即没有用户输入),这个函数会一直等待下去,直到有消息进入到消息队列为止。
::GetMessage(&msg, NULL, 0, 0);
GetMessage 函数从消息队列中取得的消息如果不是WM_QUIT,则返回非零值。一个 WM_QUIT 消息会促使GetMessage 函数返回 0,从而结束消息循环。
MSG 结构类型
typedef struct tagMSG {
HWND hwnd; // 消息要发向的窗口句柄
UINT message; // 消息标识符,以WM_ 开头的预定义值(意为Window Message)
WPARAM wParam;
// 消息的参数之一
LPARAM lParam; // 消息的参数之二
DWORD time; // 消息放入消息队列的时间
POINT pt; // 这是一个POINT 数据结构,表示消息放入消息队列时的鼠标位置
} MSG, *PMSG ;
DispatchMessage 函数分发一个消息到对应窗口的窗口函数。在上面的例子中,窗口函数是MainWndProc。MainWndProc 处理消息后把控制权交给Windows,此时 DispatchMessage 函数仍然在继续工作,当它返回时,消息循环从调用GetMessage 函数开始进入下一轮循环。
相关文章推荐
- Qt自定义界面类并提升(提升的窗口部件),把OpenGL绘制的图形显示在QT的ui界面上
- bash for windows 图形界面显示方法汇总
- windows 下 putty 登陆服务器 显示matlab图形界面
- Windows界面编程第六篇 动画启动效果(动画效果显示及隐藏窗口)
- Windows界面编程第六篇 动画启动效果(动画效果显示及隐藏窗口)
- OpenGL学习笔记:Console工程下如何不显示控制台黑窗口只显示Windows窗口
- Windows界面编程第六篇 动画启动效果(动画效果显示及隐藏窗口)
- 终于解决了用JAVA写窗口程序在不同的windows界面下的显示保持一致。
- Qt自定义界面类并提升(提升的窗口部件),把OpenGL绘制的图形显示在QT的ui界面上
- Windows界面编程第六篇 动画启动效果(动画效果显示及隐藏窗口)
- Windows界面编程第六篇 动画启动效果(动画效果显示及隐藏窗口)
- 在windows下使用Xming+Putty显示Linux下软件图形界面
- Windows 图形界面笔记(2) - 处理消息
- 跟我一起学Windows界面封装(二) 之 前奏篇:显示第一个窗口
- OpenGL学习笔记:Console工程下怎么不显示控制台黑窗口只显示Windows窗口(VS2015)
- VS2012+C语言+图形界面窗口+读取TXT文件+显示
- windows+xshell+xming 显示远程linux服务器的图形程序窗口
- 在窗口显示文字和绘制图形
- [电脑问题解决]在windows 8.1升级后,电脑重启时不显示ubuntu的系统引导界面,而总是直接进入windows
- 创建windows窗口后没有显示(DefWindowProc)