7.2 使用对话框和控件与用户交互

本文介绍了如何使用对话框作为主界面来编写Windows程序,强调了子窗口控件在对话框中的应用。通过示例展示了如何处理用户交互,如切换图片、添加文本到列表框、设置窗口最前以及改变控件颜色。同时,讨论了WM_COMMAND和WM_CTLCOLOR系列消息在处理用户输入和控件样式时的作用。
摘要由CSDN通过智能技术生成

7.2.1 以对话框为主界面的应用程序

仔细观察上一节使用子窗口的例子就会发现,用户无法按TAB键从一个子窗口控件跳到另一个子窗口控件,要想转移只有用鼠标一下一下地点击。这对用户来说是不友好的。另一件事是如果把主窗口的背景色从白色改成灰色,为了使子窗口控件相应地改变,编程者还必须子类化父窗口中的所有子窗口控件。

造成上述诸多不便的原因是子窗口控件本来是为对话框而设计的。比如按钮控件的默认背景色是灰色的,而对话框的背景色也是灰色的,这样它们就相互协调了,而无须加入其他处理。

下面的例子说明了如何以对话框为主界面编写与用户交互的Windows程序。例子的运行效果如图7.4所示。
在这里插入图片描述
图片中的两个单选按钮用于切换图片1、2,下面的复选按钮用于隐藏和显示图片;在文本框中输入文字,单击添加按钮,这些文字就会被添加到列表框中;如果选中了“总在最前”复选框,则窗口就会一直处于最上层;整个对话框的背景色是天蓝色,笔者声明的几个字是蓝色。图中的箭头指明了子窗口的ID号。

下面是程序的源代码,可以在07ControlsDemo工程下找到。

// Controls.cpp文件
#include <windows.h>
#include "resource.h"

BOOL __stdcall DlgProc(HWND, UINT, WPARAM, LPARAM);

HBITMAP g_hBitmap1;	// 第一个图片的句柄
HBITMAP g_hBitmap2;	// 第二个图片的句柄
HICON	g_hIcon;	// 对话框图标句柄
HBRUSH	g_hBgBrush;	// 背景刷子

int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
	// 从资源中加载BMP文件和图标,这些工作也可以在WM_INITDIALOG消息中进行
	g_hBitmap1 = ::LoadBitmap(hInstance, (LPCTSTR)IDB_BITMAP1);
	g_hBitmap2 = ::LoadBitmap(hInstance, (LPCTSTR)IDB_BITMAP2);
	g_hIcon = ::LoadIcon(hInstance, (LPCTSTR)IDI_MAIN);
	// 创建背景刷子
	g_hBgBrush = ::CreateSolidBrush(RGB(0xa6, 0xca, 0xf0));

	int nResult = ::DialogBoxParam(
		hInstance,		// 实例句柄
		(LPCTSTR)IDD_MAIN,	// 对话框资源ID号
		NULL,			// 父窗口句柄
		DlgProc,		// 消息处理函数
		NULL); 			// 对话框初始化的值,在WM_INITDIALOG消息的lParam参数中取出

	::DeleteObject(g_hBgBrush);

	return 0;
}

