AnimateWindow()错误地以高dpi(Win10)绘制背景

时间:2019-03-09 19:58:50

标签: winapi mfc windows-10 highdpi animatewindow

我正在创建一个带有主窗口的简单Win32 / MFC应用程序,以及一个使用AnimateWindow()来显示(向上滑动)和隐藏(向下滑动)窗口的子窗口。当应用程序以100%dpi缩放比例运行时,一切正常。

Child window shown

我已覆盖WM_ERASEBKGND来呈现随机的红色,以演示效果。当窗口在动画的每个“步骤”上向下滑动(隐藏)时,将重新绘制背景的“更新矩形”,即子窗口消失的确切位置,并且背景将再次变得可见。

Child window retracted with the background re-drawn with random red colors

但是,当通过Windows设置更改dpi缩放比例(在这种情况下为125%)时,将重新绘制不正确的区域。似乎传递到OnEraseBkgnd()的区域仍在使用100%dpi缩放比例,但该位置也已关闭:好像在屏幕上传递了左上角的x / y位置-space而不是client-space。因此,根据窗口在屏幕上的位置,重绘区域看起来有所不同。

Update-rectangle with wrong size and position

白色区域是子窗口的实际放置位置,背景重绘实际上应该发生的位置。

我已经确认了对Win10(1803和1809)和Win8.1的影响 这是操作系统中的错误,还是我可以做些避免该问题的措施-除了不使用AnimateWindow()以外? ShowWindow()(使用SW_SHOWSW_HIDE)可以正常工作,顺便说一句。

更新:添加了完整的源代码以重现该问题。 根本不使用可识别dpi的清单时会出现此问题,但在使用<gdiScaling xmlns="http://schemas.microsoft.com/SMI/2017/WindowsSettings">true</gdiScaling>

时也会发生此问题。
class CDialogTestApp : public CWinApp
{
    virtual BOOL InitInstance();
};

CDialogTestApp theApp;

class CAboutDlg : public CDialogEx
{
public:
    CAboutDlg() : CDialogEx(IDD_ABOUTBOX) {}
};

class CDialogTestDlg : public CDialogEx
{
public:
    CDialogTestDlg(CWnd* pParent = nullptr) : CDialogEx(IDD_DIALOGTEST_DIALOG, pParent) {}

protected:
    virtual BOOL OnInitDialog();
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);

    DECLARE_MESSAGE_MAP()

private:
    CAboutDlg mDialog;
};

BEGIN_MESSAGE_MAP(CDialogTestDlg, CDialogEx)
    ON_WM_ERASEBKGND()
    ON_WM_LBUTTONUP()
END_MESSAGE_MAP()

BOOL CDialogTestApp::InitInstance()
{
    CWinApp::InitInstance();

    CDialogTestDlg dlg;
    m_pMainWnd = &dlg;
    INT_PTR nResponse = dlg.DoModal();
    return FALSE;
}

BOOL CDialogTestDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    mDialog.Create(IDD_ABOUTBOX, this);
    return TRUE;
}

BOOL CDialogTestDlg::OnEraseBkgnd(CDC* pDC)
{
    COLORREF color = RGB(rand() & 255, 20, 40);

    CRect rect;
    GetClipBox(pDC->m_hDC, &rect);     // retrieve the update-rectangle

    CBrush brush(color);
    FillRect(pDC->m_hDC, &rect, (HBRUSH)brush.m_hObject);

    return TRUE;
}

void CDialogTestDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
    if (mDialog.IsWindowVisible())
    {
        mDialog.AnimateWindow(200, AW_HIDE | AW_SLIDE | AW_VER_POSITIVE);
    }
    else
    {
        mDialog.SetWindowPos(&CWnd::wndTop, 0, 50, 0, 0, SWP_NOSIZE);
        mDialog.AnimateWindow(200, AW_ACTIVATE | AW_SLIDE | AW_VER_NEGATIVE);
    }

    CDialogEx::OnLButtonUp(nFlags, point);
}

0 个答案:

没有答案