【问题标题】:Set position of MFC dialog-based application window设置基于 MFC 对话框的应用程序窗口的位置
【发布时间】:2019-04-25 03:02:14
【问题描述】:

我有一个基于 CDialog 的 MFC 应用程序。程序结束时我保存窗口的当前位置。当程序启动时,我想恢复之前的位置。我目前正在尝试在OnInitDialog() 中执行此操作,但是,当我从OnInitDialog() 中调用SetWindowPos() 时,程序会断言。我对SetWindowPos() 的调用类似于:

SetWindowPos(&CWnd::wndTop, 10, 10, 500, 500, SWP_NOREDRAW | SWP_NOZORDER);

断言与空的m_hWnd 句柄有关。

这是重新定位基于对话框的应用程序窗口的正确位置吗?

关于我为什么要断言的任何想法?

【问题讨论】:

  • OnInitDialog()调用SetWindowPos()是有效的,因为窗口句柄已经存在。需要查看minimal reproducible example 以获得进一步的帮助。
  • 我记得,MFC 已经为您保存了窗口位置(并恢复它们)。有变化吗?
  • @IInspectable 不在基于 CDialog 的应用程序中。

标签: mfc cdialog


【解决方案1】:

在为我最初的问题提供更多信息的过程中,我发现调用SetWindowPos() 会将消息传递到尚未创建的对话框中的工具栏。我将SetWindowPos() 移到OnInitiDialog() 的末尾,它起作用了。

感谢您的鼓励,@zett42。

