跟我一起玩Win32开发(11):使用控件——先来耍一下按钮
用户通过控件与应用程序交互,在吹牛之前,先介绍一个工具,这是官方的工具,使用它,你可以预览常用控件的外观、样式,以及对控进行操作时接收和发送哪些消息。下载地址如下:
http://www.microsoft.com/en-us/download/details.aspx?id=4635
我们可以把控件当成特殊的一类窗口,所以,创建控件与创建窗口一样,使用CreateWindow或CreateWindowEx函数,不过,在窗口样式上面记得用上以下两位帅哥:
a、WS_CHILD:控件是放在我们的窗口上的,自然要作为窗口的子窗口,WS_CHILDWINDOW也一样,为了节约几个字母,用WS_CHILD吧。
b、WS_VISIBLE:既然要使用控件,自然要让别人看得见。要想别人称赞你老婆漂亮,当然要先让别人见一见你老婆了,哈哈,不要想歪了。
理论的东西,怎么说都是抽象的,咱们还是“所见即所得”吧。那么,到底在啥时候创建控件合适一点呢?一种方法是在WinMain方法中创建,把CreateWindow函数的hWndParent设置为窗口的句柄。
俺这里用第二种方法,我们知道,在窗口创建后,显示之前,即CreateWindow函数返回之前,我们会收到WM_CREATE消息,我们响应它的号召,艰苦奋斗创建一个按钮。
- case WM_CREATE:
- {
- //创建按钮
- HWND hButton = CreateWindow(L"Button", L"有种就来点击我!", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
- 35, 45, 160, 65, hwnd, NULL, hg_app, NULL);
- }
- return 0;
hg_app是我定义的一个全局变量,当前应用程序的句柄(HINSTANCE类型)。
然后,运行一下,先看看效果再说吧。
接下来,新的问题来了,按钮我是创建了,但怎么响应用户点击呢?其实,这按钮与菜单项一样,单击用户与她“亲密”接触后,我们的WindowProc会收到WM_COMMAND消息,和菜单一样。
wParam的低字节位表示ID号,高字节位表示控件通知,比如用户单击了按钮,通知码为BN_CLICKED,这样我们就可以了解到用户具体对按钮干了什么。
lParam中保存了控件的句柄。
问题是,怎么设置控件的ID?我们看看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 [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,反正hMenu闲着也没事干,就给个ID它玩玩。ID号是一个整数,不过为了可读性,一般是声明一个宏,其实我们在资源编辑器中使用的资源ID(如IDM_FUCK)就是在resource.h中定义的宏的,既然叫ID了,你就知道它的值不要重复。
我们也来模拟一下,在文件的前面(#include...后)也声明三个宏,分别标识三个按钮。
- #define IDB_ONE 3301
- #define IDB_TWO 3302
- #define IDB_THREE 3303
然后创建三个按钮:
- case WM_CREATE:
- {
- //创建三个按钮
- CreateWindow(L"Button", L"按钮一", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
- 35, 10, 120, 60, hwnd, (HMENU)IDB_ONE, hg_app, NULL);
- CreateWindow(L"Button", L"按钮二", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
- 35, 80, 120, 60, hwnd, (HMENU)IDB_TWO, hg_app, NULL);
- CreateWindow(L"Button", L"按钮三", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
- 35, 150, 120, 60, hwnd, (HMENU)IDB_THREE, hg_app, NULL);
- }
- return 0;
然后我们来响应WM_COMMAND消息。
- case WM_COMMAND:
- {
- switch(LOWORD(wParam))
- {
- case IDB_ONE:
- MessageBox(hwnd, L"您点击了第一个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);
- break;
- case IDB_TWO:
- MessageBox(hwnd, L"您点击了第二个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);
- break;
- case IDB_THREE:
- MessageBox(hwnd, L"您点击了第三个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);
- break;
- default:
- break;
- }
- }
- return 0;
看看效果。
这时候,我希望,当我点击了按钮后,按钮上的文本变成“按钮X已点击”,该怎么做呢?Windows系统是基于消息机制的,所以,首先想到,向控件发送消息,要改变控件相关的文本,应当发送WM_SETTEXT消息。
我们把上面的代码改一下。
- case WM_COMMAND:
- {
- switch(LOWORD(wParam))
- {
- case IDB_ONE:
- //MessageBox(hwnd, L"您点击了第一个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);
- SendMessage((HWND)lParam, WM_SETTEXT, (WPARAM)NULL, (LPARAM)L"第一个按鈕已点击");
- break;
- case IDB_TWO:
- //MessageBox(hwnd, L"您点击了第二个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);
- SendMessage((HWND)lParam, WM_SETTEXT, (WPARAM)NULL, (LPARAM)L"第二个按鈕已点击");
- break;
- case IDB_THREE:
- //MessageBox(hwnd, L"您点击了第三个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);
- SendMessage((HWND)lParam, WM_SETTEXT, (WPARAM)NULL, (LPARAM)L"第三个按鈕已点击");
- break;
- default:
- break;
- }
- }
- return 0;
前面我们知道,WM_COMMAND消息的lParam保存控件的句柄,所以,我们传给SendMessage的第一个参数是操作目标的句柄,注意,这里不要传WindowProc回调中的参数,因为我们现在要操作的对象是按钮,不是窗口,WindowProc传进到的句柄是指我们注册的窗口,因为我们在WNDCLASS中已经设定了该WindowProc函数。
要对按钮进行操作,应当使用WM_COMMAND的lParam中包含的值,强制转换为HWND。
运行结果如下图所示。
完整的示例如下:
- #include <Windows.h>
- #include <WinNT.h>
- //#include "resource.h"
- #define IDB_ONE 3301
- #define IDB_TWO 3302
- #define IDB_THREE 3303
- LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
- LPCWSTR lps_cl = L"MyApp";//类名
- LPCWSTR wd_text = L"超级应用";//窗口标题
- HINSTANCE hg_app;//全局实例句柄
- int WINAPI wWinMain(HINSTANCE hThisApp,
- HINSTANCE hPrevApp,
- LPWSTR lpCmd,
- int nShow)
- {
- WNDCLASSEX wc = { };
- wc.cbSize = sizeof(WNDCLASSEX);
- wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
- wc.hInstance = hThisApp;
- wc.lpfnWndProc = (WNDPROC)WindowProc;
- wc.lpszClassName = lps_cl;
- wc.style = CS_HREDRAW | CS_VREDRAW;
- RegisterClassEx(&wc);
- HWND hwnd = CreateWindowEx(WS_EX_WINDOWEDGE,
- lps_cl,
- wd_text,
- WS_OVERLAPPEDWINDOW,
- 20,
- 25,
- 400,
- 300,
- NULL,
- NULL,
- hThisApp,
- NULL);
- if(hwnd == NULL)
- return -1;
- ShowWindow(hwnd, nShow);
- UpdateWindow(hwnd);
- hg_app = hThisApp;
- MSG msg;
- while(GetMessage(&msg,NULL,0,0))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return 0;
- }
- LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
- {
- switch(msg)
- {
- case WM_DESTROY:
- PostQuitMessage(0);
- return 0;
- case WM_CREATE:
- {
- //创建三个按钮
- CreateWindow(L"Button", L"按钮一", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
- 35, 10, 160, 60, hwnd, (HMENU)IDB_ONE, hg_app, NULL);
- CreateWindow(L"Button", L"按钮二", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
- 35, 80, 160, 60, hwnd, (HMENU)IDB_TWO, hg_app, NULL);
- CreateWindow(L"Button", L"按钮三", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
- 35, 150, 160, 60, hwnd, (HMENU)IDB_THREE, hg_app, NULL);
- }
- return 0;
- case WM_COMMAND:
- {
- switch(LOWORD(wParam))
- {
- case IDB_ONE:
- //MessageBox(hwnd, L"您点击了第一个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);
- SendMessage((HWND)lParam, WM_SETTEXT, (WPARAM)NULL, (LPARAM)L"第一个按鈕已点击");
- break;
- case IDB_TWO:
- //MessageBox(hwnd, L"您点击了第二个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);
- SendMessage((HWND)lParam, WM_SETTEXT, (WPARAM)NULL, (LPARAM)L"第二个按鈕已点击");
- break;
- case IDB_THREE:
- //MessageBox(hwnd, L"您点击了第三个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);
- SendMessage((HWND)lParam, WM_SETTEXT, (WPARAM)NULL, (LPARAM)L"第三个按鈕已点击");
- break;
- default:
- break;
- }
- }
- return 0;
- default:
- return DefWindowProc(hwnd,msg,wParam,lParam);
- }
- return 0;
- }
跟我一起玩Win32开发(11):使用控件——先来耍一下按钮的更多相关文章
- 跟我一起玩Win32开发(转自CSDN-东邪独孤)
跟我一起玩Win32开发(1):关于C++的几个要点 跟我一起玩Win32开发(2):完整的开发流程 跟我一起玩Win32开发(3):窗口的重绘 跟我一起玩Win32开发(4):创建菜单 跟我一起玩W ...
- 跟我一起玩Win32开发(17):启动和结束进程
这里我再次说明一下,我不知道为什么,现在的人那么喜欢走极端,估计是价值观都“升级”了的缘故吧. 我撰写这一系列Win32相关的文章,并不是叫大家一定要用Win32去开发项目,仅仅是给大家了解一下,Wi ...
- python开发_tkinter_窗口控件_自己制作的Python IDEL_博主推荐(二)
在上一篇blog:python开发_tkinter_窗口控件_自己制作的Python IDEL_博主推荐 中介绍了python中的tkinter的一些东西,你可能对tkinter有一定的了解了.这篇b ...
- Android零基础入门第17节:Android开发第一个控件,TextView属性和方法大全
原文:Android零基础入门第17节:Android开发第一个控件,TextView属性和方法大全 前面简单学习了一些Android UI的一些基础知识,那么接下来我们一起来详细学习Android的 ...
- 基于Jquery WeUI的微信开发H5页面控件的经验总结(2)
在微信开发H5页面的时候,往往借助于WeUI或者Jquery WeUI等基础上进行界面效果的开发,由于本人喜欢在Asp.net的Web界面上使用JQuery,因此比较倾向于使用 jQuery WeUI ...
- WinForm界面开发之布局控件"WeifenLuo.WinFormsUI.Docking"的使用
WinForm界面开发之布局控件"WeifenLuo.WinFormsUI.Docking"的使用 转自:http://www.cnblogs.com/wuhuacong/arch ...
- Android开发之日历控件实现
Android开发之日历控件实现:以下都是转载的. 日历控件 日历控件 日历控件 日历控件
- Qt 开发 MS VC 控件终极篇
Qt 开发 MS VC 控件终极篇 1. 使用 MSVC2015 通过项目向导创建 Qt ActiveQt Server 解决方案 项目配置:以下文件需要修改 1. 项目属性页->项目属性-&g ...
- Android开发:文本控件详解——TextView(一)基本属性
一.简单实例: 新建的Android项目初始自带的Hello World!其实就是一个TextView. 在activity_main.xml中可以新建TextView,从左侧组件里拖拽到右侧预览界面 ...
随机推荐
- sendmessage传递数组
1.在初始化数组尤其是需要每次都初始化的时候,很多同学使用循环来进行,这样不但速度慢,而且写起来也很长.所以现在提供一个函数来实现这个功能... 原型:extern void *memset(void ...
- 新装Linux系统没有网卡驱动的解决办法和步骤
Linux下查看网卡驱动和版本信息 - CSDN博客 https://blog.csdn.net/guyan1101/article/details/72770424/ 检查网卡是否加载 - Linu ...
- DOM操作二
1.创建节点 createElement(): 创建新的Element节点 var s = document.createElement('script'); createTextNode(): ...
- HDFS集群安装部署
准备环境: 三台centos7虚拟机(Node-1,Node-2,Node-3) 配置虚拟机网络,保证三台机器可以互相ping通,并且和宿主机可以互相ping通.如果仅仅是作为虚拟机学习,可以关闭防火 ...
- nodejs的request模块
request模块让http请求变的更加简单.(作为客户端,去请求.抓取另一个网站的信息) request的GitHub主页: https://github.com/request/request 最 ...
- Qt & opencv 学习(二)
例子:打开图片并显示.打开图片利用Qt的标准文件对话框,第一步是利用OpenCV创建窗口并显示. 添加一个Button,转到信号槽添加代码: using namespace cv; Mat image ...
- MessageBox_ swt
SWT有不同类型的对话框.有些对话框具有特殊的属性. MessageBox messageBox = new MessageBox(shell, SWT.OK|SWT.CANCEL); if (mes ...
- C/S转分布式数据库的解决方法
C/S转分布式数据库的解决方法1. 直接VPN建一个网不就行了.(大概是虚拟成一个网络)2. 直连也可以,就是速度慢3. 还是三层吧,推荐RTC4. 弄个花生壳硬件试试呢,成本低,不用改程序5. 搞一 ...
- 51nod 1600 Simple KMP
又被机房神犇肉丝哥哥和glory踩爆了 首先这个答案的输出方式有点套路,当前的答案=上一个答案+每一个后缀的f值=上一个答案+上一次算的每个后缀的f值+当前每个后缀的深度 这个题意给了个根深度为-1有 ...
- hdu 2680 Choose the best route 解题报告
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2680 题目意思:实质就是给定一个多源点到单一终点的最短路. 卑鄙题---有向图.初始化map时 千万不 ...