自学内容网 自学内容网

创建模态对话框窗口

概要

在 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()方法,创建一个以它为父窗口的模态对话框窗口。这个模态对话框窗口也在其消息响应函数里创建了一个子窗口,子窗口的大小是全屏窗口。这样就实现了双击窗口,将窗口变成全屏的效果。


原文地址:https://blog.csdn.net/sinat_38854292/article/details/144090242

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!