【讨论】:

    【解决方案2】:

    这就是我的做法:

    #include "stdafx.h"
    #include "resource.h"
    #include "ResizingDialog.h"
    
    IMPLEMENT_DYNAMIC(CResizingDialog, CDialogEx)
    
    CResizingDialog::CResizingDialog(const CString& strWindowID, UINT nIDTemplate, CWnd* pParent /* nullptr */, bool bOnlyStorePosition /* false */)
        : CDialogEx(nIDTemplate, pParent)
        , m_strWindowID(strWindowID)
        , m_bOnlyStorePosition(bOnlyStorePosition)
        , m_bDoNotShowResizeIcon(false)
    {
        m_rcInit.SetRect(0, 0, 0, 0);
    }
    
    
    CResizingDialog::~CResizingDialog()
    = default;
    
    void CResizingDialog::DoDataExchange(CDataExchange* pDX)
    {
        CDialogEx::DoDataExchange(pDX);
    }
    
    
    BEGIN_MESSAGE_MAP(CResizingDialog, CDialogEx)
        ON_WM_GETMINMAXINFO()
        ON_WM_DESTROY()
        ON_WM_PAINT()
        ON_WM_NCHITTEST()
        ON_WM_SIZE()
    END_MESSAGE_MAP()
    
    
    BOOL CResizingDialog::OnInitDialog()
    {
        CDialogEx::OnInitDialog();
    
        // Save Initial window size to m_rcInit
        GetWindowRect(&m_rcInit);
    
        //if (!m_bOnlyStorePosition && !m_bDoNotShowResizeIcon)
            //InitialiseResizeIcon(m_bmpResize, m_lblResize, this);
    
        RestoreWindowPosition(m_strWindowID, this, true);
    
        return TRUE;  // return TRUE unless you set the focus to a control
                      // EXCEPTION: OCX Property Pages should return FALSE
    }
    
    
    void CResizingDialog::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
    {
        // Set the minimum window size to initial size.
        lpMMI->ptMinTrackSize.x = m_rcInit.Width();
        lpMMI->ptMinTrackSize.y = m_rcInit.Height();
    
        CDialogEx::OnGetMinMaxInfo(lpMMI);
    }
    
    
    void CResizingDialog::RestoreWindowPosition(CString strWindow, CWnd* pWindow, bool bOverrideState)
    {
        int     max_x, max_y;
        RECT    rtWindow;
    
        if (pWindow == nullptr)
            return;
    
        // Only restore if there is a previously saved position
        if ((rtWindow.top = AfxGetApp()->GetProfileInt(strWindow, _T("Top"), -1)) != -1 &&
            (rtWindow.left = AfxGetApp()->GetProfileInt(strWindow, _T("Left"), -1)) != -1 &&
            (rtWindow.bottom = AfxGetApp()->GetProfileInt(strWindow, _T("Bottom"), -1)) != -1 &&
            (rtWindow.right = AfxGetApp()->GetProfileInt(strWindow, _T("Right"), -1)))
        {
            max_x = rtWindow.right - rtWindow.left;
            max_y = rtWindow.bottom - rtWindow.top;
    
            // Get a handle to the monitor
            HMONITOR hMonitor = ::MonitorFromPoint(
                CPoint(rtWindow.left, rtWindow.top), MONITOR_DEFAULTTONEAREST);
    
            // Get the monitor info
            MONITORINFO monInfo;
    
            monInfo.cbSize = sizeof(MONITORINFO);
            if (::GetMonitorInfo(hMonitor, &monInfo) == 0)
                AfxMessageBox(_T("GetMonitorInfo failed"));
            else
            {
                // Adjust for work area
                rtWindow.left += monInfo.rcWork.left - monInfo.rcMonitor.left;
                rtWindow.top += monInfo.rcWork.top - monInfo.rcMonitor.top;
    
                // Ensure top left point is on screen
                if (CRect(monInfo.rcWork).PtInRect(CPoint(rtWindow.left, rtWindow.top)) == FALSE)
                {
                    rtWindow.left = monInfo.rcWork.left;
                    rtWindow.top = monInfo.rcWork.top;
                }
    
                rtWindow.right = rtWindow.left + max_x;
                rtWindow.bottom = rtWindow.top + max_y;
    
                // Restore window size
                pWindow->MoveWindow(&rtWindow, FALSE);
            }
    
            if (bOverrideState)
            {
                // Let us override by restoring the window state
                int iState = AfxGetApp()->GetProfileInt(strWindow, _T("ShowCmd"), SW_SHOWNORMAL);
                pWindow->ShowWindow(iState);
            }
        }
    }
    
    void CResizingDialog::SaveWindowPosition(CString strWindow, CWnd* pWindow)
    {
        WINDOWPLACEMENT wp;
    
        if (pWindow == nullptr)
            return;
    
        pWindow->GetWindowPlacement(&wp);
    
        // Commit to registry
        AfxGetApp()->WriteProfileInt(strWindow, _T("Top"), wp.rcNormalPosition.top);
        AfxGetApp()->WriteProfileInt(strWindow, _T("Left"), wp.rcNormalPosition.left);
        AfxGetApp()->WriteProfileInt(strWindow, _T("Bottom"), wp.rcNormalPosition.bottom);
        AfxGetApp()->WriteProfileInt(strWindow, _T("Right"), wp.rcNormalPosition.right);
        AfxGetApp()->WriteProfileInt(strWindow, _T("ShowCmd"), wp.showCmd);
    }
    
    
    void CResizingDialog::InitialiseResizeIcon(CBitmap& rBmpResize, CStatic& rLblResize, CWnd* pDialog)
    {
        CRect rcIcon, rcClient;
    
        if (pDialog != nullptr)
        {
            rBmpResize.LoadOEMBitmap(OBM_SIZE);
            rLblResize.Create(nullptr, WS_CHILD | WS_VISIBLE | SS_BITMAP,
                CRect(0, 0, 16, 16), pDialog, IDC_STATIC_RESIZE);
            rLblResize.SetBitmap(rBmpResize);
            //theApp.UpdateBitmapBackground(rLblResize.GetBitmap(), true, GetSysColor(COLOR_ACTIVECAPTION));
    
            pDialog->GetClientRect(rcClient);
            rLblResize.GetClientRect(rcIcon);
            rLblResize.SetWindowPos(&CWnd::wndTop,
                rcClient.right - rcIcon.Width(),
                rcClient.bottom - rcIcon.Height(), 0, 0, SWP_NOSIZE);
    
            CMFCDynamicLayout *pDynamicLayout = pDialog->GetDynamicLayout();
            if (pDynamicLayout != nullptr)
            {
                CMFCDynamicLayout::MoveSettings moveSettings = CMFCDynamicLayout::MoveHorizontalAndVertical(100, 100);
                CMFCDynamicLayout::SizeSettings sizeSettings = CMFCDynamicLayout::SizeNone();
    
                pDynamicLayout->AddItem(rLblResize.GetSafeHwnd(), moveSettings, sizeSettings);
            }
        }
    }
    
    void CResizingDialog::OnDestroy()
    {
        CDialogEx::OnDestroy();
    
        SaveWindowPosition(m_strWindowID, this);
    }
    
    
    void CResizingDialog::DoNotShowResizeIcon()
    {
        m_bDoNotShowResizeIcon = true;
    }
    
    
    void CResizingDialog::OnPaint()
    {
        CPaintDC dc(this); // device context for painting
                           // TODO: Add your message handler code here
                           // Do not call CDialogEx::OnPaint() for painting messages
    
        if (!m_bOnlyStorePosition && !m_bDoNotShowResizeIcon)
        {
            CRect rc;
            GetClientRect(&rc);
            rc.left = rc.right - ::GetSystemMetrics(SM_CXHSCROLL);
            rc.top = rc.bottom - ::GetSystemMetrics(SM_CYVSCROLL);
            HTHEME ht = OpenThemeData(GetSafeHwnd(), L"STATUS");
            if (ht)
            {
                DrawThemeBackground(ht, dc, SP_GRIPPER, 0, &rc, nullptr);
                CloseThemeData(ht);
            }
            else
            {
                dc.DrawFrameControl(rc, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
            }
        }
    }
    
    
    LRESULT CResizingDialog::OnNcHitTest(CPoint point)
    {
        CRect rc;
    
        GetWindowRect(rc);
        rc.left = rc.right - ::GetSystemMetrics(SM_CXHSCROLL);
        rc.top = rc.bottom - ::GetSystemMetrics(SM_CYVSCROLL);
        if (rc.PtInRect(point))
            return HTBOTTOMRIGHT;
    
        return CDialogEx::OnNcHitTest(point);
    }
    
    
    void CResizingDialog::OnSize(UINT nType, int cx, int cy)
    {
        CDialogEx::OnSize(nType, cx, cy);
    
        Invalidate(TRUE);
    }
    

    我不知道您是如何存储窗口位置的,但我的代码考虑了多个显示器配置。

    【讨论】:

      猜你喜欢
      • 2011-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-22
      • 2012-11-27
      • 2012-01-26
      • 1970-01-01
      相关资源
      最近更新 更多