当前位置: 首页 > news >正文

【第七节】windows sdk编程:Windows 中的对话框

目录

引言

一、对话框简介

1.1 对话框的创建

1.2 基本函数

1.3 模态对话框与非模态对话框

1.4 对话框与窗口的区别

二、模态对话框编程方法

2.1 模态对话框编程

2.2 消息框

三、非模态对话框编程方法

四、综合代码案例


引言

        在Windows应用程序开发中,对话框是用户交互的重要组件,能够简化复杂界面的设计和实现。通过资源编辑器,开发者可以快速创建对话框资源,并通过`DialogBox`或`CreateDialog`函数将其集成到应用程序中。模态对话框要求用户先关闭对话框才能操作主窗口,而非模态对话框则允许用户同时与主窗口和对话框交互。无论是简单的消息框还是复杂的自定义对话框,Windows提供了丰富的API和资源管理机制,帮助开发者高效构建用户友好的界面。

一、对话框简介

1.1 对话框的创建

        虽然可以使用 `CreateWindow` 创建 `POPUP` 风格的窗口,但对话框程序通常包含多个控件,逐个创建控件会非常繁琐。因此,微软提供了更为便捷的方式来创建对话框程序。

        通过资源编辑器,我们可以直接创建对话框资源,并通过资源 ID 来标识。在对话框上,可以拖拽各种控件(如 `Button`、`Edit`、`Static` 等),并通过属性调整对话框和控件的风格。随后,调用 `DialogBox` 或 `CreateDialog` 函数,利用资源创建出对话框。

        在资源视图中,右键单击 `.rc` 文件,选择“添加资源”,然后新建一个对话框,即可创建对话框资源。通过“视图 -> 工具箱”可以向对话框上添加控件。

1.2 基本函数

常用的对话框创建函数有两个:

INT_PTR WINAPI DialogBox(
    _In_opt_ HINSTANCE hInstance,
    _In_ LPCTSTR lpTemplate,
    _In_opt_ HWND hWndParent,
    _In_opt_ DLGPROC lpDialogFunc
);

HWND WINAPI CreateDialog(
    _In_opt_ HINSTANCE hInstance,
    _In_ LPCTSTR lpTemplate,
    _In_opt_ HWND hWndParent,
    _In_opt_ DLGPROC lpDialogFunc
);

- `DialogBox`:用于生成模态窗口。
- `CreateDialog`:用于创建非模态窗口。

        两者都会调用 `CreateWindow` 来创建窗口。非模态对话框需要程序员自己实现消息循环,而模态对话框自带消息循环,消息循环在函数内部进行。退出模态对话框需要使用 `EndDialog`。

参数对比:

`DialogBox` 和 `CreateDialog` 的参数相同:
(1)当前程序实例句柄
(2)资源 ID
(3)父实例句柄(通常为空)
(4)回调函数指针(需要用 `DLGPROC` 转换)

        两者的主要区别在于模态与非模态,`CreateDialog` 的消息循环需要程序员自己实现。

1.3 模态对话框与非模态对话框

- 模态对话框:创建后,用户必须关闭对话框,父窗口才能响应用户操作。否则,父窗口无法响应任何用户操作。
- 非模态对话框:创建后,父窗口不需要等待对话框关闭即可响应用户操作,即使对话框未关闭,父窗口仍可响应用户操作。

1.4 对话框与窗口的区别

对话框处理的主要消息:

- `WM_INITDIALOG`:对话框初始化时执行的操作。
- `WM_COMMAND`:响应对话框上控件的操作。
- `WM_NOTIFY`:响应对话框上控件的复杂操作。

二、模态对话框编程方法

2.1 模态对话框编程

(1)定义对话框资源
   在资源中添加一个对话框,并拖拽一些控件。

(2)调用 `DialogBox` 显示对话框
   定义资源后,调用 `DialogBox` 函数显示对话框:

int DialogBox(HINSTANCE hInstance, LPCTSTR lpszDialogName, HWND hwnd, WNDPROC lpDialogFunc);

(3)构造对话框消息处理函数
   对话框消息处理函数的一般形式:

BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
       switch(message) {
           case WM_INITDIALOG: return 1;
           case WM_COMMAND:
               switch(LOWORD(wParam)) {
                   case ...: break;
                   case ...: break;
               }
               break;
           ...
       }
       return 0;
   }


   在消息处理函数中,主要处理以下两类消息:
   - `WM_INITDIALOG`:对话框初始化时执行的操作。
   - `WM_COMMAND`:响应对话框上控件的操作。

