windows程序设计(11)初探控件

什么是控件呢?简单的说,控件的其实就是一个个窗口(如果不是窗口,怎么能或得鼠标点击或者空格键的消息呢)。所以理论上,我们也可以不使用windows自带的控件,而自己动手写一个当做控件用的窗口。那么我们大概需要做一下几件事情:

1.创建并注册这个窗口。

2.通过前面的雷区翻盖程序,我们可以想到:控件每次点击不同的相应,应该是就是贴图的效果,所以对于每次点击窗口,需要贴图。

3.建立一个数据结构,记录控件是否被选中。

而windos系统,自动帮我们完成了后两件事情,当我们使用控件时,只需要注册窗口就行了。
让我们先看一段程序:

#include <windows.h>

struct
{	     
	int	iStyle ;

	TCHAR *	    szText ;
}

button[] =

{

	BS_PUSHBUTTON,			TEXT ("下压按钮"),

	BS_DEFPUSHBUTTON,		TEXT ("默认下压按钮"),
	//该复选框需要程序员给它发出消息才能被选中
	BS_CHECKBOX,			TEXT ("复选框"),
	//自动复选框
	BS_AUTOCHECKBOX,		TEXT ("自动复选框"),

	BS_RADIOBUTTON,			TEXT ("单选按钮"),

	BS_3STATE,				TEXT ("3状态复选框"),

	BS_AUTO3STATE,			TEXT ("自动3状态复选框"),
							
	//既不处理鼠标键盘输入,也不向父窗口发送WM_COMMAND消息,用来包含其他控制按钮
	BS_GROUPBOX,			TEXT ("分组框"),

	BS_AUTORADIOBUTTON,		TEXT ("自动单选按钮"),
	//自绘按钮
	BS_OWNERDRAW,			TEXT ("OWNERDRAW")

} ;

//总控件数
#define NUM (sizeof button / sizeof button[0])

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow)
{

	static TCHAR szAppName[] = TEXT ("BtnLook") ;

	HWND			hwnd ;

	MSG				msg ;

	WNDCLASS		wndclass ;

   

	wndclass.style				= CS_HREDRAW | CS_VREDRAW ;

	wndclass.lpfnWndProc		= WndProc ;

	wndclass.cbClsExtra			= 0 ;

	wndclass.cbWndExtra			= 0 ;

	wndclass.hInstance			= hInstance ;

	wndclass.hIcon				= LoadIcon (NULL, IDI_APPLICATION) ;

	wndclass.hCursor			= LoadCursor (NULL, IDC_ARROW) ;

	wndclass.hbrBackground		= (HBRUSH) GetStockObject (WHITE_BRUSH) ;

	wndclass.lpszMenuName		= NULL ;

	wndclass.lpszClassName		 = szAppName ;

   

	if (!RegisterClass (&wndclass))

    {

	       MessageBox (  NULL, TEXT ("This program requires Windows NT!"),

						     szAppName, MB_ICONERROR) ;

	       return 0 ;

	}

   

	hwnd = CreateWindow (szAppName, TEXT ("Button Look"),

			WS_OVERLAPPEDWINDOW,

			CW_USEDEFAULT, CW_USEDEFAULT,

			CW_USEDEFAULT, CW_USEDEFAULT,

			NULL, NULL, hInstance, NULL) ;


	ShowWindow (hwnd, iCmdShow) ;

	UpdateWindow (hwnd) ;


	while (GetMessage (&msg, NULL, 0, 0))

	{

		TranslateMessage (&msg) ;

		DispatchMessage (&msg) ;

	}

	return msg.wParam ;

}


LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

