win32程序创建按钮并响应点击
2017-10-29 15:26
423 查看
我们可以把控件当成特殊的一类窗口,所以,创建控件与创建窗口一样,使用CreateWindow或CreateWindowEx函数,不过,在窗口样式上面记得用上以下两位帅哥:
a、WS_CHILD:控件是放在我们的窗口上的,自然要作为窗口的子窗口,WS_CHILDWINDOW也一样,为了节约几个字母,用WS_CHILD吧。
b、WS_VISIBLE:既然要使用控件,自然要让别人看得见。
到底在啥时候创建控件合适一点呢?一种方法是在WinMain方法中创建,注意要把CreateWindow函数的hWndParent参数设置为窗口的句柄。
这里用第二种方法,我们知道,在窗口创建后,显示之前,即CreateWindow函数返回之前,我们会收到WM_CREATE消息,我们响应它的号召,艰苦奋斗创建一个按钮。
//窗口处理函数
LRESULT CALLBACK WinProc(
HWND hwnd, //当前句柄
UINT msg, //当前MSG消息
WPARAM wParam,
LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
//创建窗口时调用,我们也可以在这里面创建按钮
break;
case WM_CLOSE: //点击关闭按钮
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd,msg,wParam,lParam);
}
return 0;
}
接下来,新的问题来了,按钮我是创建了,但怎么响应用户点击呢?其实,这按钮与菜单项一样,单击点击后,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 lpPar
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了,你就知道它的值不要重复。
我们也来模拟一下,在文件的前面也声明三个宏,分别标识三个按钮。
然后创建三个按钮:
case WM_CREATE:
{
//创建三个按钮
CreateWindow(L"Button", L"按钮一", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
35, 10, 120, 60, hwnd, (HMENU)IDB_ONE, hwnd, NULL);
CreateWindow(L"Button", L"按钮二", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
35, 80, 120, 60, hwnd, (HMENU)IDB_TWO, hwnd, NULL);
CreateWindow(L"Button", L"按钮三", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
35, 150, 120, 60, hwnd, (HMENU)IDB_THREE, hwnd, NULL);
}
break;
然后我们来响应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;
}
}
break;
看看效果。
这时候,我希望,当我点击了按钮后,按钮上的文本变成“按钮X已点击”,该怎么做呢?Windows系统是基于消息机制的,所以,首先想到,向控件发送消息,要改变控件相关的文本,应当发送WM_SETTEXT消息。
我们把上面的代码改一下。
前面我们知道,WM_COMMAND消息的lParam保存控件的句柄,所以,我们传给SendMessage的第一个参数是操作目标的句柄,注意,这里不要传WindowProc回调中的参数,因为我们现在要操作的对象是按钮,不是窗口,WindowProc传进到的句柄是指我们注册的窗口,因为我们在WNDCLASS中已经设定了该WindowProc函数。
要对按钮进行操作,应当使用WM_COMMAND的lParam中包含的值,强制转换为HWND。
运行结果如下图所示。
完整的示例如下:
#include <Windows.h>
//按钮ID
#define IDB_ONE 3301
#define IDB_TWO 3302
#define IDB_THREE 3303
//函数声明
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
LPCWSTR WINDOWS_CLASS = "MyClass"; //类名
LPCWSTR WINDOWS_TITLE = "测试按钮"; //窗口标题
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 = WINDOWS_CLASS;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClassEx(&wc);
HWND hwnd = CreateWindowEx(WS_EX_WINDOWEDGE,
WINDOWS_CLASS,
WINDOWS_TITLE,
WS_OVERLAPPEDWINDOW,
20,
25,
400,
300,
NULL,
NULL,
hThisApp,
NULL);
if (hwnd == NULL)
{
return -1;
}
ShowWindow(hwnd, nShow);
UpdateWindow(hwnd);
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, hwnd, NULL);
CreateWindow(L"Button", L"按钮二", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
35, 80, 160, 60, hwnd, (HMENU)IDB_TWO, hwnd, NULL);
CreateWindow(L"Button", L"按钮三", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
35, 150, 160, 60, hwnd, (HMENU)IDB_THREE, hwnd, 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;
}
a、WS_CHILD:控件是放在我们的窗口上的,自然要作为窗口的子窗口,WS_CHILDWINDOW也一样,为了节约几个字母,用WS_CHILD吧。
b、WS_VISIBLE:既然要使用控件,自然要让别人看得见。
到底在啥时候创建控件合适一点呢?一种方法是在WinMain方法中创建,注意要把CreateWindow函数的hWndParent参数设置为窗口的句柄。
这里用第二种方法,我们知道,在窗口创建后,显示之前,即CreateWindow函数返回之前,我们会收到WM_CREATE消息,我们响应它的号召,艰苦奋斗创建一个按钮。
//窗口处理函数
LRESULT CALLBACK WinProc(
HWND hwnd, //当前句柄
UINT msg, //当前MSG消息
WPARAM wParam,
LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
//创建窗口时调用,我们也可以在这里面创建按钮
break;
case WM_CLOSE: //点击关闭按钮
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd,msg,wParam,lParam);
}
return 0;
}
接下来,新的问题来了,按钮我是创建了,但怎么响应用户点击呢?其实,这按钮与菜单项一样,单击点击后,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 lpPar
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了,你就知道它的值不要重复。
我们也来模拟一下,在文件的前面也声明三个宏,分别标识三个按钮。
#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, hwnd, NULL);
CreateWindow(L"Button", L"按钮二", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
35, 80, 120, 60, hwnd, (HMENU)IDB_TWO, hwnd, NULL);
CreateWindow(L"Button", L"按钮三", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
35, 150, 120, 60, hwnd, (HMENU)IDB_THREE, hwnd, NULL);
}
break;
然后我们来响应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;
}
}
break;
看看效果。
这时候,我希望,当我点击了按钮后,按钮上的文本变成“按钮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; } } break;
前面我们知道,WM_COMMAND消息的lParam保存控件的句柄,所以,我们传给SendMessage的第一个参数是操作目标的句柄,注意,这里不要传WindowProc回调中的参数,因为我们现在要操作的对象是按钮,不是窗口,WindowProc传进到的句柄是指我们注册的窗口,因为我们在WNDCLASS中已经设定了该WindowProc函数。
要对按钮进行操作,应当使用WM_COMMAND的lParam中包含的值,强制转换为HWND。
运行结果如下图所示。
完整的示例如下:
#include <Windows.h>
//按钮ID
#define IDB_ONE 3301
#define IDB_TWO 3302
#define IDB_THREE 3303
//函数声明
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
LPCWSTR WINDOWS_CLASS = "MyClass"; //类名
LPCWSTR WINDOWS_TITLE = "测试按钮"; //窗口标题
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 = WINDOWS_CLASS;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClassEx(&wc);
HWND hwnd = CreateWindowEx(WS_EX_WINDOWEDGE,
WINDOWS_CLASS,
WINDOWS_TITLE,
WS_OVERLAPPEDWINDOW,
20,
25,
400,
300,
NULL,
NULL,
hThisApp,
NULL);
if (hwnd == NULL)
{
return -1;
}
ShowWindow(hwnd, nShow);
UpdateWindow(hwnd);
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, hwnd, NULL);
CreateWindow(L"Button", L"按钮二", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
35, 80, 160, 60, hwnd, (HMENU)IDB_TWO, hwnd, NULL);
CreateWindow(L"Button", L"按钮三", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
35, 150, 160, 60, hwnd, (HMENU)IDB_THREE, hwnd, 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 htmlayout点击按钮创建新窗口,以及按钮图片样式
- 如何在其他程序的窗口上创建按钮并使之能响应
- 点击触摸屏按钮,qt程序弹出提示信息很慢!
- MFC点击按钮发出声音_playsound_循环/单次播放_声音文件加入程序中
- 用 C++ 创建简单的 Win32 服务程序
- UIActionSheet 按钮不响应点击事件的解决方法
- 关于无边框EXE程序窗口嵌入IE浏览器WebBrowser右键属性窗口无法点击响应问题的解决
- 用android做的一个简单的点击按钮显示图片的程序
- win32只创建一个对话框的程序(很有趣)
- 急求高手指点!程序修改之后,点击button按钮,为什么没有反应??
- VC模拟点击其他程序按钮
- Android下listview每个Item中包含有按钮,为什么在点击某一行按钮的时候,同时有多行button触发了响应事件?
- 响应send按钮的点击事件
- 创建一个不显示窗口的Win32程序