Win 32 编程之按钮消息响应(代码小错误修复)
最近不想用MFC写东西了,有没有安装Qt和其他图形化开发环境,只能捣鼓API了。于是乎,就有了以下的学习--
首先,老套的创建个Windows窗口,由于自己有点小懒,就直接用Hello Word的源码了。
#include <windows.h>
#include <stdio.h> // 窗口过程函数
LRESULT CALLBACK WinSunProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // command line
int nCmdShow // show state
) {
// 窗口类
WNDCLASS wndcls;
wndcls.cbClsExtra = ; // 类附加内存
wndcls.cbWndExtra = ; // 窗口附加内存
wndcls.hbrBackground = (HBRUSH) GetStockObject(COLOR_WINDOW); // 背景画刷句柄
wndcls.hCursor = LoadCursor(NULL, IDC_ARROW); // 窗口光标句柄
wndcls.hIcon = LoadIcon(NULL, IDI_APPLICATION); // 窗口图标句柄
wndcls.hInstance = hInstance; // 包含窗口过程函数的程序实例
wndcls.lpfnWndProc = WinSunProc; // 只想窗口过程函数的指针
wndcls.lpszClassName = "CRoot"; // 窗口类名称
wndcls.lpszMenuName = NULL; // 菜单资源
wndcls.style = CS_HREDRAW | CS_VREDRAW; // 窗口样式
RegisterClass(&wndcls); // 创建窗口, 定义一个变量用来保存成功创建窗口后返回的句柄
HWND hwnd;
hwnd = CreateWindow( // 窗口创建成功时返回为窗口分配的句柄 失败时返回NULL
"CRoot", // 窗口类名
"Hello World", // 窗口名字
WS_CAPTION|WS_SYSMENU, // 窗口样式
CW_USEDEFAULT, CW_USEDEFAULT, // 窗口左上角坐标
, , // 窗口宽高
NULL, // 父窗口句柄
NULL, // 窗口菜单句柄
hInstance, // 窗口所属应用程序实例
NULL // WM_CREATE消息附加参数lParam传入的数据指针
); // 显示及刷新窗口
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd); // 定义消息结构体
MSG msg;
while (GetMessage( // WM_QUIT消息返回0 错误返回-1
&msg, // 指向消息的结构体
NULL, // 指定接收属于哪一窗口的消息 通常设为NULL,用来接收属于调用线程的所有窗口的窗口消息
, // 获取消息的最小值 通常为0
)) // 获取消息的最大值 都设为0表示接收所有消息
{
TranslateMessage(&msg); // 将虚拟消息转换为字符消息 投递到调用线程的消息队列中 下次调用GetMessage时被取出
DispatchMessage(&msg); // 将消息传递给操作系统 由操作系统调用窗口过程函数对消息进行处理
}
return msg.wParam;
} // 窗口过程函数
LRESULT CALLBACK WinSunProc(
HWND hwnd, // 窗口句柄
UINT uMsg, // 消息代码
WPARAM wParam, // 附加参数
LPARAM lParam
)
{
switch(uMsg)
{
case WM_CHAR:
char szChar[];
sprintf(szChar, "char code is %d", wParam);
MessageBox(hwnd, szChar, "char", );
break; default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
} return ;
}
然后,我们要在消息循环里面添加创建Button的代码,因为Button是一个子窗口,所以创建方式也如同创建窗口一样,使用CreateWindow()函数。
而,此窗口要一开始跟随父窗口出现,所以要在父窗口创建时创建该Button。嗯,所以要在窗口过程函数里面监听下WM_CREATE消息。
代码片段:
switch(uMsg)
{
case WM_CHAR:
char szChar[];
sprintf(szChar, "char code is %d", wParam);
MessageBox(hwnd, szChar, "char", );
break;
case WM_CREATE:
CreateWindowEx(,"Button","按钮1",WS_VISIBLE|WS_CHILD,,,,,hwnd,(HMENU),,); default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
这里要说明一下啦,一开始我也搞得晕晕乎乎,不知道怎么搞Button的消息事件,这里我们用Button的ID啦。先看下微软的MSDN关于CreateWindow()函数
HWND WINAPI CreateWindow(
_In_opt_ LPCTSTR lpClassName,
_In_opt_ LPCTSTR lpWindowName,
_In_ DWORD dwStyle,
_In_ int x,
_In_ int y,
_In_ int nWidth,
_In_ int nHeight,
_In_opt_ HWND hWndParent,
_In_opt_ HMENU hMenu,
_In_opt_ HINSTANCE hInstance,
_In_opt_ LPVOID lpParam
);
关键点在参数HMENU hWndParent,第一眼一看是不是感觉像菜单?不错啦~确实在菜单中用到的。进一步看他的解释
hMenu [in, optional]
Type: HMENU
A handle to a menu, or specifies a child-window identifier depending on the window style. For an overlapped or pop-up window, hMenu identifies the menu to be used with the window; it can be NULL if the class menu is to be used. For a child window, hMenu specifies the child-window identifier, an integer value used by a dialog box control to notify its parent about events. The application determines the child-window identifier; it must be unique for all child windows with the same parent window.
红色选中大体意思说,当在做一个子窗口的时候,这个参数就是一个整形表示,用于标识这个子窗口,提供父窗口的消息处理。总的来说就是所谓的控件ID啦~
既然有标识,就好办啦,我们就判断是不是他,若是这个按钮,我们就让他响应相应的操作啦~~
但是怎么知道按钮被Click了呢?我们又得监听另一个消息WM_COMMAND,它有两个参数,其中一个就传输了所谓的控件ID
wParam
For a description of this parameter.
lParam
For a description of this parameter.
我们可以判断他如果是这个按钮的ID,我们就让他干某些事情。我们首先要转换下wParam的类型,否则和我们写的ID的类型不一样的。
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId)
{
case ()://之前我们创建按钮时,写的ID为0
//功能代码 //....... break; //...更多代码 }
好了,整体框架差不多完工啦,自己再加下代码啥的就没问题了。在这里,我再次浪费下篇幅,给出完整代码:
关于wmId一开始写程序没有编译,因为逻辑错误,未有注意到,忘记声明他了。为了防止被default给忽略掉,我们把他写在switch(uMsg)之前。
#include <windows.h>
#include <stdio.h>
#include <Windef.h> // 窗口过程函数
LRESULT CALLBACK WinSunProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // command line
int nCmdShow // show state
) {
// 窗口类
WNDCLASS wndcls;
wndcls.cbClsExtra = ; // 类附加内存
wndcls.cbWndExtra = ; // 窗口附加内存
wndcls.hbrBackground = (HBRUSH) GetStockObject(COLOR_WINDOW); // 背景画刷句柄
wndcls.hCursor = LoadCursor(NULL, IDC_ARROW); // 窗口光标句柄
wndcls.hIcon = LoadIcon(NULL, IDI_APPLICATION); // 窗口图标句柄
wndcls.hInstance = hInstance; // 包含窗口过程函数的程序实例
wndcls.lpfnWndProc = WinSunProc; // 只想窗口过程函数的指针
wndcls.lpszClassName = "CRoot"; // 窗口类名称
wndcls.lpszMenuName = NULL; // 菜单资源
wndcls.style = CS_HREDRAW | CS_VREDRAW; // 窗口样式
RegisterClass(&wndcls); // 创建窗口, 定义一个变量用来保存成功创建窗口后返回的句柄
HWND hwnd;
hwnd = CreateWindow( // 窗口创建成功时返回为窗口分配的句柄 失败时返回NULL
"CRoot", // 窗口类名
"Hello World", // 窗口名字
WS_CAPTION|WS_SYSMENU, // 窗口样式
CW_USEDEFAULT, CW_USEDEFAULT, // 窗口左上角坐标
, , // 窗口宽高
NULL, // 父窗口句柄
NULL, // 窗口菜单句柄
hInstance, // 窗口所属应用程序实例
NULL // WM_CREATE消息附加参数lParam传入的数据指针
); // 显示及刷新窗口
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd); // 定义消息结构体
MSG msg;
while (GetMessage( // WM_QUIT消息返回0 错误返回-1
&msg, // 指向消息的结构体
NULL, // 指定接收属于哪一窗口的消息 通常设为NULL,用来接收属于调用线程的所有窗口的窗口消息
, // 获取消息的最小值 通常为0
)) // 获取消息的最大值 都设为0表示接收所有消息
{
TranslateMessage(&msg); // 将虚拟消息转换为字符消息 投递到调用线程的消息队列中 下次调用GetMessage时被取出
DispatchMessage(&msg); // 将消息传递给操作系统 由操作系统调用窗口过程函数对消息进行处理
}
return msg.wParam;
} // 窗口过程函数
LRESULT CALLBACK WinSunProc(
HWND hwnd, // 窗口句柄
UINT uMsg, // 消息代码
WPARAM wParam, // 附加参数
LPARAM lParam
)
{
WORD wmId = LOWORD(wParam);
//WORD wmEvent = HIWORD(wParam);
switch(uMsg)
{
/*case WM_CHAR:
char szChar[20];
sprintf(szChar, "char code is %d", wParam);
MessageBox(hwnd, szChar, "char", 0);
break;*/
case WM_CREATE:
CreateWindowEx(,"Button","按钮1",WS_VISIBLE|WS_CHILD,,,,,hwnd,(HMENU),,);
break;
case WM_COMMAND:
switch (wmId)
{
case ://(HMENU) 和创建中的id对应
//这里写你要让按钮实现的功能
MessageBoxA(NULL,"Hello Button!","My TestProject",MB_OK);
}
break; default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
} return ;
}
目前已经在GNU GCC Compiler成功!
最新文章
- mysql truncate带有被引用外键的表时报错解决方法
- Java for LeetCode 038 Count and Say
- PHP框架学习错误总结
- 从SVN导出指定版本号之间修改的文件
- noip2009提高组题解
- 扫描二维码跳转app
- JavaScript——以简单的方式理解闭包
- 今天用css做了一个QQ登录页面
- centos 7下配置mysql+php(ThinkPHP)+nginx
- IE8’s Substr() Bug
- 截取字符串一之substr
- leetcode24,交换链表相邻的节点
- IE6下绝对定位元素父级宽高是奇数,绝对定位元素的right和bottom值会有1个像素的偏差
- 微信小程序(基本知识点)
- css伪类及伪元素用法
- HDFS退出安全模式
- shell脚本使用技巧7--cat
- Best Time to Buy and Sell Stock - LeetCode
- 青蛙的约会---poj1061(扩展欧几里德)
- 20145225唐振遠《网络对抗》Exp5 MSF基础应用
热门文章
- SQL Server AlwaysON从入门到进阶(3)——基础架构
- Weblogic 12c 集群环境搭建
- Programming In Scala笔记-第十五章、Case Classes和模式匹配
- LauncherModel.Callbacks接口
- Hive基本原理及环境搭建
- Markdown对应Yelee主题语法
- 如何对n个大小都小于100的整数进行排序,要求时间复杂度O(n),空间复杂度O(1)。
- svn数据仓库配置,权限配置
- Android基于Retrofit2.0 +RxJava 封装的超好用的RetrofitClient工具类(六)
- java详解final、多态、抽象类、接口原理