《Windows程序设计》读书笔十一 对话框

第十一章  对话框


基于模板的对话框,包含了弹出窗口,和子窗口控件,而且有一个窗口过程来处理对话框消息。 包括键盘和鼠标的输入。

称为 “对话框管理器”  和标准的Windows窗口消息处理略有不同。稍后能看到具体区别


许多消息不仅被对话框窗口过程处理,还会传递给你自己的程序中的某些函数。  称为对话框过程

对话框过程一般处理初始化自创控件以及子窗口传来的消息。不处理WM_PAINT 也不直接处理键盘和鼠标的输入


子窗口控件由windows对话框管理器来负责。对话框管理器来负责处理在多个控件中转义输入焦点的相关逻辑


11.1  模态对话框

用户不能在该对话框和该程序的其他对话框之间切换。但是可以切换到其他的程序。有些系统模态不允许切换程序。必须结束系统模态才可以进行其他操作。

11.1.1 创建一个about对话框


About.cpp

#include <windows.h>  
#include "resource.h"   

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.   
BOOL	CALLBACK AboutDlgProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	PSTR szCmdLine, int iCmdShow)
{
	static      TCHAR szAppName[] = TEXT("About1");    
	HACCEL      hAccel;
	HWND        hwnd;
	MSG         msg;
	WNDCLASS    wndClass;       //The window Class        

	wndClass.style = CS_HREDRAW | CS_VREDRAW;
	wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.        
	wndClass.cbClsExtra = 0;
	wndClass.cbWndExtra = 0;
	wndClass.hInstance = hInstance;
	wndClass.hIcon = LoadIcon(hInstance, szAppName);// LoadIcon(NULL, IDI_APPLICATION);  
	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);    
	wndClass.lpszMenuName = szAppName;
	wndClass.lpszClassName = szAppName;

	//Register the Window Class to the Windows System.         
	if (!RegisterClass(&wndClass))
	{
		MessageBox(NULL, TEXT("This program require Windows NT!"),
			szAppName, MB_ICONERROR);
		return 0;
	}

	//This function will generate an WM_CREATE message.        
	hwnd = CreateWindow(szAppName,      //Window class name        
		TEXT("About Box Demo Program"),      //Window caption        
		WS_OVERLAPPEDWINDOW,            //Window Style        
		CW_USEDEFAULT,                  //initial x position        
		CW_USEDEFAULT,                  //initial y position        
		CW_USEDEFAULT,                  //initial x size        
		CW_USEDEFAULT,                  //initial y size        
		NULL,                           //parent window handle        
		NULL,                           //window menu handle        
		hInstance,                      //program instance handle        
		NULL);                          //creation parameters        

	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd); //This function will generate a WM_PAINT message.        

	/* The message loop for this program.
	if received the WM_QUIT message, the function will return 0.*/
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);	
	}
	return msg.wParam;

}

//define the Window Procedure WndProc        
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HINSTANCE hInstance;

	switch (message) //get the message        
	{
	case WM_CREATE:
		hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
		return 0;

	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDM_APP_ABOUT:
			DialogBox(hInstance, TEXT("AboutBox"), hwnd, AboutDlgProc);
			break;
		}

		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return  DefWindowProc(hwnd, message, wParam, lParam);
}

BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_INITDIALOG:
		return TRUE;

	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDOK:
		case IDCANCEL:
			EndDialog(hDlg, 0);
			return TRUE;
		}
		break;
	}

	return FALSE;
}

About1.rc

// Microsoft Visual C++ generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"

/
#undef APSTUDIO_READONLY_SYMBOLS

/
// English (United States) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)

#ifdef APSTUDIO_INVOKED
/
//
// TEXTINCLUDE
//

1 TEXTINCLUDE 
BEGIN
    "resource.h\0"
END

2 TEXTINCLUDE 
BEGIN
    "#include ""afxres.h""\r\n"
    "\0"
END

3 TEXTINCLUDE 
BEGIN
    "\r\n"
    "\0"
END

#endif    // APSTUDIO_INVOKED


/
//
// Dialog
//

ABOUTBOX DIALOGEX 32, 32, 180, 102
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP
FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN
    DEFPUSHBUTTON   "OK",IDOK,66,81,50,14
    ICON            "ABOUT1",IDC_STATIC,7,7,20,20
    CTEXT           "About1",IDC_STATIC,40,12,100,8
    CTEXT           "About Box Demo Program",IDC_STATIC,7,40,166,8
    CTEXT           "(c) Charles Petzold, 1998",IDC_STATIC,7,52,166,8
