2009-10-11 63 views
4

我有一個很大的對話框,有一個子窗口 - 一個列表控件。當對話框重新調整大小時,我會重新調整列表控件的大小;它基本上固定在對話框的所有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應用程序(甚至是那些由微軟寫的)採取一看後,他們中的每單一個遭受同樣閃爍的問題。從左上角的狀態欄和滾動條調整窗口大小時尤其明顯。我想我只能忍受它。

+0

我真的沒有任何閃爍(XP SP2,視覺風格開啓和關閉)。哪個版本的Windows具有閃爍,並且Visual風格是否打開(exe文件中的清單)? – Anders 2009-10-11 21:56:03

+0

XP SP3。我包含comctl32清單,但是我關閉了視覺樣式。嘗試從頂部/左側而不是右下角調整大小;那是閃爍最差的地方。 – Luke 2009-10-11 22:25:26

+0

是的,從頂部/左側調整大小給出了一個「反彈」,它發生在大多數Windows應用程序,但我沒有看到任何閃爍 – Anders 2009-10-12 14:55:01

回答

1

看過許多其他Windows應用程序(甚至是由Microsoft編寫的應用程序)之後,它們中的每一個應用程序都會遇到相同的閃爍問題。從左上角的狀態欄和滾動條調整窗口大小時尤其明顯。我想我只能忍受它。

+0

你是對的,甚至記事本(Word Wrap關閉)仍然會產生閃爍。但是,如果打開Word Wrap,閃爍將消失。 – dns 2014-01-08 08:04:16

2

很多閃爍來自WM_ERASEBKGRD,處理此消息並返回TRUE;

+0

子控件不覆蓋整個對話框,所以如果你忽略WM_ERASEBKGRD那麼對話框背景當它調整大小時從未被繪。 – Luke 2009-10-11 16:24:59

2

你可以做幾件事。

  • 自己處理WM_ERASE。您可能仍然需要清除一些背景,但是您可以在窗口邊緣繪製4個矩形,以填充對話框的背景區域,而不會在子控件位於中間的位置繪製矩形。

  • 在調用SetWindowPos之後,嘗試調用UpdateWindow()立即重新繪製窗口(在列表視圖控件和您自己的窗口上嘗試它)。這可以最大限度地縮短進行尺寸更改和重繪完成之間的時間。

  • 另一種方法是雙緩衝(您將整個窗口表面繪製到離屏位圖,並且只在完成時將其繪製到屏幕上,這樣可以最小化屏幕上更新proicess的開始和結束之間的時間,所以減少了閃爍,這很難通過對話框和窗口控制來實現,所以不適用於你的情況)。

  • 一般來說,不要害怕嘗試東西。嘗試以不同的順序進行操作等,看看結果如何。如果某些事情(如UpdateWindow())沒有提供明顯的改進,那麼很容易再次移除代碼,並嘗試其他方法,直到獲得最佳結果。

編輯 - 更多的想法

  • 也看到this SO question

  • 當更新控件,您還可以暫停和恢復重新粉刷(的BeginUpdate()和EndUpdate()),以阻止他們在添加多個項目時不止一次繪製等等。但這不可能幫助您調整窗口大小。

+0

處理WM_ERASEBKGRD沒有幫助;閃爍似乎在列表控制的處理過程中發生。 UpdateWindow()沒有效果;我認爲SetWindowPos()已經發送了一個WM_PAINT消息。 我想看看雙緩衝,但這似乎是一個控制的東西;似乎沒有辦法將雙緩衝整個對話框。 Windows資源管理器與我的對話框具有相同的行爲,所以如果微軟無法做到這一點,我想我只能忍受閃爍。 – Luke 2009-10-11 20:15:09

+0

嘗試WM_ERASE - WM_ERASEBKGRD可能會有不同的行爲(我在Win32中編寫了16年的用戶界面,並且從未聽說過或使用過WM_ERASEBKGRD)。另請參閱編輯我的答案。 – 2009-10-11 20:36:26