设置基于MFC对话框的应用程序窗口的位置

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设置基于MFC对话框的应用程序窗口的位置相关的知识,希望对你有一定的参考价值。

我有一个基于CDialog的MFC应用程序。程序结束时,我保存窗口的当前位置。程序启动时,我想恢复以前的位置。我现在正试图在OnInitDialog()中这样做,但是,当我从SetWindowPos()中调用OnInitDialog()时程序断言。我对SetWindowPos()的呼吁类似于:

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

断言与null m_hWnd句柄有关。

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

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

答案

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

感谢您的鼓励,@ zett42。

另一答案

我是这样做的:

#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);
}

我不知道你如何存储窗口位置,但我的代码因素适用于多个监视器配置。

以上是关于设置基于MFC对话框的应用程序窗口的位置的主要内容,如果未能解决你的问题,请参考以下文章

急急急!mfc中怎么在基于对话框的主界面中显示proppage属性页?最好有例子

MFC:在运行时设置控件位置

使用MFC编制基于对话框的Windows应用程序,实现画图功能

MFC 怎样在主窗口任意位置使用控件

隐藏基于对话框的MFC应用程序窗口的方法

[转]隐藏基于对话框的MFC应用程序窗口的方法