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

创建模态对话框窗口

文章目录

    • 概要
    • 实例代码
    • 技术细节

概要

在 Windows 应用程序开发中,创建自定义对话框是一个常见需求。本文提供一份创建模态对话框的代码,供大家参考。

实例代码

下面是真实项目中使用的代码,实现的效果是,双击一个窗口,将窗口变成全屏(实际上这个全屏窗口是新建的一个以原窗口为父窗口的模态对话框窗口):

HINSTANCE g_hInstance;  // 实例句柄

bool fakeMessageBox(HINSTANCE hInst, HWND hwnd, DLGPROC lpDglPrc, void* pApi) {
    bool bSuccess = false;
    HDC hdc = GetDC(nullptr);
    if (hdc) {
        NONCLIENTMETRICSW ncm = { sizeof(ncm) };
        if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0)) {
            DialogTemplate tmp;

            // Write out the extended dialog template header
            tmp.Write<WORD>(1);       // dialog version
            tmp.Write<WORD>(0xFFFF);  // extended dialog template
            tmp.Write<DWORD>(0);      // help ID
            tmp.Write<DWORD>(0);      // extended style
            tmp.Write<DWORD>(DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_SYSMENU | WS_CLIPCHILDREN);
            tmp.Write<WORD>(0);       // number of controls
            tmp.Write<WORD>(0);       // X
            tmp.Write<WORD>(0);       // Y
            tmp.Write<WORD>(439);     // width
            tmp.Write<WORD>(275);     // height
            tmp.WriteString(L"");     // no menu
            tmp.WriteString(L"");     // default dialog class
            tmp.WriteString(L"");     // title

            // Next comes the font description.
            // See text for discussion of fancy formula.
            if (ncm.lfMessageFont.lfHeight < 0) {
                ncm.lfMessageFont.lfHeight = -MulDiv(ncm.lfMessageFont.lfHeight, 72, GetDeviceCaps(hdc, LOGPIXELSY));
            }
            tmp.Write<WORD>((WORD)ncm.lfMessageFont.lfHeight);  // point
            tmp.Write<WORD>((WORD)ncm.lfMessageFont.lfWeight);  // weight
            tmp.Write<BYTE>(ncm.lfMessageFont.lfItalic);        // Italic
            tmp.Write<BYTE>(ncm.lfMessageFont.lfCharSet);       // CharSet
            tmp.WriteString(ncm.lfMessageFont.lfFaceName);

            // Template is ready - go display it.
            bSuccess = DialogBoxIndirectParam(hInst, tmp.Template(), hwnd, lpDglPrc, (LPARAM)pApi) >= 0;
        }
        ReleaseDC(nullptr, hdc);  // fixed 11 May
    }
    return bSuccess;
}

// 模态对话框的消息响应函数,hwndDlg是窗口句柄。在WM_INITDIALOG消息中再创建一个子窗口hwnd
INT_PTR dlgFullScreenPrc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    static CPlayWnd *pPlayWnd = nullptr;
    HWND hwnd = nullptr;
    PAINTSTRUCT ps;
    HDC hdc;
    switch (uMsg) {
        case WM_INITDIALOG: {
            pPlayWnd = (CPlayWnd *)lParam;
            const int SCREEN_WIDTH = GetSystemMetrics(SM_CXSCREEN), SCREEN_HEIGHT = GetSystemMetrics(SM_CYSCREEN);
            HINSTANCE hinstance = (HINSTANCE)GetWindowLong(hwndDlg, GWL_HINSTANCE);
            hwnd = CreateWindowEx(0, TEXT("STATIC"), nullptr,
                                 /* WS_CHILD |*/WS_POPUP | WS_VISIBLE,
                                  0,
                                  0,
                                  SCREEN_WIDTH,
                                  SCREEN_HEIGHT,
                                  hwndDlg, nullptr, hinstance, nullptr);
            long lWindowStyle = GetWindowLong(hwnd, GWL_STYLE);
            lWindowStyle &= ~WS_SYSMENU;  // 去掉系统菜单
            lWindowStyle &= ~WS_CAPTION;  // 去掉标题栏
            SetWindowLong(hwnd, GWL_STYLE, lWindowStyle);
        } break;
        case WM_LBUTTONDBLCLK: {
            SendMessage(hwndDlg, WM_COMMAND, WM_DESTROY, NULL);
        } break;
        case WM_COMMAND: {
            pPlayWnd = nullptr;
            EndDialog(hwndDlg, 0);
        } break;
        case WM_PAINT: {
            hdc = BeginPaint(hwndDlg, &ps);
            RECT rect;
            rect.left = 0;
            rect.top = 0;
            rect.right = GetSystemMetrics(SM_CXSCREEN);
            rect.bottom = GetSystemMetrics(SM_CYSCREEN);
            FillRect(hdc, &rect, CreateSolidBrush(RGB(0, 0, 0)));
            EndPaint(hwndDlg, &ps);
        } break;
        case WM_ERASEBKGND: {
            return true;
        }
        default:
            return false;
    }
    return true;
}

