Win32SDK实现自定义消息框(亦可用来做应用窗口框架)

xingyun86 2021-6-28 845

Win32SDK实现自定义消息框(亦可用来做应用窗口框架)

使用简单,static控件实现同时支持水平居中对齐、垂直居中对齐和自动换行。

class MessageWindow {
public:
    MessageWindow()
    {
        // InitCommonControlsEx() is required on Windows XP if an application
        // manifest specifies use of ComCtl32.dll version 6 or later to enable
        // visual styles.  Otherwise, any window creation will fail.
        INITCOMMONCONTROLSEX InitCtrls = { 0 };
        InitCtrls.dwSize = sizeof(InitCtrls);
        // Set this to include all the common control classes you want to use
        // in your application.
        InitCtrls.dwICC = ICC_LISTVIEW_CLASSES | ICC_TREEVIEW_CLASSES 
            | ICC_BAR_CLASSES | ICC_TAB_CLASSES | ICC_UPDOWN_CLASS 
            | ICC_PROGRESS_CLASS | ICC_HOTKEY_CLASS | ICC_ANIMATE_CLASS 
            | ICC_WIN95_CLASSES | ICC_DATE_CLASSES | ICC_USEREX_CLASSES 
            | ICC_COOL_CLASSES | ICC_INTERNET_CLASSES | ICC_PAGESCROLLER_CLASS 
            | ICC_NATIVEFNTCTL_CLASS | ICC_STANDARD_CLASSES | ICC_LINK_CLASS;
        InitCommonControlsEx(&InitCtrls);
        m_hGlobal = GlobalAlloc(GMEM_ZEROINIT, sizeof(DLGTEMPLATE));
        if (m_hGlobal != NULL)
        {
            m_pDlgTemplate = (DLGTEMPLATE*)GlobalLock(m_hGlobal);
        }
    }
    ~MessageWindow()
    {
        if (m_hGlobal != NULL)
        {
            if (m_pDlgTemplate != NULL)
            {
                GlobalUnlock(m_hGlobal);
                m_pDlgTemplate = NULL;
            }
            GlobalFree(m_hGlobal);
            m_hGlobal = NULL;
        }
    }
public:
    HGLOBAL m_hGlobal = NULL;
    DLGTEMPLATE*m_pDlgTemplate = NULL;
    TSTRING m_strCaption = TEXT("");
    TSTRING m_strMessage = TEXT("");
    HGDIOBJ DEFAULTGUIFONT = GetStockObject(DEFAULT_GUI_FONT);
    typedef enum CTRLIDTYPE 
    {
        IDC_STATIC_IMG = (IDC_STATIC + 512),
        IDC_STATIC_MSG,
        IDC_TOOLTIP_MSG,
    }CTRLIDTYPE;
    INT ICON_WIDTH = 48;
    INT ICON_HEIGHT = 48;
    INT BUTTON_WIDTH = 80;
    INT BUTTON_HEIGHT = 20;
    HWND m_hTip = NULL;
    TOOLINFO m_ToolInfo = { 0 };
public:
    static void SetWindowIcon(HWND hWnd)
    {
        DeleteObject((HGDIOBJ)SNDMSG(hWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)SNDMSG(GetParent(hWnd), WM_GETICON, (WPARAM)ICON_BIG, (LPARAM)NULL)));
        DeleteObject((HGDIOBJ)SNDMSG(hWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)SNDMSG(GetParent(hWnd), WM_GETICON, (WPARAM)ICON_SMALL, (LPARAM)NULL)));
        DeleteObject((HGDIOBJ)SNDMSG(hWnd, WM_SETICON, (WPARAM)ICON_SMALL2, (LPARAM)SNDMSG(GetParent(hWnd), WM_GETICON, (WPARAM)ICON_SMALL2, (LPARAM)NULL)));
    }
    static BOOL CALLBACK EnumProcCallBack(HWND hWnd, LPARAM lParam)
    {
        SNDMSG(hWnd, WM_SETFONT, (LPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)TRUE);
        return TRUE;
    }
    static void UsingDefaultFont(HWND hWnd, LPARAM lParam)
    {
        EnumChildWindows(hWnd,(WNDENUMPROC)&MessageWindow::EnumProcCallBack, lParam);
    }
    static void SetStaticSystemIcon(HWND hWnd, LPCTSTR lpIconName)
    {
        DeleteObject((HGDIOBJ)SNDMSG(hWnd, STM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIcon(NULL, lpIconName)));
    }
    static void SetStaticApplicationIcon(HWND hWnd, LPCTSTR lpIconName, HINSTANCE hInstance)
    {
        DeleteObject((HGDIOBJ)SNDMSG(hWnd, STM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIcon(hInstance, lpIconName)));
    }
    static BOOL CALLBACK ProcCallBack(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        MessageWindow* thiz = (MessageWindow*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
        switch (uMsg)
        {
        case WM_INITDIALOG:
        {
            RECT rcDlg = { 0 };
            GetClientRect(hWnd, &rcDlg);
            SetWindowLongPtr(hWnd, GWLP_USERDATA, lParam);
            thiz = (MessageWindow*)GetWindowLongPtr(hWnd, GWLP_USERDATA);

            CreateWindowEx(0, WC_STATIC, TEXT(""), WS_CHILD | WS_VISIBLE | SS_ICON | SS_CENTERIMAGE, (rcDlg.right - rcDlg.left - thiz->BUTTON_WIDTH - thiz->ICON_WIDTH) / 2, 0, thiz->ICON_WIDTH, thiz->ICON_HEIGHT, hWnd, (HMENU)IDC_STATIC_IMG, NULL, (LPVOID)lParam);
            CreateWindowEx(0, WC_STATIC, thiz->m_strMessage.c_str(), WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE | SS_CENTER | SS_OWNERDRAW, 0, thiz->ICON_WIDTH, rcDlg.right - rcDlg.left, rcDlg.bottom - rcDlg.top - thiz->ICON_WIDTH, hWnd, (HMENU)IDC_STATIC_MSG, NULL, (LPVOID)lParam);
            CreateWindowEx(0, WC_BUTTON, TEXT("是"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, rcDlg.right - rcDlg.left - thiz->BUTTON_WIDTH, 0, thiz->BUTTON_WIDTH, thiz->BUTTON_HEIGHT, hWnd, (HMENU)IDYES, NULL, (LPVOID)lParam);
            CreateWindowEx(0, WC_BUTTON, TEXT("否"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, rcDlg.right - rcDlg.left - thiz->BUTTON_WIDTH, thiz->BUTTON_HEIGHT, thiz->BUTTON_WIDTH, thiz->BUTTON_HEIGHT, hWnd, (HMENU)IDNO, NULL, (LPVOID)lParam);

            if (thiz->m_strMessage.length() > 512)
            {
                thiz->m_hTip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL,
                    WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
                    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                    hWnd, (HMENU)NULL, NULL, NULL);
                DWORD dwErr = GetLastError();
                SetWindowPos(thiz->m_hTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

                // Associate the tooltip with the tool.
                thiz->m_ToolInfo.cbSize = sizeof(thiz->m_ToolInfo);
                thiz->m_ToolInfo.hwnd = hWnd;
                thiz->m_ToolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
                thiz->m_ToolInfo.uId = (UINT_PTR)thiz->m_hTip;
                thiz->m_ToolInfo.lpszText = (LPTSTR)thiz->m_strMessage.c_str();
                SNDMSG(thiz->m_hTip, TTM_ADDTOOL, 0, (LPARAM)&thiz->m_ToolInfo);
            }

            SetWindowIcon(hWnd);
            UsingDefaultFont(hWnd, lParam);
            SetStaticSystemIcon(GetDlgItem(hWnd, IDC_STATIC_IMG), IDI_QUESTION);

            SetWindowText(hWnd, thiz->m_strCaption.c_str());
        }
        break;
        case WM_MOUSEMOVE:
        {
            TRACKMOUSEEVENT tme = { 0 };
            tme.cbSize = sizeof(tme);
            tme.dwFlags = TME_LEAVE;
            tme.dwHoverTime = HOVER_DEFAULT;
            tme.hwndTrack = hWnd;
            TrackMouseEvent(&tme);

            RECT rcMsg = { 0 };
            POINT ptCursor = { 0 };
            GetClientRect(GetDlgItem(hWnd, IDC_STATIC_MSG), &rcMsg);
            ClientToScreen(GetDlgItem(hWnd, IDC_STATIC_MSG), &((LPPOINT)&rcMsg)[0]);
            ClientToScreen(GetDlgItem(hWnd, IDC_STATIC_MSG), &((LPPOINT)&rcMsg)[1]);
            GetCursorPos(&ptCursor);
            if (PtInRect(&rcMsg, ptCursor) == TRUE)
            {
                // Activate the tooltip.
                SNDMSG(thiz->m_hTip, TTM_TRACKACTIVATE, (WPARAM)TRUE, (LPARAM)&thiz->m_ToolInfo);
                SNDMSG(thiz->m_hTip, TTM_TRACKPOSITION, 0, (LPARAM)MAKELONG(ptCursor.x, ptCursor.y));
            }
            else
            {
                // InActivate the tooltip.
                SNDMSG(thiz->m_hTip, TTM_TRACKACTIVATE, (WPARAM)FALSE, (LPARAM)&thiz->m_ToolInfo);
            }
        }
        break;
        case WM_MOUSELEAVE:
        {
            // InActivate the tooltip.
            SNDMSG(thiz->m_hTip, TTM_TRACKACTIVATE, (WPARAM)FALSE, (LPARAM)&thiz->m_ToolInfo);
        }
        break;
        case WM_GETMINMAXINFO:
        {
            MINMAXINFO* mminfo = (PMINMAXINFO)lParam;
            /*mminfo->ptMinTrackSize.x = thiz->m_MinSize.cx;
            mminfo->ptMinTrackSize.y = thiz->m_MinSize.cy;
            mminfo->ptMaxSize.x = thiz->m_MaxSize.cx;
            mminfo->ptMaxSize.y = thiz->m_MaxSize.cy;
            mminfo->ptMaxPosition.x = 0;
            mminfo->ptMaxPosition.y = 0;
            mminfo->ptMaxTrackSize.x = thiz->m_MaxSize.cx;
            mminfo->ptMaxTrackSize.y = thiz->m_MaxSize.cy;*/
        }
        break;
        case WM_DRAWITEM:
        { 
            LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)lParam;
            //声明一个指向DRAWITEMSTRUCT结构体的指针并将其指向存储着按钮构造信息的lParam
            switch (lpDIS->CtlID)
            {
            case IDC_STATIC_MSG:
            {
                int realHeight = 0;
                RECT itemRect = { 0 };
                RECT realRect = { 0 };
                GetClientRect(lpDIS->hwndItem, &itemRect); // 获得客户区范围
                memcpy(&realRect, &itemRect, sizeof(realRect));
                realHeight = DrawText(lpDIS->hDC, thiz->m_strMessage.c_str(), (int)thiz->m_strMessage.length(), &realRect, DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_CALCRECT | DT_EDITCONTROL); // 获得文本高度

                realRect.top = ((itemRect.bottom - itemRect.top) - realHeight) / 2;
                realRect.bottom = realRect.top + realHeight;
                DrawText(lpDIS->hDC, thiz->m_strMessage.c_str(), (int)thiz->m_strMessage.length(), &realRect, DT_CENTER | DT_VCENTER | DT_EDITCONTROL | DT_WORDBREAK);
            }
            break;
            }
        }
        break;
        case WM_PAINT:
        {
            //
            //PAINTSTRUCT ps = {0};
            //HDC hDC= BeginPaint(hWnd, &ps);
            //EndPaint(hWnd, &ps);
        }
        break;
        case WM_COMMAND:
        {
            switch (LOWORD(wParam))
            {
            case IDYES:
            case IDNO:
            case IDOK:
            case IDCANCEL:
            case IDRETRY:
            {
                ::EndDialog(hWnd, LOWORD(wParam));
            }
            break;
            default:
                break;
            }
        }
        break;
        case WM_CLOSE:
        {
            ::EndDialog(hWnd, IDCLOSE);
        }
        break;
        case WM_DESTROY:
        {
            ::DestroyWindow(hWnd);
        }
        break;
        }
        return FALSE;
    }
    INT_PTR Run(const TSTRING& strMessage, const TSTRING& strCaption, HWND hParent)
    {
        m_strMessage = strMessage; 
        m_strCaption = strCaption;
        m_pDlgTemplate->x = 0;
        m_pDlgTemplate->y = 0;
        m_pDlgTemplate->cx = 120;
        m_pDlgTemplate->cy = 60;
        m_pDlgTemplate->style = WS_POPUP | WS_BORDER | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | DS_MODALFRAME | DS_SETFONT | DS_FIXEDSYS;
        m_pDlgTemplate->dwExtendedStyle = WS_EX_TOPMOST;
        m_pDlgTemplate->cdit = 0;
        return DialogBoxIndirectParam(GetModuleHandle(NULL), (DLGTEMPLATE*)m_pDlgTemplate, hParent, (DLGPROC)&MessageWindow::ProcCallBack, (LPARAM)this);
    }
};

使用例子:

void CPCMDlg::OnNMRClickListProcess(NMHDR* pNMHDR, LRESULT* pResult)
{
    LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
    // TODO: Add your control notification handler code here
    if (pNMItemActivate->iItem != (-1))
    {
        CListCtrl* pListCtrl = (CListCtrl*)GetDlgItem(IDC_LIST_PROCESS);
        TCHAR tText[MAX_PATH] = { 0 };
        LVITEM lvi = { 0 };
        lvi.mask = LVIF_TEXT;
        lvi.iItem = pNMItemActivate->iItem;
        lvi.iSubItem = pNMItemActivate->iSubItem;
        lvi.pszText = tText;
        lvi.cchTextMax = sizeof(tText) / sizeof(*tText);
        pListCtrl->GetItem(&lvi);

        enum MenuType {
            MT_CLOSE = WM_USER + WM_NOTIFY,
        };
        POINT pt = { 0 };
        HMENU menu = CreatePopupMenu();
        AppendMenu(menu, MF_STRING, MT_CLOSE, TEXT("关闭"));
        GetCursorPos(&pt);
        switch (TrackPopupMenu(menu, TPM_VERTICAL | TPM_VCENTERALIGN | TPM_RETURNCMD, pt.x, pt.y, 0, GetSafeHwnd(), NULL))
        {
        case MT_CLOSE:
        {
            TSTRING tMsg = (TEXT("即将关闭") + TSTRING(tText) + TEXT("?"));
            if (MessageWindow().Run(tMsg, TEXT("关闭提示"), m_hWnd) == IDYES)
            {
                OnOK();
            }
        }
        break;
        }
    }
    *pResult = 0;
}


×
打赏作者
最新回复 (0)
只看楼主
全部楼主
返回