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. 模态窗口适用于提示等对话框,比如:记事本的帮助等提示类信息的显示。
相关推荐
_WndProc4 分钟前
C++ 日志输出
开发语言·c++·算法
薄荷故人_5 分钟前
从零开始的C++之旅——红黑树及其实现
数据结构·c++
m0_748240025 分钟前
Chromium 中chrome.webRequest扩展接口定义c++
网络·c++·chrome
qq_4335545413 分钟前
C++ 面向对象编程:+号运算符重载,左移运算符重载
开发语言·c++
努力学习编程的伍大侠17 分钟前
基础排序算法
数据结构·c++·算法
yuyanjingtao1 小时前
CCF-GESP 等级考试 2023年9月认证C++四级真题解析
c++·青少年编程·gesp·csp-j/s·编程等级考试
闻缺陷则喜何志丹1 小时前
【C++动态规划 图论】3243. 新增道路查询后的最短距离 I|1567
c++·算法·动态规划·力扣·图论·最短路·路径
charlie1145141911 小时前
C++ STL CookBook
开发语言·c++·stl·c++20
小林熬夜学编程2 小时前
【Linux网络编程】第十四弹---构建功能丰富的HTTP服务器:从状态码处理到服务函数扩展
linux·运维·服务器·c语言·网络·c++·http
倔强的石头1062 小时前
【C++指南】类和对象(九):内部类
开发语言·c++