Как устранить мерцание в значительном диалоге? - PullRequest
3 голосов
/ 11 октября 2009

У меня есть значительный диалог с одним дочерним окном - элементом управления списком. Когда размер диалогового окна изменяется, я соответствующим образом изменяю размер элемента управления списком; это в основном привязано ко всем 4 краям диалога. Проблема заключается в том, что во время изменения размера по краям элемента управления списка заметно мерцание, особенно при наличии полос прокрутки. Я новичок в Win32 GUI, поэтому я не знаю, как с этим справиться. Я видел много статей о рисовании без мерцания, но все они посвящены отдельным нарисованным элементам управления, и ни одна из них не касается рисования диалога без мерцания в целом. Как я могу заставить это работать без особого мерцания?

В моем реальном диалоговом окне, очевидно, имеется несколько элементов управления, но здесь приведен минимальный пример кода, который воспроизводит проблему (IDC_LIST1 - это элемент управления списком в представлении отчета, в IDD_DIALOG2 установлен стиль WS_CLIPCHILDREN).

#define NUM_COLUMNS  8
#define NUM_ROWS    32

RECT rcDialog2WindowOriginal;
RECT rcDialog2ClientOriginal;
RECT rcList1ClientOriginal;

INT_PTR Dialog2_OnInitDialog(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
    GetWindowRect(hDlg, &rcDialog2WindowOriginal);
    GetClientRect(hDlg, &rcDialog2ClientOriginal);
    GetWindowRect(GetDlgItem(hDlg, IDC_LIST1), &rcList1ClientOriginal);
    ScreenToClient(hDlg, ((LPPOINT)&rcList1ClientOriginal));
    ScreenToClient(hDlg, ((LPPOINT)&rcList1ClientOriginal) + 1);
    SendDlgItemMessage(hDlg, IDC_LIST1, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
    TCHAR szText[32];
    // add some columns
    LVCOLUMN col;
    ZeroMemory(&col, sizeof(LVCOLUMN));
    col.mask = LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
    col.cx = 60;
    col.pszText = szText;
    for(int i = 0; i < NUM_COLUMNS; i++)
    {
        col.iSubItem = i;
        _stprintf_s(szText, 32, _T("Column %d"), col.iSubItem);
        SendDlgItemMessage(hDlg, IDC_LIST1, LVM_INSERTCOLUMN, col.iSubItem, LPARAM)&col);
    }
    // add some items
    LVITEM item;
    ZeroMemory(&item, sizeof(LVITEM));
    item.mask = LVIF_TEXT;
    item.pszText = szText;
    for(int i = 0; i < NUM_ROWS; i++)
    {
        item.iItem = i;
        for(int j = 0; j < NUM_COLUMNS; j++)
        {
            item.iSubItem = j;
            _stprintf_s(szText, 32, _T("Item %d, SubItem %d"), i, j);
            if(j == 0)
            {
                SendDlgItemMessage(hDlg, IDC_LIST1, LVM_INSERTITEM, 0, (LPARAM)&item);
            }
            else
            {
                SendDlgItemMessage(hDlg, IDC_LIST1, LVM_SETITEM, 0, (LPARAM)&item);
            }
        }
    }
    // autosize the columns
    for(int i = 0; i < NUM_COLUMNS; i++)
    {
        SendDlgItemMessage(hDlg, IDC_LIST1, LVM_SETCOLUMNWIDTH, i, LVSCW_AUTOSIZE);
    }
    return TRUE;
}

INT_PTR Dialog2_OnGetMinMaxInfo(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
    LPMINMAXINFO lpMinMaxInfo = (LPMINMAXINFO)lParam;
    // don't allow dialog to be resized smaller than original size
    lpMinMaxInfo->ptMinTrackSize.x = rcDialog2WindowOriginal.right - rcDialog2WindowOriginal.left;
    lpMinMaxInfo->ptMinTrackSize.y = rcDialog2WindowOriginal.bottom - rcDialog2WindowOriginal.top;
    return TRUE;
}