BOOL __stdcall DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch(message)
	{	
	case WM_INITDIALOG:
		{
			// 设置标题栏图标
			::SendMessage(hDlg, WM_SETICON, ICON_BIG, (long)g_hIcon);

			// 初始化显示图片的静态框架

			HWND hWndBmp = ::GetDlgItem(hDlg, IDC_BMP);
			// 设置SS_BITMAP风格
			LONG nStyle = ::GetWindowLong(hWndBmp, GWL_STYLE);
			::SetWindowLong(hWndBmp, GWL_STYLE, nStyle | SS_BITMAP);
			// 设置图片
			::SendDlgItemMessage(hDlg, IDC_BMP, STM_SETIMAGE, IMAGE_BITMAP, (long)g_hBitmap1);

			// 初始化复选框
			::CheckDlgButton(hDlg, IDC_BMP1, BST_CHECKED);
		}
		break;

	case WM_COMMAND:
		switch(LOWORD(wParam))
		{
		case IDOK:	// 向列表框中添加文本
			{
				HWND hWndEdit = ::GetDlgItem(hDlg, IDC_INPUT);

				// 取得文本框中的文本
				char szText[256];
				int nLen = ::GetWindowText(hWndEdit, szText, 256);
				if(nLen > 0)
				{
					// 向列表框控件中添加文本
					::SendDlgItemMessage(hDlg, IDC_LIST, LB_ADDSTRING, NULL, (long)szText);
					// 清空文本框中的文本
					::SetWindowText(hWndEdit, "");
				}
			
			}
			break;

		case IDCANCEL:		// 退出程序
			::EndDialog (hDlg, IDCANCEL);
			break;

		case IDC_TOPMOST:	// 设置对话框的Z轴位置 
			{
				HWND hWndCheck = ::GetDlgItem(hDlg, IDC_TOPMOST);
				int nRet = ::SendMessage(hWndCheck, BM_GETCHECK, 0, 0);
				if(nRet == BST_CHECKED)
				{
					::SetWindowPos(hDlg, HWND_TOPMOST, 0, 0, 0, 0, 
						SWP_NOMOVE|SWP_NOSIZE|SWP_NOREDRAW);
				}
				else
				{
					::SetWindowPos(hDlg, HWND_NOTOPMOST, 0, 0, 0, 0, 
						SWP_NOMOVE|SWP_NOSIZE|SWP_NOREDRAW);
				}
			}
			break;

		case IDC_BMP1:		// 更换到第一个图片
			{
				int nRet = ::IsDlgButtonChecked(hDlg, IDC_BMP1);
				if(nRet == BST_CHECKED)
				{
					::SendDlgItemMessage(hDlg, IDC_BMP, 
						STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)g_hBitmap1);
				}
			
			}
			break;

		case IDC_BMP2:		// 更换到第二个图片
			{
				int nRet = ::IsDlgButtonChecked(hDlg, IDC_BMP2);
				if(nRet == BST_CHECKED)
				{
					::SendDlgItemMessage(hDlg, IDC_BMP, 
						STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)g_hBitmap2);
				}
			}
			break;

		case IDC_HIDE:		// 更换图片的显示状态
			{
				HWND hWndBmp = ::GetDlgItem(hDlg, IDC_BMP);
				HWND hWndCheck = ::GetDlgItem(hDlg, IDC_HIDE);
				int nRet = ::SendMessage(hWndCheck, BM_GETCHECK, 0, 0);
				if(nRet == BST_CHECKED)
					::ShowWindow(hWndBmp, SW_HIDE);
				else
					::ShowWindow(hWndBmp, SW_SHOW);
			}
			break;
		}
		break;

	case WM_CTLCOLORSTATIC:	// 设置静态文本框的背景色
	case WM_CTLCOLORDLG:	// 设置对话框的背景色
		{
			HDC hdc = (HDC)wParam;

			// 为静态文本框设置文本背景色
			::SetBkColor(hdc, RGB(0xa6, 0xca, 0xf0));

			if((HWND)lParam == ::GetDlgItem(hDlg, IDC_AUTHOR))
			{
				::SetTextColor(hdc, RGB(0, 0, 0xff));
			}
			
			return (int)g_hBgBrush;
		}
	}

	return 0;
}

在这里插入图片描述
对话框资源默认的字体用于显示汉字并不合适,一般在添加对话框之后,要将字体设置为宋体。方法是这样的,双击对话框资源,弹出属性对话框,单击对话框中“Font…”按钮,弹出选择字体对话框,如图7.5所示,在Font窗口下键入“宋体”,Size窗口下键入“小五”。
在这里插入图片描述
程序的资源文件Controls.rc(文件名是任意的)中定义了两个位图资源,一个图标资源,它们的ID号分别是IDB_BITMAP1、IDB_BITMAP2、IDI_MAIN。可以像添加.cpp文件一样将这些.bmp和.ico文件添加到工程中。

设置标题栏的图标,只需简单的向目标窗口发送一个WM_SETICON消息即可,消息的wParam参数指定图标的类型,lParam参数指定图标句柄。如下代码所示。

::SendMessage(hDlg, WM_SETICON, ICON_BIG, (long)g_hIcon); 

要设置控件的属性,可以在对话框编译器中双击感兴趣的控件(或者右击它,在快捷菜单中选择“Properties”命令)。如果想在程序运行过程中改变窗口的风格可以使用GetWindowLong和SetWindowLong函数。例如下面两句代码为目标窗口添加了SS_BITMAP风格。

LONG nStyle = ::GetWindowLong(hWndBmp, GWL_STYLE); 
::SetWindowLong(hWndBmp, GWL_STYLE, nStyle | SS_BITMAP); 

使用子窗口时,经常需要在窗口ID号和窗口句柄之间转化,也经常需要向子窗口发送消息,下面几个API就是为这个目的而设计的:

HWND GetDlgItem(HWND hDlg, int nIDDlgItem); // 取得指定对话框中一个控件的句柄 
int GetDlgCtrlID( HWND hwndCtl); // 取得指定控件的ID号 
LRESULT SendDlgItemMessage( HWND hDlg, // 向指定的控件发送一个消息  
int nIDDlgItem, UINT Msg, WPARAM wParam, LPARAM lParam); 

7.2.2 常用子窗口控件