END


/
//
// Menu
//

ABOUT1 MENU
BEGIN
    POPUP "&Help"
    BEGIN
        MENUITEM "&About About1...",            IDM_APP_ABOUT
    END
END


/
//
// Icon
//

// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
ABOUT1                  ICON                    "About1.ico"


/
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
    "ABOUTBOX", DIALOG
    BEGIN
        LEFTMARGIN, 7
        RIGHTMARGIN, 173
        TOPMARGIN, 7
        BOTTOMMARGIN, 95
    END
END
#endif    // APSTUDIO_INVOKED


/
//
// AFX_DIALOG_LAYOUT
//

ABOUTBOX AFX_DIALOG_LAYOUT
BEGIN
    0
END

#endif    // English (United States) resources
/



#ifndef APSTUDIO_INVOKED
/
//
// Generated from the TEXTINCLUDE 3 resource.
//


/
#endif    // not APSTUDIO_INVOKED

resource.h

//{
  {NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by About1.rc
//
#define IDM_APP_ABOUT                   40001

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        104
#define _APS_NEXT_COMMAND_VALUE         40004
#define _APS_NEXT_CONTROL_VALUE         1003
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif


11.1.2 对话框及其模板


DEFPUSHBUTTON, ICON 和CTEXT只被用于对话框。他们是一些特殊类和窗口样式的缩写。  CTEXT指定窗口控件的类型是静态的,同时其样式是

WS_CHILD | SS_CENTER | WS_VISIBLE | WS_GROUP

文本设定等价于Caption参数

当子窗口像父窗口发送WM_COMMAND时,id字段是子窗口用来表示自己的标识符。 子窗口控件的父窗口是对话框本身。它会把这些消息发送给某个windows的窗口过程。

这里的ID和CreateWindow中 (HMENU)id  参数相同。 由于文本和图标并不需要向父窗口发送消息。所以ID被设定为ID_STATIC 按钮的ID为IDOK   在winuser.h中定义为1

接下来设定子窗口控件的位置和大小。   单位是 字符评均宽度的1/4 和  平均高度的1/8


11.1.3 对话框过程

发送给对话框的消息是用户程序中的对话框过程来处理的。和窗口过程很像,但是其实是不一样的。  对话框的窗口过程属于windows。 而对话框过程是独立的。

对话框的窗口过程会调用这个对话框的过程来处理许多消息。

对话框过程

BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_INITDIALOG:
		return TRUE;

	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDOK:
		case IDCANCEL:
			EndDialog(hDlg, 0);
			return TRUE;
		}
		break;
	}

	return FALSE;
}
对话框过程  和 对话框的窗口过程的区别

1)窗口过程返回值是  LRESULT  而对话框过程的返回值是BOOL

2)窗口过程不处理一条消息时,会调用DefWindowProc。  对话框过程处理一条消息会返回TRUE,不处理则返回FALSE

3)  对话框过程不需要处理WM_PAINT和WM_DESTROY消息。他也不会收到WM_CREATE消息。 然后他会在一条处理WM_INITDIALOG消息时进行初始化,这是对话框过程接收到的第一条消息。当其返回TRUE时,windows会把输入焦点放在第对话框第一个含有WS_TABSTOP样式的窗口子空间。本例中是按钮。

另外在WM_INITDIALOG也可以调用SetFocus来设置焦点,并返回FALSE

除此之外,对话框过程只处理WM_COMMAND,当鼠标单击按钮或者当焦点在按钮控件时按下空格键,按钮控件会像父窗口发送WM_COMMAND消息。wParam低位时控件ID

其他任何消息,对话框过程会返回FALSE来通知对话框的窗口过程该消息未处理。

模态对话框的消息并不通过程序的消息循环。


11.1.4 激活对话框

Dialog(hInstance, TEXT("AboutBox"), hwnd, AboutDlgProc);

实例句柄, 对话框名称在资源该脚本中定义, 父窗口句柄   和对话框过程的地址。

也可以使用MAKEINTRESOURCE宏来将其转换为字符。


当回车或空格被按下,windows会向对话框发送WM_COMMAND消息。 wParam的低位时默认按钮ID。 也可以按ESC来结束对话框。

直到对话框结束以后,用来显示对话框的DialogBox才将控制返回给WndProc。 DialogBox的返回值等于EndDialog函数的第二个参数。并将控制权返回给Windows.


