Windows程序设计(第五版)学习:第三章 窗口与消息
第三章 窗口与消息
1,windows窗口过程:应用程序所创建的每一个窗口都有一个与之关联的窗口过程,用于处理传递给窗口的消息。
2,窗口依据窗口类来创建。窗口类标识了用于处理传递给窗口的消息的窗口过程。窗口类的使用允许多个窗口共享一个窗口类,因而多个窗口可以使用相同的窗口过程。
3,Windows程序开始执行的时候,Windows首先为该程序创建一个消息队列。该消息队列中存放着应用程序可能创建的所有窗口的消息。Windows应用程序中一般包含一小段称为"消息循环"的代码,该段代码用于从消息队列中检索消息,并将其分发给相应的窗口过程。其他消息则不经过消息队列直接发送给窗口过程。
4,创建显示窗口的代码如下:
|
/*---------------------------------------------- HelloWindow.c Displays "Hello, Window." in client area code and compile it with visual studio 2008
----------------------------------------------*/
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow) { static TCHAR szWndClassName[] = TEXT("Hello Window"); HWND hwnd; MSG msg; WNDCLASS wndClass;
//define property of window class wndClass.style = CS_HREDRAW|CS_VREDRAW; wndClass.lpfnWndProc = WndProc; wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; wndClass.hInstance = hInstance; wndClass.hIcon = LoadIcon(NULL, IDI_QUESTION); wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndClass.lpszMenuName = NULL; wndClass.lpszClassName = szWndClassName;
//register window class if(!RegisterClass(&wndClass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), TEXT("Hint"), MB_ICONERROR|MB_OKCANCEL); return 0; }
//create the window based on the previous registered window class hwnd = CreateWindow(szWndClassName, //window class name TEXT("The Hello Program"), //window caption WS_OVERLAPPEDWINDOW, //window style CW_USEDEFAULT, //initial x position CW_USEDEFAULT, //initial y position CW_USEDEFAULT, //initial x size CW_USEDEFAULT, //initial y size NULL, //parent window handle NULL, //window menu handle hInstance, //program instance handle NULL); //creation parameters
//show and refresh the window ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd);
//set message loop while(GetMessage(&msg, NULL, 0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); }
return msg.wParam; }
//window process function LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; RECT rect;
switch(message) { case WM_CREATE: PlaySound(TEXT("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC); return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect);
DrawText(hdc, TEXT("Hello, Window."), -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); } |
5,一些windows api 函数
LoadIcon:加载图标
LoadCursor:加载鼠标光标
GetStockObject:获取图形对象
RegisterClass:为窗口注册窗口类
CreateWindow:创建窗口
ShowWindow:在屏幕中显示窗口
UpdateWindow:指示窗口对其自身进行重绘
GetMessage:从消息队列中获得消息
TranslateMessage:翻译一些键盘消息
DispatchMessage:将消息发送给窗口过程
BeginPaint:标明窗口绘制开始
EndPaint:结束窗口绘制
DrawText:显示文本字符串
PostQuitMessage:将退出消息插入消息队列
DefWindowProc:执行默认的消息处理
6,数值常量前缀:
|
CS |
类风格选项 |
|
CW |
创建窗口选项 |
|
DT |
文本绘制选项 |
|
IDI |
图标ID号 |
|
IDC |
光标的ID号 |
|
MB |
消息框选项 |
|
SND |
声音选项 |
|
WM |
窗口消息 |
|
WS |
窗口风格 |
7,一些数据类型
UINT:unsigned int
WPARAM: word param, 16位程序为unsigned short ,32位程序为unsigned int
LPARAM:long
LRESULT:long
WINAPI, CALLBACK: __stdcall
HINSTANCE: 实例句柄,程序本身
HWND:窗口句柄
HDC:设备环境句柄
句柄本质上是引用某个对象的数值,通常为32位。
8,窗口的注册
(1)窗口类结构WNDCLASS
参考资料:https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms633576(v=vs.85).aspx
WNDCLASS 的lpszClassName最长为256
(2)窗口类注册使用RegisterWindow或者RegisterWindowEx
参考资料:https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms633586(v=vs.85).aspx
RegisterWindow有RegisterWindowA和RegisterWindowW两个版本,程序使用哪个版本注册窗口类,决定着传递给窗口的消息是包含ASCII文本还是Unicode文本
关于Windows窗口类:
https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms633574(v=vs.85).aspx#class_styles
9,窗口的创建
由于窗口类只是定义了窗口的一般特征,因此基于同一窗口类可以创建许多不同的窗口。
关于窗口类和窗口的区别:
例:所有下压按钮都是基于相同的窗口类。与该窗口类关联的窗口过程位于Windows内部,并负责处理鼠标和键盘对按钮的输入,以及定义按钮在屏幕上的视觉外观。但是按钮位置尺寸不同,文字不同,这些就属于窗口定义。
窗口的WS_OVERLAPPEDWINDOW:层叠窗口,包含标题栏,标题左边的系统菜单按钮,一个窗口尺寸调整边框以及位于标题栏右方的三个按钮。
连续创建的窗口,Windows会沿水平和垂直做步长为1的偏移。
若新建的窗口为顶级窗口,父窗口句柄为NULL。通常,两个窗口存在父子关系时,子窗口总是位于父窗口的前方。应用程序窗口总是位于桌面窗口的前方。
10,窗口的显示
当CreateWindow返回时,窗口已在Windows内部被创建,即Windows已为窗口分配了一块内存。
11,消息循环
Windows为当前在其中运行的每一个Windows程序(进程)都维护了一个消息队列,
GetMessage:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms644936(v=vs.85).aspx
GetMessage(&msg, NULL, 0,0)
获取由该程序创建的所有窗口的消息。Windows用从消息队列中得到下一条消息来填充消息结构的各个字段。如果从消息队列中检索到的消息message字段不是WM_QUIT,返回非零,否则返回0.
TranslateMessage(&msg):将消息返回给Windows进行键盘消息的转换,
DispathMessage(&msg):将消息再次返回给Windows。
接下来,Windows将此消息发送给合适的窗口过程来处理。
12,窗口过程
一个Windows程序可以包含多个窗口过程,但是一个窗口过程总是与一个通过调用RegisterClass注册的特定窗口类相关联。
窗口过程由Windows进行调用。
13,消息的处理
通过switch-case结构来确定窗口过程受到的消息的类型以及相应的处理办法。窗口过程对消息进行处理后,应返回0。所有窗口过程不进行处理的消息都必须传给DefWindowProc的Widows函数。
14,WM_PAINT消息
当窗口的客户区部分或者全部无效且必须更新时,应用程序将得到此通知。这也意味着窗口必须被重绘。
当窗口创建后,客户区为无效的,通过调用ShowWindow使窗口重绘,窗口尺寸发生变化,也会重绘。最大最小化也会重绘。窗口被重叠后再次显示,也会发送WM_PAINT消息。
WM_PAINT以调用BeginPaint开始,EndPaint结束。
在调用BeginPaint期间,若客户区背景未被擦除,Windows会调用窗口类中的背景对其进行擦除。BeginPaint返回设备环境句柄。
若一个窗口过程不对WM_PAINT消息进行处理,必须交给DeWindowProc进行处理
15,Windows编程的若干难点
- WinMain函数只负责定义注册窗口类、创建窗口、从消息队列中检索和分发消息。
- WndProc会在如下情况被调用:新建窗口时,窗口被最终销毁时,用户从键盘输入字符时,用户从菜单中选择某个项时,用户用鼠标操作或者单击滚动条时,窗口的客户区需要重绘时。
16,队列消息和非队列消息
队列消息:Windows放入程序消息队列中的消息。在程序的消息循环中,消息被检索,然后被投递(post)到窗口过程中。主要是用户的输入产生,如WM_KEYDOWN,WM_KEYUP,WM_CHAR,WM_TIMER,WM_LBUTTONDOWN,WM_PAINT,WM_QUIT。
非队列消息:由Windows直接对窗口过程进行调用产生的,是被发送到窗口过程中的。包括消息队列以外的其它消息,如WM_CREATE,WM_SIZE,WM_SHOWWINDOW。处理菜单项选择的WM_COMMAND。
Windows程序可有多个执行线程。但每个线程的消息队列仅为那些其窗口过程在该线程内执行的窗口进行消息处理。即,消息循环和窗口过程不是并发运行的,当一个消息循环从其自身的消息队列中检索消息,并调用DispatchMessage函数将检索到的消息发送给窗口过程时,只有在窗口过程将控制权返回给Windows后,DispatchMessage才会返回。
Windows程序设计(第五版)学习:第三章 窗口与消息的更多相关文章
- Windows程序设计(第五版)学习:第一章 起步
第一章 起步 1,windows主要的三个动态库: kernel32.dll负责操作系统的传统工作,包括内存管理.文件输入以及任务管理等. user32.dll负责用户界面的操作,即所有窗口的管理 g ...
- Windows程序设计(第五版)学习:第二章 Unicode简介
第二章 Unicode简介 1,Windows通过双字节技术DBCS解决这个问题,代码页定义不同的字符集,称为ANSI字符集,比如日文为CP932,韩文为CP949,繁体中文为CP950,简体中文为C ...
- Windows程序设计(第五版)学习:第四章 文本输出
第四章 文本输出 1,客户区:整个应用程序窗口中没有被标题栏.边框.菜单栏.工具栏.状态栏和滚动条占用的区域.简而言之,客户区就是窗口中程序可以在上面绘制并向用户传达可视化信息的区域. 2,大多数 ...
- C#高级编程 (第六版) 学习 第三章:对象和类型
第三章 对象和类型 1,类和结构 类存储在托管堆上 结构存储在堆栈上 2,类成员 类中的数据和函数称为类成员 数据成员 数据成员包括了字段.常量和事件 函数成员 方法:与某个类相关的函数,可以 ...
- 《Windows程序设计第5版》学习进度备忘
书签:另外跳过的内容有待跟进 __________________学习资源: <Windows程序设计第5版珍藏版> __________________知识基础支持: _________ ...
- 《Python学习手册 第五版》 -第18章 参数
在函数的定义和调用中,参数是使用最多喝最频繁的,本章内容就是围绕函数的参数进行讲解 本章重点内容如下: 1.参数的传递 1)不可变得参数传递 2)可变得参数传递 2.参数的匹配模式 1)位置次序:从左 ...
- 《Python学习手册 第五版》 -第15章 文档
本章主要介绍Python中的文档,会通过多种方式来说明,如果查看Python自带文档和其他参考的资料 本章重点内容 1.#注释:源文件文档 2.dir函数:以列表显示对象中可用的属性 3.文档字符串 ...
- 《Python学习手册 第五版》 -第16章 函数基础
前面的章节讲解的是一些基础数据类型.基本语句使用和一些文档查看的内容,这些都是一些基础,其实还谈不上入门,只有了解了函数,才算入门 函数是编程里面使用最多的也是最基本的程序结构, 本章重点内容 1.函 ...
- 《C++Primer》第五版习题答案--第一章【学习笔记】
C++Primer第五版习题解答---第一章 ps:答案是个人在学习过程中书写,可能存在错漏之处,仅作参考. 作者:cosefy Date: 2022/1/7 第一章:开始 练习1.3 #includ ...
随机推荐
- Xml Schema:C#访问在complextype中插入新元素
最近用c#写Xml Schema代码,找了很久也找不到如何在已有的complextype中插入新的element,最后我充分发挥自己的聪明才智,哈哈,终于从...中找到了灵感. XmlSchemaSe ...
- 数据库update死锁
比较常见的死锁场景,并发批量update时的一个场景: update cross_marketing set gmtModified = NOW(), pageview = pageview+ #ex ...
- 基于MPI的并行计算—矩阵向量乘
以前没接触过MPI编程,对并行计算也没什么了解.朋友的期末课程作业让我帮忙写一写,哎,实现结果很一般啊.最终也没完整完成任务,惭愧惭愧. 问题大概是利用MPI完成矩阵和向量相乘.输入:Am×n,Bn× ...
- POJ 2533 动态规划入门 (LIS)
Longest Ordered Subsequence Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 42914 Accepte ...
- GDB中文手册
用GDB调试程序GDB概述 2使用GDB 5GDB中运行UNIX的shell程序 8在GDB中运行程序 8调试已运行的程序 两种方法: 9暂停 / 恢复程序运行 9一.设置断点(BreakPoint) ...
- windows环境下局域网内无法访问apache站点
DocumentRoot "D:/wamp/www/" <Directory /> AllowOverride none order deny,allo ...
- knockout 第一个实例visible
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- [Spring MVC] - Spring MVC环境搭建
1) 复制Spring所需要的lib包 (这是SSH所需要的lib包,如果只使用spring,可以移除一些包) 2) 配置web.xml <?xml version=" ...
- 在同一个机器上运行两个jboss修改配置
http://blog.sina.com.cn/s/blog_8ebe17aa0101mnft.html 解决办法:修改 \jboss-4.0.4.GA\server\default\conf 目录下 ...
- linux net command /uboot command
1. uboot command 读取寄存器内容 md [内存地址][长度] 修改内存地址 mw [内存地址][长度] 2. linux络命令 -- netstat -a (all)显示所有选项,默 ...