三、Button控件

一、关于ClassName

在创建窗口的时候,无论是CreateWindow()函数还是CreateWindowEX()函数,所给定的第一个参数就是一个关于类名的字符串。而这样的一个类名,在之前的程序里都是在自行自行设定了WNDCLASSEX结构体变量后,注册的窗口类。实际上,Win32系统在创建窗口寻找参照的窗口类时,假如并没有在程序局部窗口类(程序员在应用程序中自行注册的窗口类)中找到CreateWindowEX()/CreateWindow()中指定类名的窗口类,会继续从系统窗口类中查找是否存在该窗口类。

一些常用的Win32系统窗口类,如:BUTTON/EDIT/LISTBOX/STATIC/SCROLLBAR等。

二、BUTTON

由于使用的是系统窗口类来创建窗口,所以不需要再注册窗口类,直接创建窗口然后消息循环。

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    HWND hwndButton=CreateWindow("BUTTON","OK",WS_OVERLAPPEDWINDOW,
                                 CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
                                 NULL,NULL,hInstance,NULL);
    if(!hwndButton) return 0;
    ShowWindow(hwndButton,nCmdShow);
    UpdateWindow(hwndButton);
    MSG msg={0};
    while(GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}
但是创建完成后可以发现,单击按钮是没有任何的反应的,因为在BUTTON类中默认使用的消息处理函数没有对该消息作出任何的响应,而消息处理函数系统在创建BUTTON窗口类型的时候已经给定了。

所以在这里需要用到另外一个函数:

LONG SetWindowLong(
  HWND hWnd,       // handle of window
  int nIndex,      // offset of value to set
  LONG dwNewLong   // new value
);
SetWindowLong()可以更改一些在注册窗口类时给定的参数值。但是其仅更改第一个窗口句柄参数hWnd所指向的窗口实例的相应参数,而不是改动的整个窗口类的属性。

其中nIndex表示需要更改的参数类型,如消息处理函数地址,则给定GWL_WNDPROC宏。

dwNewLong表示需要改变的新值。

所以,在这只需要再写一个消息处理函数:

WNDPROC g_OldButtonProc=NULL;
LRESULT CALLBACK ButtonProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
	if(uMsg==WM_DESTROY) 
	{
		PostQuitMessage(0);
		return 0;
	}
	else if(uMsg==WM_LBUTTONDOWN)
	{
		MessageBox(hWnd,"HELLO","HI",MB_OK);
		return 0;
	}
	return CallWindowProc(g_OldButtonProc,hWnd,uMsg,wParam,lParam);
}
然后在主函数中创建窗口与消息循环中间加上

g_OldButtonProc=(WNDPROC)SetWindowLong(hwndButton,GWL_WNDPROC,(LONG)ButtonProc);

三、子窗口

前面所提到的一些系统窗口类,如BUTTON、EDIT等,一般都叫作控件。

而这类控件又一般则不会像前一节一样直接创建一个窗口,而是以其他窗口的子窗口的形式出现。

所以一般来讲控件的创建一般都是在父窗口的WM_CREATE消息中所创建的:

void OnCreate(HWND hWnd,LPARAM lParam)
{
    CreateWindowEx(0,"BUTTON","OK",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
                   4,4,150,32,hWnd,(HMENU)IDC_BTN_OK,g_hInstance,NULL);
}

基本上参数的给定都与之前一般窗口的创建一致,而唯一要注意的两处地方就是第四个参数窗口风格,以及倒数第三个参数默认菜单句柄的给定。

首先来看风格。

由于该BUTTON控件属于主窗口的子窗口(所以父窗口参数也给定的是主窗口句柄hWnd),所以添加了WS_CHILD属性。

WS_VISIBLE使得该控件可见。

而BS_PUSHBUTTON这样的以BS(BUTTON STYLE)开头是BUTTON控件的专用属性,BS_PUSHBUTTON指的是按钮窗口,其他的还有:

BS_RADIOBUTTON:单选按钮;

BS_CHECKBOX/BS_AOTOCHECKBOX:复选按钮等等。

然后是默认菜单句柄的给定。

这里的给定很独特。

是一个完全随意定义的整数常量(强转为HMENU)。那是因为在控件中,是已经不可能添加菜单资源了的,所以这个参数在这里是一个复用,而其含义则不再表示菜单资源句柄,表示的是控件ID。