对话框在显示使,WndProc依旧可以处理消息。比如SendMessage(GetParent(Dlg), ...);


11.1.5 主题变换

对话框资源脚本

对话框常用样式

STYLE WS_POPUP | DS_MODALFRAME

带标题栏 WS_CAPTION


CAPTION "Dialog Box Caption"  标题栏文本

或者当对话框过程处理WM_INITDIALOG消息时,你可以使用

SetWindowText(hDlg, TEXT("Dialog Box Caption"));


使用WS_CAPTION样式 还运行使用WS_SYSMENU 增加系统菜单框。这一样式允许用户通过系统菜单来选择Move或Close


WS_THICKFRAME   (Resizing) 允许用户改变对话框的大小。甚至还可以给对话框添加菜单

MENU 菜单名


FONT 语句用来设置对话框文本为系统字体以外的字体。 早起VS创建对话框默认的字体是 8pt的 MS Scans Serif。  现在VS2015使用的是  8pt的 MS Shell Dlg 字体


可以指定某个窗口过程来处理对话框消息。

CLASS “类名”


调用DialogBox函数, windows会从对话框资源模板中获取信息来CreateWindow ,windows从DialogBox函数的参数获取hInstance 和 父窗口hwnd

windows所需的唯一其他信息是一个窗口类,假设对话框模板没有指定。  window设为对话框注册一个特殊的窗口类。窗口类用于对话框过程的访问地址。

因此弹出式窗口可以向程序传递其收到的消息。 也可以自己使用CreateWindow并注册窗口类来创建自己的对话框,DialogBox函数只是一种简便的方法。


也可以动态创建对话框,不需要写资源脚本。DialogBoxIndirect函数   使用数据结构来定义对话框模板。

常用控件类型的相应窗口类和窗口样式



除了表中的样式,每个控件默认还有以下样式

WS_CHILD | WS_VISIBLE

  EDITTEXT, SCROLLBAR, LISTBOX 和COMBOBOX以下格式

控件类型 id, xPos, yPos, xWidth, yHeight, iStyle

除此之外所有控件的定义都有以下格式

控件类型 "文本" , id, xpos, ypos, xwidth, yHeight, iStyle

对话框模板中的单位是平均字符宽度的1/4 和  高度的 1/8 。


例如复选框

CHECKBOX "TEXT", id, xPos, yPos, xWidth, yHeight, BS_LEFTTEXT      checkbox上的说明文本左对齐


EDITTEXT id, xPos, yPos, xWidth, yHeight, NOT WS_BORDER        不带边框的EDITTEXT


资源编辑器还承认这样的一般化语句

CONTROL  "文本" , id, "类", IStyle, xPos, yPos, xWidth, yHeight

创建任何类型的子窗口控件

比如 

PUSHBUTTON "OK", IDOK, 10, 20, 32, 14

可以使用下面语句

CONTROL "OK" , IDOK, "button", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP,

        10, 20, 32, 14

可使用VS中自定义控件选项来生成以上语句


在模板资源中,则无需WS_CHILD | WS_VISIBLE 样式

上面的CONTROL语句转换成如下调用

hCtrl1 = CreateWindow( TEXT("button"), TEXT("OK"),

                  WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,

                  10 * cxChar / 4,     20 * cyChar / 8,

                  32 * cxChar / 4,     14 * cyChar / 8,

                  hDlg, IDOK, hInstance, NULL);


11.1.6 更复杂的对话框

about2.cpp

#include <windows.h>  
#include "resource.h"   

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.   
BOOL	CALLBACK AboutDlgProc(HWND, UINT, WPARAM, LPARAM);

