非模态对话框
书籍:《Visual C++ 2017从入门到精通》的2.3.8 Win32控件编程
环境:visual studio 2022
内容:【例2.39】非模态对话框
说明:以下内容大部分来自腾讯元宝。
手动创建文件子菜单
1.点击资源视图,找到项目对应的Menu目录,点击IDC_TEST230打开菜单,点击“请在此处键入”后,输入“非模态对话框”,创建一个子菜单,成功后,可以右击该子菜单->属性,然后可以修改子菜单名字及ID.(编辑好后必须要保存,否则程序中出现会找不到对应的ID等异常。)
手动创建对话框
同样在资源视图,找到项目对应的Dialog目录,右击->插入,插入一个新的对话框。
在父窗口创建对话框
1. IDM_MODLESS是点击非模态对话框菜单后产生的消息,点击该菜单后,创建对话框绑定自定义的对话框回调函数DialogProc(),然后显示。
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// 分析菜单选择:
switch (wmId)
{
//处理菜单项 IDM_MODLESS 的点击事件,实现非模态对话框的动态创建与销毁
case IDM_MODLESS:
/*销毁已存在的非模态对话框
功能:确保每次点击菜单时,先关闭已打开的非模态对话框,避免多个实例重叠。
技术要点:
非模态对话框必须通过 DestroyWindow 关闭(模态对话框使用 EndDialog)。
销毁后需将句柄设为 NULL(代码中未显式体现,需补充)以避免悬挂指针。*/
if (hDlgModeless)
{
DestroyWindow(hDlgModeless);
hDlgModeless = NULL;
}
/*创建新的非模态对话框
参数解析:
hInst:应用程序实例句柄,用于加载对话框资源。
MAKEINTRESOURCE(IDD_DIALOG1):将对话框资源 ID 转换为系统可识别的格式。
hWnd:父窗口句柄,非模态对话框需指定父窗口以支持 Z 顺序和消息路由。
DialogProc:对话框过程函数,处理 WM_INITDIALOG、WM_COMMAND 等消息。
返回值检查:若创建失败(如资源未加载),则直接退出菜单命令处理流程。*/
hDlgModeless = CreateDialog(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, DialogProc);
if (!hDlgModeless)
{
break;
}
/*显示与更新对话框
** ShowWindow** :将对话框显示在屏幕上,SW_SHOW 表示正常显示。
** UpdateWindow** :强制立即发送 WM_PAINT 消息,确保对话框内容立即更新(避免闪烁)。*/
ShowWindow(hDlgModeless, SW_SHOW);
UpdateWindow(hDlgModeless);
break;
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
对话框回调函数DialogProc
DialogProc()中处理当对话框被创建的时候的WM_INITDIALOG消息,简单设置了对话框的位置;同时如果用户点击了OK或CANCEL按钮后调用DestroyWindow()来销毁非模态对话框。
//DialogProc 是Windows对话框回调函数,用于处理对话框消息。
//参数:
//hWnd:对话框窗口句柄。
//uMsg:当前处理的消息类型(如WM_INITDIALOG、WM_COMMAND等)。
//wParam和lParam:携带消息特定参数(如控件ID、按键代码等)。
INT_PTR CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
/*功能:对话框初始化时触发,将对话框窗口移动到屏幕坐标(200, 200)。
关键点:
SetWindowPos的SWP_NOSIZE标志表示不改变窗口尺寸。
返回TRUE表示已处理初始化消息,但需注意:若需自定义控件焦点,应返回FALSE并手动调用SetFocus。*/
case WM_INITDIALOG:
SetWindowPos(hWnd, NULL, 200, 200, 0, 0, SWP_NOSIZE);
return TRUE;
case WM_COMMAND:
/*功能:处理用户交互(如点击OK或取消按钮)。
关键点:
LOWORD(wParam)提取控件ID,判断是否为退出按钮。
DestroyWindow用于关闭非模态对话框(hDlgModeless需提前保存对话框句柄)。
返回TRUE表示消息已处理,对话框管理器不再转发该消息。*/
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
DestroyWindow(hDlgModeless);
hDlgModeless = NULL;
}
return TRUE;
/*功能:对话框销毁时触发,清理资源。
关键点:
将hDlgModeless设为NULL,避免悬挂指针。
返回TRUE表示消息已处理。*/
case WM_DESTROY:
hDlgModeless = NULL;
return TRUE;
}
//功能:对于未显式处理的消息(如WM_CLOSE、WM_PAINT等),返回FALSE由对话框管理器(DefWindowProc)处理。
return FALSE;
}
主循环
在主循环中,通过hDlgModeless和IsDialogMessage()筛选优先处理对话框的消息。
// 主消息循环:
while (GetMessage(&msg, nullptr, 0, 0))
{
/*对话框消息过滤
** hDlgModeless** :非模态对话框的句柄,需确保其有效性。
** IsDialogMessage** :
仅处理属于指定对话框的消息(如WM_KEYDOWN转换为控件选择)。
若消息不属于对话框(如WM_CLOSE),返回FALSE,进入后续处理流程。
逻辑意义:优先由对话框自身处理消息,避免父窗口拦截对话框专用消息。*/
if (hDlgModeless == 0 || !IsDialogMessage(hDlgModeless, &msg))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
相关内容
详细介绍MAKEINTRESOURCE-CSDN博客https://blog.csdn.net/qq_20725221/article/details/146275158?sharetype=blogdetail&sharerId=146275158&sharerefer=PC&sharesource=qq_20725221&spm=1011.2480.3001.8118