自实现模态对话框-DoModal函数

发布时间 2023-11-21 17:41:57作者: 西兰花战士

参考CDialog::DoModal函数的实现方式,自己实现了模态框相关功能。

ModalBase.h头文件

 1 #include <afxwin.h>
 2 
 3 #define ID_NULL                    0
 4 #define ID_OK                    1
 5 #define ID_CANCEL                2
 6 #define ID_ABORT                3
 7 #define ID_RETRY                4
 8 #define ID_IGNORE                5
 9 #define ID_YES                    6
10 #define ID_NO                    7
11 #define ID_CLOSE                8
12 
13 
14 //模态窗基类
15 class ModalBase : public CWnd
16 {
17 public:
18     ModalBase();
19     ~ModalBase();
20 
21     virtual int                        DoModal(HWND hParent = NULL);
22 
23     void                            SetWindowSize(int nWidth, int nHeight);
24 
25 protected:
26     virtual void                    EndDialog(int nExitCode);
27 
28     virtual void                    UpdateLayout();
29 
30     virtual    CRect                    GetTitleRect();            //获取标题栏矩形
31 
32     virtual CRect                    GetWndRect();            //获取整个窗口的矩形【忽略了边框】
33 
34     BOOL                            Create(CWnd* pParent);
35 
36 //消息循环
37 protected:
38     DECLARE_MESSAGE_MAP()
39     afx_msg void                    OnMouseMove(UINT nFlags, CPoint point);
40     afx_msg void                    OnLButtonDown(UINT nFlags, CPoint point);
41     afx_msg void                    OnLButtonUp(UINT nFlags, CPoint point);
42     
43 private:
44     bool                    m_bMouseMove = false;
45     CPoint                    m_ptOrigin;
46     int                        m_nRetCode = ID_NULL;            //模态窗退出码
47     int                        m_nWidth = 0;                    //窗口的宽度
48     int                        m_nHeight = 0;                    //窗口的高度
49 };

