AnimateWindow () неправильно рисует фон с высоким разрешением (Win10) - PullRequest
1 голос
/ 09 марта 2019

Я создаю простое приложение Win32 / MFC с главным окном и дочерним окном, которое использует AnimateWindow(), чтобы показать (сдвинуть вверх) и скрыть (сдвинуть вниз) окно. При запуске приложения с масштабированием 100% dpi все работает нормально.

Child window shown

Я переопределил WM_ERASEBKGND для отображения случайного красного цвета, чтобы продемонстрировать эффект. Когда окно скользит вниз (скрывается) на каждом «шаге» анимации, «прямоугольник обновления» фона перерисовывается в том месте, где исчезло дочернее окно, и фон должен снова стать видимым.

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

Однако при изменении dpi-масштабирования через настройки Windows (в данном случае до 125%) неверная область перерисовывается. Похоже, что область, переданная в OnEraseBkgnd(), все еще использует размер 100% dpi-масштабирования, но также и позиция выключена: это выглядит так, как будто позиция x / y верхнего левого угла пройдена в экранном пространстве вместо клиентского пространства. Таким образом, область перерисовки выглядит по-разному, в зависимости от того, где на экране расположено окно.

Update-rectangle with wrong size and position

Белая область - это то место, где на самом деле было расположено дочернее окно, и где в действительности должно было произойти перерисовка фона.

Я подтвердил этот эффект на Win10 (1803 и 1809) и на Win8.1 Это ошибка в ОС или есть что-то, что я могу сделать, чтобы избежать проблемы, кроме использования AnimateWindow()? ShowWindow()SW_SHOW или SW_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);
}
...