AnimateWindow() неправильно рисует фон с высоким разрешением (Win10)
Я создаю простое приложение Win32/MFC с главным окном и дочерним окном, которое использует AnimateWindow()
показать (сдвинуть вверх) и скрыть (сдвинуть вниз) окно. При запуске приложения с масштабированием 100% dpi все работает нормально.
Я переопределил WM_ERASEBKGND
сделать случайный красный цвет, чтобы продемонстрировать эффект. Когда окно скользит вниз (скрывается) на каждом "шаге" анимации, "прямоугольник обновления" фона перерисовывается именно там, где исчезло дочернее окно, и фон должен снова стать видимым.
Однако при изменении dpi-масштабирования через настройки Windows (в данном случае до 125%) неверная область перерисовывается. Похоже, что область перешла в OnEraseBkgnd()
по-прежнему использует размер 100% dpi-масштабирования, но позиция также отключена: создается впечатление, что позиция x/y верхнего левого угла передается в пространстве экрана, а не в пространстве клиента. Таким образом, область перерисовки выглядит по-разному, в зависимости от того, где на экране расположено окно.
Белая область - это то место, где на самом деле было расположено дочернее окно, и где на самом деле должно было произойти перерисовка фона.
Я подтвердил этот эффект на Win10 (1803 и 1809) и на Win8.1. Это ошибка в ОС или есть что-то, что я могу сделать, чтобы избежать проблемы - кроме как не использовать AnimateWindow()
? ShowWindow()
(с SW_SHOW
или же SW_HIDE
) работает просто отлично, кстати.
Обновление: добавлен полный исходный код для воспроизведения проблемы. Проблема возникает, когда вообще не используется dpi -ware-манифест, но также и при использовании <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);
}