ModalBase.cpp源文件

  1 #include "stdafx.h"
  2 #include <afxpriv.h>
  3 #include "ModalBase.h"
  4 
  5 BEGIN_MESSAGE_MAP(ModalBase, CWnd)
  6     ON_WM_SIZE()
  7     ON_WM_PAINT()
  8     ON_WM_LBUTTONDOWN()
  9     ON_WM_MOUSEMOVE()
 10     ON_WM_LBUTTONUP()
 11 END_MESSAGE_MAP()
 12 
 13 ModalBase::ModalBase(){ }
 14 
 15 
 16 ModalBase::~ModalBase(){ }
 17 
 18 int ModalBase::DoModal(HWND hParent /*= NULL*/)
 19 {
 20     CWinApp* pApp = AfxGetApp();
 21     if (pApp) pApp->EnableModeless(FALSE);            //禁用所有非模态窗
 22     
 23     if (!hParent)
 24         hParent = ::GetActiveWindow();            //获取当前焦点窗口
 25 
 26     BOOL bEnableParent = FALSE;
 27     BOOL bEnableMainWnd = FALSE;
 28     CWnd* pMainWnd = NULL;
 29     if (hParent && hParent != ::GetDesktopWindow() && ::IsWindowEnabled(hParent))        //判断窗口是否禁用
 30     {
 31         ::EnableWindow(hParent, FALSE);            //禁用父窗口
 32         bEnableParent = TRUE;
 33 
 34         pMainWnd = AfxGetMainWnd();
 35         if (pMainWnd && pMainWnd->IsFrameWnd() && pMainWnd->IsWindowEnabled())            //禁用框架窗口
 36         {
 37             pMainWnd->EnableWindow(FALSE);
 38             bEnableMainWnd = TRUE;
 39         }
 40     }
 41 
 42     BOOL bRet = Create(CWnd::FromHandle(hParent));                //创建窗口
 43     if (!bRet)
 44     {
 45         if (bEnableParent) ::EnableWindow(hParent, TRUE);
 46 
 47         if (bEnableMainWnd) pMainWnd->EnableWindow(TRUE);
 48 
 49         return 0;
 50     }
 51 
 52     HWND hWndLastActive = ::SetActiveWindow(m_hWnd);            //激活当前窗口
 53 
 54     //显示当前窗口
 55     SetWindowPos(CWnd::FromHandle(HWND_TOPMOST), 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE);
 56     CenterWindow(CWnd::FromHandle(hParent));
 57 
 58     DWORD dwFlags = MLF_SHOWONIDLE;
 59     if (GetStyle() & DS_NOIDLEMSG) dwFlags |= MLF_NOIDLEMSG;
 60         
 61     int nResult = RunModalLoop(dwFlags);        //进入消息循环
 62 
 63     ASSERT(m_nRetCode != ID_NULL);                //从消息循环退出,应该已经设置了其他值
 64 
 65     if (IsWindow(m_hWnd))
 66         SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
 67 
 68     if (bEnableMainWnd) pMainWnd->EnableWindow(TRUE);            //激活框架窗口
 69     if (bEnableParent) ::EnableWindow(hParent, TRUE);            //激活父窗口
 70         
 71     ::SetActiveWindow(hWndLastActive);            //还原
 72     ::DestroyWindow(m_hWnd);                    //销毁当前窗口
 73 
 74     if (pApp) pApp->EnableModeless(TRUE);            //启用所有非模态窗
 75 }
 76 
 77 void ModalBase::SetWindowSize(int nWidth, int nHeight)
 78 {
 79     m_nWidth = nWidth;
 80     m_nHeight = nHeight;
 81 }
 82 
 83 BOOL ModalBase::Create(CWnd* pParent)
 84 {
 85     CString strWndClass = AfxRegisterWndClass(CS_VREDRAW | CS_HREDRAW, ::LoadCursor(NULL, IDC_ARROW), NULL, NULL);
 86     BOOL bResult = CreateEx(NULL, strWndClass, _T(""), WS_POPUP, CRect(0, 0, m_nWidth, m_nHeight), pParent, NULL);
 87     return bResult;
 88 }
 89 
 90 void ModalBase::OnMouseMove(UINT nFlags, CPoint point)
 91 {
 92     if (m_bMouseMove)
 93     {
 94         CRect rcWindow;
 95         GetWindowRect(rcWindow);
 96         CPoint pt = point - m_ptOrigin + rcWindow.TopLeft();
 97         SetWindowPos(NULL, pt.x, pt.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOREDRAW);
 98     }
 99     __super::OnMouseMove(nFlags, point);
100 }
101 
102 void ModalBase::OnLButtonDown(UINT nFlags, CPoint point)
103 {
104     SetFocus();
105     if (nFlags == MK_LBUTTON && GetTitleRect().PtInRect(point))
106     {
107         SetCapture();
108         m_bMouseMove = true;
109         m_ptOrigin = point;
110     }
111     __super::OnLButtonDown(nFlags, point);
112 }
113 
114 void ModalBase::OnLButtonUp(UINT nFlags, CPoint point)
115 {
116     if (m_bMouseMove)
117     {
118         ReleaseCapture();
119         m_bMouseMove = false;
120     }
121 }
122 
123 void ModalBase::EndDialog(int nExitCode)
124 {
125     ASSERT(nExitCode != ID_NULL);
126     if (m_nRetCode == ID_NULL)
127     {
128         m_nRetCode = nExitCode;
129         if (m_nFlags & (WF_MODALLOOP | WF_CONTINUEMODAL))
130             EndModalLoop(m_nRetCode);
131 
132         ::EndDialog(m_hWnd, m_nRetCode);
133     }
134 }
135 
136 void ModalBase::UpdateLayout()
137 {
138 
139 }
140 
141 CRect ModalBase::GetTitleRect()
142 {
143     CRect rcTitle = GetWndRect();
144     rcTitle.bottom = rcTitle.top + 28;
145     return rcTitle;
146 }
147 
148 CRect ModalBase::GetWndRect()
149 {
150     CRect rcClient;
151     GetClientRect(rcClient);
152     rcClient.DeflateRect(2, 2, 2, 2);
153     return rcClient;
154 }

上面只提供了基类代码,有需要的,可以自己派生相关的类。