跟我一起玩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类型)。

然后,运行一下,先看看效果再说吧。
跟我一起玩Win32开发(11):使用控件——先来耍一下按钮_第1张图片

 

接下来,新的问题来了,按钮我是创建了,但怎么响应用户点击呢?其实,这按钮与菜单项一样,单击用户与她“亲密”接触后,我们的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;


看看效果。

跟我一起玩Win32开发(11):使用控件——先来耍一下按钮_第2张图片

 

这时候,我希望,当我点击了按钮后,按钮上的文本变成“按钮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。

运行结果如下图所示。

跟我一起玩Win32开发(11):使用控件——先来耍一下按钮_第3张图片

 

完整的示例如下:

#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):使用控件——先来耍一下按钮)