SDK (非)模态对话框

目录

模态对话框

模态对话框阻塞父窗口的原因

DialogBox

DialogProc

GetModuleHandle

非模态对话框

CreateDialog

总结


模态对话框

创建的步骤:

  1. 编辑对话框资源模板
  2. 创建对话框 [Dialog]
  3. 实现模态对话框过程函数
  4. 模态对话框关闭

对话框过程函数:对话框也属于一个窗口,有自己的过程处理函数。在创建对话框的时候需要绑定过程处理函数。**函数作用:**处理对话框产生的消息。处理返回TRUE,不处理返回FALSE由系统进行内定处理。

模态对话框阻塞父窗口的原因

  • 模态对话框内部自建消息循环。
  • 对话框初始化的时候,显示对话框之前发送【WM_INITDIALOG】进行初始化,调用了EnableWindows 禁用了父窗口你的鼠标和键盘输入
    • 解决:初始化对话框响应时候,在调用一次EnableWindows恢复父窗口的键盘鼠标输入
  • 对话框创建完成后不能如CreateWindow创建的那般缩放窗口大小。

DialogBox

从对话框模板资源创建模式对话框。 在指定的回调函数通过调用 EndDialog 函数终止模式对话框之前,DialogBox 不会返回控件。

void DialogBoxA(
  [in, optional]  hInstance,
  [in]            lpTemplate,
  [in, optional]  hWndParent,
  [in, optional]  lpDialogFunc
);

参数说明:

  • 参数1:包含对话框模板的模块的句柄。 如果此参数为 NULL,则使用当前可执行文件。
  • 参数2:对话框模板。 此参数是指向指定对话框模板名称的以空字符结尾的字符串的指针,或者是指定对话框模板的资源标识符的整数值。 如果参数指定了资源标识符,则其高位字必须为零,其低位字必须包含该标识符。 你可以使用 MAKEINTRESOURCE 宏来创建此值。
  • 参数3:拥有对话框的窗口的句柄。
  • 参数4:指向对话框过程的指针。

返回值:无

代码示例

DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DialogProc);

在WM_CLOSE消息处理中,关闭对话框

if (uMsg == WM_CLOSE) {
    EndDialog(hwndDlg, 0);
	return TRUE;
}

DialogProc

用于用来处理发送到模态或无模型对话框的消息。过程函数,该对话框中的所有消息都通过该过程函数来进行处理。

BOOL CALLBACK DialogProc(
    HWND 	hwndDlg,	//指向该对话框的句柄
    UINT 	uMsg,		//消息ID
    WPARAM  wParam,		//其他消息
    LPARAM 	lParam		//其他消息
    );

GetModuleHandle

检索指定模块的模块句柄。 模块必须已由调用进程加载

HMODULE GetModuleHandleA(
  [in, optional] LPCSTR lpModuleName
);