INT_PTR Dialog2_OnSize(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
    int cx = LOWORD(lParam);
    int cy = HIWORD(lParam);
    // anchor the list control to all edges of the dialog
    int left_delta = rcList1ClientOriginal.left - rcDialog2ClientOriginal.left;
    int right_delta = rcDialog2ClientOriginal.right - rcList1ClientOriginal.right;
    int top_delta = rcList1ClientOriginal.top - rcDialog2ClientOriginal.top;
    int bottom_delta = rcDialog2ClientOriginal.bottom - rcList1ClientOriginal.bottom;
    int left = left_delta;
    int top = top_delta;
    int width = cx - left_delta - right_delta;
    int height = cy - top_delta - bottom_delta;
    HWND hWndList1 = GetDlgItem(hDlg, IDC_LIST1);
    SetWindowPos(hWndList1, NULL, left, top, width, height, SWP_NOZORDER);
    return TRUE;
}

INT_PTR Dialog2_OnClose(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
    EndDialog(hDlg, IDOK);
    return TRUE;
}

INT_PTR CALLBACK Dialog2_DialogProc(HWND hDlg, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
    switch(nMsg)
    {
    case WM_INITDIALOG:
        return Dialog2_OnInitDialog(hDlg, wParam, lParam);
    case WM_GETMINMAXINFO:
        return Dialog2_OnGetMinMaxInfo(hDlg, wParam, lParam);
    case WM_SIZE:
        return Dialog2_OnSize(hDlg, wParam, lParam);
    case WM_CLOSE:
        return Dialog2_OnClose(hDlg, wParam, lParam);
    }
    return FALSE;
}

Обновление

Взглянув на многие другие приложения Windows (даже написанные Microsoft), у каждого из них возникают те же проблемы с мерцанием. Это особенно заметно при изменении размера окна с панелью состояния и полосой прокрутки слева вверху. Я думаю, мне просто придется с этим смириться.

Ответы [ 3 ]

2 голосов
/ 11 октября 2009

Вы можете сделать несколько вещей.

  • Обрабатывайте WM_ERASE самостоятельно. Возможно, вам все же придется стереть часть фона, но вы можете нарисовать 4 прямоугольника по краям окна, чтобы заполнить фоновую область диалога, не перерисовывая прямоугольник в середине, где находится ваш дочерний элемент управления.

  • После вызова SetWindowPos попробуйте вызвать UpdateWindow (), чтобы немедленно перекрасить окно (попробуйте сделать это как в элементе управления представлением списка, так и в своем собственном окне). Это минимизирует время между изменением размера и завершением перерисовки.

  • Другой подход - двойная буферизация (вы рисуете всю поверхность окна в закадровом растровом изображении и выводите ее на экран только после того, как все закончено. Это минимизирует время между началом и окончанием обновления обновления на экране , так что уменьшает мерцание. Это труднее достичь с помощью диалогового окна и оконного элемента управления, хотя, так что не очень применимо в вашем случае).

  • В общем, не бойтесь экспериментировать с вещами. Попробуйте делать вещи в разных порядках и т. Д. И посмотрите, каковы результаты. Если что-то (например, UpdateWindow ()) не дает заметного улучшения, тогда легко снова удалить код и попробовать что-то еще, пока не получите наилучшие результаты.

edit - дополнительные идеи

  • см. Также этот вопрос SO

  • При обновлении элементов управления вы также можете приостановить и возобновить перекрашивание (BeginUpdate () и EndUpdate ()), чтобы остановить их рисование более одного раза, когда вы добавляете много элементов и т. Д. Это вряд ли поможет с изменением размера окна хотя.

2 голосов
/ 11 октября 2009

Много мерцания исходит от WM_ERASEBKGRD, обработайте это сообщение и просто верните TRUE;

1 голос
/ 05 января 2010

Взглянув на многие другие приложения Windows (даже написанные Microsoft), у каждого из них возникают те же проблемы с мерцанием. Это особенно заметно при изменении размера окна с панелью состояния и полосой прокрутки слева вверху. Думаю, мне просто придется с этим жить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...