(4)关闭对话框函数
   在消息处理函数中调用 `EndDialog` 关闭对话框。

2.2 消息框

        消息框是模态对话框的一种特殊形式。应用程序可以通过调用 `MessageBox` 函数快速生成一些简单但常用的 Windows 消息框。函数原型为:

int MessageBox(HWND hwnd, LPCTSTR lpszText, LPCTSTR lpszCaption, DWORD dwType);

- `hwnd`:拥有该消息的窗口。
- `lpszText`:消息框中显示的字符串。
- `lpszCaption`:作为标题的字符串。
- `dwType`:指定消息框的内容。

常用标识及说明:

用户操作与 `MessageBox` 返回值的对应关系:

三、非模态对话框编程方法

(1)定义对话框资源
   与非模态对话框相同。

(2)创建对话框
   非模态对话框的创建由 `CreateDialog` 函数完成:

HWND CreateDialog(HINSTANCE hInstance, LPCTSTR lpszDialogName, HWND hwndParent, WNDPROC lpDialogFunc);

(3)消息循环部分的处理
   由于非模态对话框不禁止应用程序向其他窗口发送消息,因此在 `WinMain` 函数的消息循环中,必须包含截获发往非模态对话框的消息,并将其发往相应的对话框处理函数处理。消息循环的一般形式为:

 while (GetMessage(&Msg, NULL, 0, 0)) {
       if (!IsDialogMessage(hdlg, &Msg)) {
           TranslateMessage(&Msg);
           DispatchMessage(&Msg);
       }
   }

(4)关闭对话框函数
   在消息处理函数中调用 `DestroyWindow` 关闭对话框:

BOOL DestroyWindow(HWND hwnd);

四、综合代码案例

        以下是一个综合性的C++代码案例,展示了如何在Windows应用程序中使用模态对话框和非模态对话框。代码包括创建对话框、处理对话框消息、使用消息框等功能。

完整代码示例

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

// 函数前向声明
INT_PTR CALLBACK ModalDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK ModelessDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);

// 全局变量
HWND g_hModelessDialog = NULL; // 非模态对话框句柄

// 主对话框过程函数
INT_PTR CALLBACK MainDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        switch (LOWORD(wParam)) {
        case IDC_BUTTON_OPEN_MODAL:
            // 调用模态对话框
            DialogBox((HINSTANCE)GetWindowLongPtr(hDlg, GWLP_HINSTANCE),
                MAKEINTRESOURCE(IDD_MODAL_DIALOG),
                hDlg, ModalDialogProc);
            break;

        case IDC_BUTTON_OPEN_MODELESS:
            // 调用非模态对话框
            if (!g_hModelessDialog) {
                g_hModelessDialog = CreateDialog((HINSTANCE)GetWindowLongPtr(hDlg, GWLP_HINSTANCE),
                    MAKEINTRESOURCE(IDD_MODELESS_DIALOG),
                    hDlg, ModelessDialogProc);
                ShowWindow(g_hModelessDialog, SW_SHOW);
            }
            break;

        case IDC_BUTTON_CLOSE:
            // 关闭主对话框
            EndDialog(hDlg, LOWORD(wParam));
            break;
        }
        break;

    case WM_DESTROY:
        if (g_hModelessDialog) {
            DestroyWindow(g_hModelessDialog); // 关闭非模态对话框
        }
        break;
    }
    return (INT_PTR)FALSE;
}

// 模态对话框过程函数
INT_PTR CALLBACK ModalDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
            // 关闭模态对话框
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

// 非模态对话框过程函数
INT_PTR CALLBACK ModelessDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDCANCEL) {
            // 关闭非模态对话框
            DestroyWindow(hDlg);
            g_hModelessDialog = NULL;
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

// 应用程序入口函数
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    // 显示主对话框
    DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN_DIALOG), NULL, MainDialogProc);
    return 0;
}

资源文件(`.rc`文件)

在资源文件中定义对话框和控件:

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

// 主对话框资源
IDD_MAIN_DIALOG DIALOGEX 0, 0, 200, 100
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION L"主对话框"
FONT 9, "Microsoft YaHei"
BEGIN
    DEFPUSHBUTTON L"打开模态对话框", IDC_BUTTON_OPEN_MODAL, 10, 10, 120, 20
    PUSHBUTTON L"打开非模态对话框", IDC_BUTTON_OPEN_MODELESS, 10, 40, 120, 20
    PUSHBUTTON L"关闭", IDC_BUTTON_CLOSE, 10, 70, 120, 20