{
	//窗口句柄数组
	static HWND	hwndButton[NUM] ;
	//矩形区域
	static RECT	rect ;

	static TCHAR	szTop[]			= TEXT ("message          wParam      lParam"),

					szUnd[]			= TEXT ("_______          ______      ______"),
					//格式控制的具体含义:[标志][输出最小宽度][.精度][长度]类型
					//左对齐,最小宽度为16,打印字符串
					//用0填充,最小宽度为4,打印16进制
					//注意上面两行程序中应注意对齐
					szFormat[]		= TEXT ("%-16s %04X-%04X   %04X-%04X"),

					szBuffer[50] ;

	static int	 cxChar, cyChar ;
	
	HDC			hdc ;

	PAINTSTRUCT	ps ;

	int			 i ;

   

	switch (message)

	{

	case   WM_CREATE :
			//系统字体的平均宽度
			cxChar = LOWORD (GetDialogBaseUnits ()) ;
			//系统字体的平局高度
			cyChar = HIWORD (GetDialogBaseUnits ()) ;



			for (i = 0 ; i < NUM ; i++)
				
				hwndButton[i] =CreateWindow ( TEXT("button"),button[i].szText,//注册类名,窗口名
							//窗口类型:子窗口,可见,窗口类型
							WS_CHILD | WS_VISIBLE | button[i].iStyle,
							//窗口左上角位置的x,y坐标
							cxChar, cyChar * (1 + 2 * i),
							//窗口的宽度和高度:
							//当按钮的高度为文字字元高度的 7/4 倍时,按钮的外观看起来最好
							20 * cxChar, 7 * cyChar / 4,
							//父窗口,子窗口ID(这个位置通常填的是菜单,所以要转换成菜单类型)
							hwnd, (HMENU) i,
							//对create消息的lParam参数进行强制类型转化后,得到的是指向
							//LPCREATESTRUCT是指向CREATESTRUCT结构的指针,对lParam进行转化后结构体的hInstance就是窗口句柄
							((LPCREATESTRUCT) lParam)->hInstance, NULL) ;

	       return 0 ;


	case   WM_SIZE :

		rect.left		= 24 * cxChar ;

		rect.top		=  2 * cyChar ;

		rect.right		= LOWORD (lParam) ;

		rect.bottom		= HIWORD (lParam) ;

		return 0 ;

	case   WM_PAINT :

		InvalidateRect (hwnd, &rect, TRUE) ;



		hdc = BeginPaint (hwnd, &ps) ;

		SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;
		//背景设为透明
		SetBkMode (hdc, TRANSPARENT) ;

		//输出的最上面两行表头
		//输出文字:参数为窗口句柄,x坐标,y坐标,字符串,输出字数
		TextOut (hdc, 24 * cxChar, cyChar, szTop, lstrlen (szTop)) ;

		TextOut (hdc, 24 * cxChar, cyChar, szUnd, lstrlen (szUnd)) ;



		EndPaint (hwnd, &ps) ;

		return 0 ;


	//自绘按钮BS_OWNERDRAW需要通过WM_DRAWITEM来绘制
	case   WM_DRAWITEM :

	case   WM_COMMAND :
		//滚动指定矩形区域的内容
		//参数为:窗口句柄,水平滚动量,垂直滚动量,滚动的区域,
		ScrollWindow (hwnd, 0, -cyChar, &rect, &rect) ;



		hdc = GetDC (hwnd) ;

		SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;

       

		TextOut(	hdc, 24 * cxChar, cyChar * (rect.bottom / cyChar - 1),

				    szBuffer,
					//在缓冲区中以一定格式存储字符串,返回值为字符串的个数
					//参数为:缓冲区,格式,
					//wParam的高字节是通知码,低字节是控件窗口ID(创建时自己定义的)
				    wsprintf (szBuffer, szFormat,
					message == WM_DRAWITEM ? TEXT ("WM_DRAWITEM") :
					TEXT ("WM_COMMAND"),HIWORD (wParam), LOWORD (wParam),HIWORD (lParam), LOWORD (lParam))) ;



		ReleaseDC (hwnd, hdc) ;

		ValidateRect (hwnd, &rect) ;

		break ;
	//鼠标按键测试直接给复选框发消息
	case WM_LBUTTONDOWN:
		
		
		
		//第三个参数为true时标明选中状态,为fasle时标明没有选中,第四个参数不用
		SendMessage (hwndButton[5], BM_SETCHECK, 1, 0) ; 
		Sleep(1000);
		SendMessage (hwndButton[5], BM_SETCHECK, 0, 0) ; 

		return 0;



	case   WM_DESTROY :

		PostQuitMessage (0) ;

		return 0 ;

    }

	return DefWindowProc (hwnd, message, wParam, lParam) ;

}


 

程序中有几点需要注意:

第一,是按钮的类型,“单选框”,“复选框”,“分组框”(与之对应的是“自动***”),它们点击并没有效果,但是可以通过发消息来改变它们的显示效果,程序中通过鼠标左键点击发送。

第二,由于每个控件都是窗口,所以在创建它们时,使用的是CreateWindow函数,返回的是HWND型句柄。

第三,只有BS_OWNERDRAW会导致WM_DRAWITEM消息,这个程序中并没有绘制自己按钮,所以最后一个控件那里只有一层灰色。但是点击那里会显示WM_DRAWITEM消息。

第四,WM_COMMAND消息的wParam和lParam的值含义如下:

 

LOWORD (wParam)

HIWORD (wParam)

lParam

子窗口ID

通知码

子窗口句柄

其中通知码:

 

按钮通知码标识符

BN_CLICKED

0

BN_PAINT

1

BN_HILITE or BN_PUSHED

2

BN_UNHILITE or BN_UNPUSHED

3

BN_DISABLE

4

BN_DOUBLECLICKED or BN_DBLCLK

5

BN_SETFOCUS

6

BN_KILLFOCUS

7

一般都能看到通知码0.但是从1到4的通知码是用于一种叫做BS_USERBUTTON的已不再使用的按钮;通知码6到7只有当按钮样式包括标识BS_NOTIFY才发送;通知码5只对BS_RADIOBUTTON、BS_AUTORADIOBUTTON和BS_OWNERDRAW按钮发送,或者当按钮样式中包括BS_NOTIFY时,也为其它按钮发送。

第五,可以通过 SetWindowText 来改变按钮(或者其他任何窗口)内的文字;如果在建立子视窗时,您没有将 WS_VISIBLE  包含在视窗类别中,可以通过ShowWindow (hwndChild, SW_SHOWNORMAL) ;显示窗口;或者是你包含了 WS_VISIBLE,通过ShowWindow (hwndChild, SW_HIDE) ;将它隐藏起来;或者设置子视窗被启用或者不被启用:EnableWindow (hwndChild, FALSE) ;

你可能感兴趣的:(windows,command,null,callback,button,RadioButton)