1.使用单选钮和复选框
单选钮和复选框控件都是基于BUTTON类的,只不过它们的窗口风格分别是BS_RADIOBUTTON 和BS_CHECKBOX。它们是特殊的“按钮”,所有和它们有关的函数都带有“Button”一词。比如,查看单选钮或复选钮是否被选中可以用下面这个函数:

UINT IsDlgButtonChecked(hDlg, nIDButton); 

函数的返回值可能是BST_CHECKED(选中状态)、BST_INDETERMINATE(复选框的灰化状态)或BST_UNCHECKED(未选中状态)。也可以用向子窗口控件发送BM_ GETCHECKED消息的方法来检测。

如果想设置单选钮或复选框的状态,可以使用CheckDlgButton函数:

BOOL CheckDlgButton(hDlg, nIDButton, uCheck );

参数uCheck用BST_CHECKED、BST_INDETERMINATE、BST_UNCHECKED来表示需要设置的状态,含义同上。向控件发送BM_ SETCHECKED消息也可以取得同样的效果,这时消息的wParam参数中放置需要设置的状态。

2.使用静态控件
静态控件是基于STATIC类的子窗口控件。之所以称为“静态”,是因为它们不向主窗口发送WM_COMMAND消息。

除了显示文本外,静态控件还可以用于图形显示。当图形是图标时,它应具有SS_ICON风格,如果想使用位图,它应具有SS_BITMAP风格。在程序中可以通过向控件发送STM_SETIMAGE消息来设置新的图片,消息的wParam参数指定图片的格式,其值可以是IMAGE_BITMAP、IMAGE_CURSOR或IMAGE_ICON,lParam参数指定图片的句柄。例子程序就是这样为静态控件设置图片的。

::SendDlgItemMessage(hDlg, IDC_BMP, STM_SETIMAGE, IMAGE_BITMAP, (long)g_hBitmap1); 

3.使用列表框和组合框

列表框提供一个可供用户选择的列类,用户可以一次选择一个项目,也可以同时选中多个项目。组合框由一个可供选择的列表和一个可供输入的编辑框类结合而成。组合框让用户既可以自己输入文本也可以选择列表中的某一项当作输入。

应用程序发送LB_ADDSTRING消息以向列表框中添加字符串。如果列表框不包含LBS_SORT风格,字符串将被添加到列表的末尾;如果包含,字符串将被插入到列表框,列表会重新排序。消息的lParam参数指明字符串的首地址。

应用程序发送LB_INSERTSTRING消息插入一个字符串到列表框。与LB_ADDSTRING消息不同,LB_INSERTSTRING消息不会促使具有LBS_SORT风格的列表框重新排序。消息的wParam参数指定插入的位置,它是一个从0开始的索引。lParam参数指明要插入的字符串。

要删除一个字符串,可以向列表框发送LB_DELETESTRING消息,消息的wParam参数指明要删除项的索引。

另外,应用程序还可以向列表框发送LB_RESETCONTENT消息以删除所有的项,发送LB_GETCOUNT消息取得列表中项的总数,发送LB_GETCURSEL消息取得用户当前选择项的索引等。

7.2.3 对话框与控件的颜色

Windows在画对话框之前会向对话框函数发送WM_CTLCOLORDLG消息,消息的wParam参数包含了对话框客户区的设备环境句柄,lParam参数是这个对话框的窗口句柄。通过响应这个消息,对话框可以使用得到的设备环境句柄设置文本和背景颜色。

如果应用程序处理这个消息,它必须返回一个画刷句柄。系统使用这个刷子重画对话框的背景,如下程序片段所示。

case WM_CTLCOLORSTATIC: // 设置静态文本框的背景色 
case WM_CTLCOLORDLG: // 设置对话框的背景色 
{ 
    HDC hdc = (HDC)wParam;  
    ::SetBkColor(hdc, RGB(0xa6, 0xca, 0xf0)); 
    if((HWND)lParam == ::GetDlgItem(hDlg, IDC_AUTHOR))  
    { 
        ::SetTextColor(hdc, RGB(0, 0, 0xff)); 
    }  
    return (int)g_hBgBrush; 
} 

与此类似,子窗口控件在绘制自己之前也向对话框函数发送通知消息,其参数的含义是相同的。比如,静态控件发送WM_CTLCOLORSTATIC消息,wParam参数是设备环境句柄,lParam参数是窗口句柄。这使得编程者能够用同样的代码处理这些消息。

在绘制自己时,文本编辑控件发送WM_CTLCOLOREDIT消息,按钮控件发送WM_CTLCOLORBTN消息,列表框控件发送WM_CTLCOLORLISTBOX消息等,可以响应它们分别设置子窗口控件的文本和背景颜色。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阳光开朗男孩

你的鼓励是我最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值