END

// 模态对话框资源
IDD_MODAL_DIALOG DIALOGEX 0, 0, 150, 80
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION L"模态对话框"
FONT 9, "Microsoft YaHei"
BEGIN
    PUSHBUTTON L"确定", IDOK, 30, 40, 80, 20
    PUSHBUTTON L"取消", IDCANCEL, 30, 70, 80, 20
END

// 非模态对话框资源
IDD_MODELESS_DIALOG DIALOGEX 0, 0, 150, 80
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION L"非模态对话框"
FONT 9, "Microsoft YaHei"
BEGIN
    PUSHBUTTON L"关闭", IDCANCEL, 30, 40, 80, 20
END

头文件(`resource.h`)

定义资源ID:

#ifndef RESOURCE_H
#define RESOURCE_H

#define IDD_MAIN_DIALOG 101
#define IDD_MODAL_DIALOG 102
#define IDD_MODELESS_DIALOG 103

// Control IDs
#define IDC_BUTTON_OPEN_MODAL 104
#define IDC_BUTTON_OPEN_MODELESS 105
#define IDC_BUTTON_CLOSE 106 

#endif // RESOURCE_H

代码说明

(1)主对话框:
   - 包含三个按钮:打开模态对话框、打开非模态对话框、关闭主对话框。
   - 点击“打开模态对话框”按钮,弹出模态对话框。
   - 点击“打开非模态对话框”按钮,弹出非模态对话框。
   - 点击“关闭”按钮,关闭主对话框。

(2)模态对话框:
   - 包含“确定”和“取消”按钮。
   - 点击按钮后关闭对话框。

(3)非模态对话框:
   - 包含“关闭”按钮。
   - 点击按钮后关闭对话框。

(4)全局变量:
   - `g_hModelessDialog` 用于保存非模态对话框的句柄。

(5)消息循环:
   - 主对话框使用 `DialogBox` 创建,自带消息循环。
   - 非模态对话框使用 `CreateDialog` 创建,需要主对话框的消息循环处理非模态对话框的消息。

运行效果

1. 主对话框显示后,点击“打开模态对话框”按钮,弹出模态对话框。在模态对话框关闭之前,主对话框无法响应操作。
2. 点击“打开非模态对话框”按钮,弹出非模态对话框。非模态对话框和主对话框可以同时操作。
3. 点击“关闭”按钮,关闭主对话框。

        通过这个案例,您可以掌握如何在Windows应用程序中使用模态对话框、非模态对话框以及消息框。

相关文章:

  • 智慧校园综合安防系统建设方案
  • 项目-个人博客测试报告
  • 04自媒体文章-自动审核(阿里云自动审核文章和图片、服务降级处理、异步调用@Async、自管理敏感词DFA、OCR识别图片文字、文章详情-静态文件生成)
  • leetcode:1827. 最少操作使数组递增(python3解法)
  • 【机器人-基础知识】标定 - 相机标定全解
  • 在IDEA中连接达梦数据库:详细配置指南
  • C++之创建线程
  • ens33没有分配到IPV4问题
  • [C语言基础]13.动态内存管理
  • vscode编译器的一些使用问题
  • 【Film】MM-StoryAgent 1:沉浸式叙事故事书视频生成,具有跨文本、图像和音频的多代理范式
  • Kali Linux快速入门指南
  • 用旧的手机搭建 MQTT Broker
  • vue-seamless-scroll无缝滚动到下一屏点击事件失效的解决办法
  • 专题三搜索插入位置
  • 新矩阵(信息学奥赛一本通-2041)
  • 文生图技术的演进、挑战与未来:一场重构人类创造力的革命
  • Qt启动新窗口
  • Android Dagger2 框架依赖图构建模块深度剖析(三)
  • 【react】react中的<></>和React Fragment的用法及区别详解
  • 商人运作亿元“茅台酒庞氏骗局”,俩客户自认受害人不服“从犯”判决提申诉
  • 首次采用“顶置主星+侧挂从星”布局,长二丁“1箭12星”发射成功
  • 安徽省委副秘书长、省委政研室主任余三元调任省社科院院长
  • 佩斯科夫:若普京认为必要,将公布土耳其谈判俄方代表人选
  • 中拉论坛部长级会议为何悬挂海地和圣卢西亚的国旗?外交部回应
  • 警方通报:某博主遭勒索后自杀系自导自演,已立案调查