int iCurrentColor = IDC_BLACK,
iCurrentFigure = IDC_RECT;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	PSTR szCmdLine, int iCmdShow)
{
	static      TCHAR szAppName[] = TEXT("About2");
	HWND        hwnd;
	MSG         msg;
	WNDCLASS    wndClass;       //The window Class        

	wndClass.style = CS_HREDRAW | CS_VREDRAW;
	wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.        
	wndClass.cbClsExtra = 0;
	wndClass.cbWndExtra = 0;
	wndClass.hInstance = hInstance;
	wndClass.hIcon = LoadIcon(hInstance, szAppName);// LoadIcon(NULL, IDI_APPLICATION);  
	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndClass.lpszMenuName = szAppName;
	wndClass.lpszClassName = szAppName;

	//Register the Window Class to the Windows System.         
	if (!RegisterClass(&wndClass))
	{
		MessageBox(NULL, TEXT("This program require Windows NT!"),
			szAppName, MB_ICONERROR);
		return 0;
	}

	//This function will generate an WM_CREATE message.        
	hwnd = CreateWindow(szAppName,      //Window class name        
		TEXT("About Box Demo Program"),      //Window caption        
		WS_OVERLAPPEDWINDOW,            //Window Style        
		CW_USEDEFAULT,                  //initial x position        
		CW_USEDEFAULT,                  //initial y position        
		CW_USEDEFAULT,                  //initial x size        
		CW_USEDEFAULT,                  //initial y size        
		NULL,                           //parent window handle        
		NULL,                           //window menu handle        
		hInstance,                      //program instance handle        
		NULL);                          //creation parameters        

	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd); //This function will generate a WM_PAINT message.        

						/* The message loop for this program.
						if received the WM_QUIT message, the function will return 0.*/
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;

}

void PaintWindow(HWND hwnd, int iColor, int iFigure)
{
	static COLORREF crColor[8] = { RGB(0, 0,   0), RGB(0,   0, 255),
		RGB(0, 255, 0), RGB(0, 255, 255),
		RGB(255, 0,   0), RGB(255,   0, 255),
		RGB(255, 255, 0), RGB(255, 255, 255) };
	HBRUSH	hBrush;
	HDC		hdc;
	RECT	rect;

	hdc = GetDC(hwnd);
	GetClientRect(hwnd, &rect);
	hBrush = CreateSolidBrush(crColor[iColor - IDC_BLACK]);
	hBrush = (HBRUSH)SelectObject(hdc, hBrush);

	if (iFigure == IDC_RECT)
		Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);
	else
		Ellipse(hdc, rect.left, rect.top, rect.right, rect.bottom);

	DeleteObject(SelectObject(hdc, hBrush));
	ReleaseDC(hwnd, hdc);
}


void PaintTheBlock(HWND hCtrl, int iColor, int iFigure)
{
	InvalidateRect(hCtrl, NULL, TRUE);
	UpdateWindow(hCtrl);
	PaintWindow(hCtrl, iColor, iFigure);
}

//define the Window Procedure WndProc        
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HINSTANCE hInstance;
	PAINTSTRUCT		 ps;

	switch (message) //get the message        
	{
	case WM_CREATE:
		hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
		return 0;

	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDM_APP_ABOUT:
			if (DialogBox(hInstance, TEXT("AboutBox"), hwnd, AboutDlgProc))
				InvalidateRect(hwnd, NULL, TRUE);
			break;
		}
		break;

	case WM_PAINT:
		BeginPaint(hwnd, &ps);
		EndPaint(hwnd, &ps);

		PaintWindow(hwnd, iCurrentColor, iCurrentFigure);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return  DefWindowProc(hwnd, message, wParam, lParam);
}

BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HWND	hCtrlBlock;
	static int	iColor, iFigure;
	switch (message)
	{
	case WM_INITDIALOG:
		iColor = iCurrentColor;
		iFigure = iCurrentFigure;

		CheckRadioButton(hDlg, IDC_BLACK, IDC_WHITE, iColor);
		CheckRadioButton(hDlg, IDC_RECT, IDC_ELLIPSE, iFigure);

		hCtrlBlock = GetDlgItem(hDlg, IDC_PAINT);

		SetFocus(GetDlgItem(hDlg, iColor));
		return FALSE;

	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDOK:
			iCurrentColor = iColor;
			iCurrentFigure = iFigure;
			EndDialog(hDlg, TRUE);
			return TRUE;

		case IDCANCEL:
			EndDialog(hDlg, FALSE);
			return TRUE;

		case IDC_BLACK:
		case IDC_RED:
		case IDC_GREEN:
		case IDC_YELLOW:
		case IDC_BLUE:
		case IDC_MAGENTA:
		case IDC_CYAN:
		case IDC_WHITE:
			iColor = LOWORD(wParam);
			CheckRadioButton(hDlg, IDC_BLACK, IDC_WHITE, LOWORD(wParam)); //The LOWORD(wParam) is the current ID of the command.
			PaintTheBlock(hCtrlBlock, iColor, iFigure);
			return TRUE;

		case IDC_RECT:
		case IDC_ELLIPSE:
			iFigure = LOWORD(wParam);
			CheckRadioButton(hDlg, IDC_RECT, IDC_ELLIPSE, LOWORD(wParam));
			PaintTheBlock(hCtrlBlock, iColor, i
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值