void threadFullScreenProc(CPlayWnd *obj) {
    // 进入全屏
    fakeMessageBox(g_hInstance, obj->m_hPWnd, (DLGPROC)dlgFullScreenPrc, obj);
    // 全屏退出,下面做其他操作
    // ......
}

// 父窗口m_hPWnd的响应函数
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) {
    // ......
    case WM_LBUTTONDBLCLK: {
        // 收到双击事件,通知到CPlayWnd的FullScreen()
    } break;
    // ......
}

class CPlayWnd {
   // ......
   public:
    int FullScreen() {
        std::thread thread = std::thread(threadFullScreenProc, this);
        thread.detach();
        return 0;
    }

   public:
    HWND m_hPWnd;  // 通过CreateWindowEx创建的父窗口
    // ......
};

int main() {
    // ......
    g_hInstance = ::GetModuleHandle(NULL);
    CPlayWnd wndObj;

    // ......
    return 0;
}

技术细节

上述代码中,m_hPWndCPlayWnd类创建的一个窗口,当它接收到鼠标双击事件后,会调用其FullScreen()方法,创建一个以它为父窗口的模态对话框窗口。这个模态对话框窗口也在其消息响应函数里创建了一个子窗口,子窗口的大小是全屏窗口。这样就实现了双击窗口,将窗口变成全屏的效果。


http://www.kler.cn/a/417648.html

相关文章:

  • 【Uniapp-Vue3】创建DB schema数据表结构
  • 20250205——Windows系统基于ollama的DeepSeek-R1本地安装
  • open-webui启动报错:OSError: [WinError 1314] 客户端没有所需的特权。
  • 【PyQt】使用PyQt5和Matplotlib实现的CSV数据可视化工具
  • 【ArcGIS_Python】使用arcpy脚本将shape数据转换为三维白膜数据
  • 【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.22 形状操控者:转置与轴交换的奥秘
  • SpringBoot 框架下的新冠密接者跟踪系统:卓越性能与稳定性保障
  • 【Python网络爬虫笔记】6- 网络爬虫中的Requests库
  • tomcat控制台中文乱码的解决方法
  • 使用LabVIEW2019x64的IMAQdx调用工业相机采图(二)
  • DataWhale—PumpkinBook(TASK07支持向量机)
  • 记录Threadlocal使用
  • 机载视频流回传+编解码方案
  • node.js基础学习-http模块-创建HTTP服务器、客户端(一)
  • jeecgbootvue2重新整理数组数据或者添加合并数组并遍历背景图片或者背景颜色
  • 三维路径规划|基于黑翅鸢BKA优化算法的三维路径规划Matlab程序
  • AI前景分析展望——GPTo1 SoraAI
  • 浮点数计算,不丢失精度
  • 第二部分shell----二、shell 条件测试
  • Flutter 1.2:flutter配置gradle环境
  • Docker初识-架构
  • 【C++boost::asio网络编程】有关socket的创建和连接的笔记
  • 半导体制造检测新突破:XARION 激光超声无损检测系统的应用
  • element的el-table表格标题用css自定义是否必填,用添加伪类的方式标红色*
  • Ubuntu 安装 MariaDB
  • Spring Boot【三】