所以在主窗口的WM_CREATE消息中调用上面的OnCreate()函数即可创建OK按钮。

然而创建以后情况与之前一个样,单击按钮不会有任何的响应。

同样是因为我们没有处理消息处理函数。在这里我们可以和前面一样,利用SetWindowLong()函数来更改OK按钮的消息处理函数。

但是在这里,更为普遍也更为规范的做法是,处理主函数的WM_COMMAND消息。

WM_COMMAND消息用途很多,这里是其中的一个。

当对按钮进行一个单击事件以后,按钮的默认事件处理函数并非没有做任何的事情。

在按钮的单击事件里,向其父窗口发出了一个WM_COMMAND消息。

其中,wParam参数的低16位中记录了该按钮的ID。

而lParam参数的高16位中记录了事件的类别,如这里的单击则是BN_CLICKED。

所以需要在主窗口消息处理函数的WM_COMMAND中添加下面函数的调用:

void OnCommand(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
	if(LOWORD(wParam)==IDC_BTN_OK)
	{
		if(HIWORD(wParam)==BN_CLICKED)
		{
			CHAR szText[256]={0};
			GetWindowText((HWND)lParam,szText,sizeof(szText)/sizeof(szText[0]));
			MessageBox(hWnd,szText,"OK",MB_OK);
		}
	}
}

四、完整代码

#include<windows.h>
#include<stdio.h>
#define IDC_BTN_OK		4001

LPCSTR g_pszAppName="WinButton";
LPCSTR g_pszMainWndClass="MAIN";
HINSTANCE g_hInstance=NULL;

void OnCreate(HWND hWnd,LPARAM lParam)
{
	CreateWindowEx(0,"BUTTON","OK",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
				   4,4,150,32,hWnd,(HMENU)IDC_BTN_OK,g_hInstance,NULL);
}

void OnCommand(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
	if(LOWORD(wParam)==IDC_BTN_OK)
	{
		if(HIWORD(wParam)==BN_CLICKED)
		{
			CHAR szText[256]={0};
			GetWindowText((HWND)lParam,szText,sizeof(szText)/sizeof(szText[0]));
			MessageBox(hWnd,szText,"OK",MB_OK);
		}
	}
}

LRESULT CALLBACK MainWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
	switch(uMsg)
	{
	case WM_COMMAND:
		OnCommand(hWnd,wParam,lParam);
		break;
	case WM_CREATE:
		OnCreate(hWnd,lParam);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;	
	}
	return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

ATOM InitApplication(HINSTANCE hInstance)
{
	WNDCLASSEX wcex={0};
	wcex.cbSize=sizeof(wcex);
	wcex.style=CS_HREDRAW|CS_VREDRAW;
	wcex.lpfnWndProc=MainWndProc;
	wcex.cbClsExtra=0;
	wcex.cbWndExtra=0;
	wcex.hInstance=hInstance;
	wcex.hIcon=LoadIcon(NULL,IDI_APPLICATION);
	wcex.hIconSm=LoadIcon(NULL,IDI_APPLICATION);
	wcex.hCursor=LoadCursor(NULL,IDC_ARROW);

	wcex.hbrBackground=GetSysColorBrush(COLOR_3DFACE);
	wcex.lpszMenuName=NULL;
	wcex.lpszClassName=g_pszMainWndClass;
	return RegisterClassEx(&wcex);
}

BOOL InitInstance(HINSTANCE hInstance,int nCmdShow)
{
	g_hInstance=hInstance;
	HWND hWnd=CreateWindowEx(WS_EX_CLIENTEDGE,g_pszMainWndClass,g_pszAppName,
							 WS_OVERLAPPEDWINDOW,
							 CW_USEDEFAULT,CW_USEDEFAULT,170,15*36,NULL,NULL,
							 hInstance,NULL);
	if(!hWnd) return 0;
	ShowWindow(hWnd,nCmdShow);
	UpdateWindow(hWnd);
	return 1;
}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	if(!hPrevInstance)
		if(!InitApplication(hInstance))
			return 0;
	if(!InitInstance(hInstance,nCmdShow)) return 0;
	MSG msg={0};
	while(GetMessage(&msg,NULL,0,0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值