加载的模块的名称 (.dll 或 .exe 文件) 。 如果省略文件扩展名,则会追加默认库扩展名 .dll。 文件名字符串可以包含尾随点字符 (.) ,以指示模块名称没有扩展名。 字符串不必指定路径。 指定路径时,请务必使用反斜杠 (\) ,而不是使用 /) (正斜杠。 名称 (大小写独立比较,) 当前映射到调用进程的地址空间的模块的名称。

如果此参数为 NULL, 则 GetModuleHandle 返回用于创建调用进程 (.exe 文件) 的文件的句柄。

非模态对话框

创建的步骤:

  1. 编辑对话框资源模板
  2. 创建对话框
  3. 实现对话框过程函数
  4. 显示非模态对话框

非模态对话框不会阻塞父窗口的原因:

  • 没有自建消息循环,和父窗口共用一个消息循环
  • 非模态对话框也有WM_PANIT消息。模态对话框中也有WM_PAINT消息。但是被内部处理了

CreateDialog

从对话框模板资源创建无模式对话框。

void CreateDialogA(
  [in, optional]  hInstance,
  [in]            lpName,
  [in, optional]  hWndParent,
  [in, optional]  lpDialogFunc
);

参数说明:

  • 参数1:包含对话框模板的模块的句柄。 如果此参数为 NULL,则使用当前可执行文件。
  • 参数2:对话框模板。 此参数是指向指定对话框模板名称的以空字符结尾的字符串的指针,或者是指定对话框模板的资源标识符的整数值。 如果参数指定了资源标识符,则其高位字必须为零,其低位字必须包含该标识符。 你可以使用 MAKEINTRESOURCE 宏来创建此值。
  • 参数3:拥有对话框的窗口的句柄。
  • 参数4:指向对话框过程的指针。

返回值:无

CreateDialog 将发送WM_INITDIALOG消息,该消息在显示对话框之前立即发送到对话框过程。 对话框过程通常使用此消息来初始化控件并执行影响对话框外观的任何其他初始化任务。

销毁对话框

DestroyWindow(hwndDlg);

代码如下:

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

HINSTANCE g_hInstance;

INT_PTR CALLBACK DialogProc2(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	if (uMsg == WM_CLOSE) {
		EndDialog(hwndDlg, 0);
		return TRUE;
	}
	return FALSE;
}



//非模态,模态对话框测试
INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	
	switch (uMsg) {
	case WM_COMMAND:
		//OutputDebugString(_T("[51asm] WM_COMMAND\n"));
		if (LOWORD(wParam) == ID_SAVE) {
			TCHAR szBuf[MAXBYTE];
			TCHAR szTitle[MAXWORD];
			LoadString(g_hInstance, IDS_SAVE, szBuf, sizeof(szBuf));
			LoadString(g_hInstance, IDS_Title, szTitle, sizeof(szTitle));
			MessageBox(hwndDlg, szBuf,szTitle, MB_OK);
		}
		else if (LOWORD(wParam) == IDB_LOGIN) {
			//DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG2), NULL, DialogProc);
			DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG2), hwndDlg, DialogProc2);
		}
		break;
	case WM_INITDIALOG:
		OutputDebugString(_T("[51asm] WM_INITDIALOG\n"));
		return TRUE;
	case WM_CLOSE:
		OutputDebugString(_T("[51asm] WM_CLOSE\n"));
		//EndDialog(hwndDlg, 0);// 模态对话框需要这个
		DestroyWindow(hwndDlg);// 非模态对话框调用这个
		return TRUE;
	case WM_DESTROY:
		OutputDebugString(_T("[51asm] WM_DESTROY\n"));
		PostQuitMessage(0);
		return TRUE;
	}
	return FALSE; //交给系统默认处理
}


int WINAPI wWinMain(
	_In_ HINSTANCE hInstance,
	_In_opt_ HINSTANCE hPrevInstance,
	_In_ LPWSTR lpCmdLine,
	_In_ int nShowCmd) 
{

	g_hInstance = hInstance;

	// 创建模态对话框,只能操作当前窗口
	// DialogBox自带有消息循环,里面封装的有消息循环,阻塞
	/*DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DialogProc);*/
	
	// 非模态对话框,也可以操作别的窗口,需要自己写消息处理,类似WinMain
	HWND hDlg = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DialogProc);
	
	// 加载快捷键资源
	HACCEL hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1));

	// 加载菜单资源,模态对话框无法加载快捷键
	HMENU hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU1));
	SetMenu(hDlg, hMenu);

	

	ShowWindow(hDlg, SW_SHOWNORMAL);
	
	BOOL bRet;
	MSG msg;
	// 消息循环是以线程为单位的
	while ((bRet = GetMessage(&msg,NULL,0,0)) != 0) {
		if (bRet == -1) {
			break;
		}
		else {
			if (!TranslateAccelerator(hDlg, hAccel, &msg)) {
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
	}

	return msg.wParam;

}

总结

  1. 模态对话框和非模态对话框根本上的区别在于前者会阻塞父窗口,但是也可以通过EndWindow来设置允许不阻塞。
  2. 模态对话框和非模态对话框的实质就是一个CreateWindow的窗口,它们都有WM_PAINT消息,以及普通窗口的能力,但是没有菜单能力。
  3. 对话框不能如普通窗口那般根据窗口风格来设置更改尺寸导致的重新绘制内容等效果。
  4. 非模态窗口是普通窗口和对话框的结合,既可以使用普通窗口的大消息循环,也可以使用对话框的按钮工具箱等、适用于小游戏的界面开发
  5. 模态窗口适用于提示等对话框,比如:记事本的帮助等提示类信息的显示。
相关推荐
半盏茶香26 分钟前
【C语言】分支和循环详解(下)猜数字游戏
c语言·开发语言·c++·算法·游戏
小堇不是码农32 分钟前
在VScode中配置C_C++环境
c语言·c++·vscode
Jack黄从零学c++35 分钟前
C++ 的异常处理详解
c++·经验分享
捕鲸叉6 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer6 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq6 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
青花瓷8 小时前
C++__XCode工程中Debug版本库向Release版本库的切换
c++·xcode
幺零九零零9 小时前
【C++】socket套接字编程
linux·服务器·网络·c++
捕鲸叉9 小时前
MVC(Model-View-Controller)模式概述
开发语言·c++·设计模式
Dola_Pan10 小时前
C++算法和竞赛:哈希算法、动态规划DP算法、贪心算法、博弈算法
c++·算法·哈希算法