2017-09-19 60 views
0

我使用下面的代碼來創建Windows ListView標題控件的子類。我的程序工作正常,對鼠標懸停在標題控件上的響應很好。如何立即顯示Ownerdrawn Listview標題行

我的問題是,當我創建的「第一次」的大名單,標題行不顯示,直到該列表是完全填充:

Header line during loading big list 1st time

然後,如果我刪除打開的列表並創建一個新的,甚至相同的舊人,標題行立即顯示,而不是等待要完成的列表:

Header line during loading big list 2nd time

如果我不繼承頭控制,本地W¯¯ indows過程總是立即顯示標題行,而不是等待列表完成,但隨後我失去了自定義。

任何建議我缺少讓標題行立即顯示?

注:

我開始前和結束添加列表視圖項後調用LockWindowUpdate()。我試圖不打電話LockWindowUpdate(),但結果是即使完成添加所有項目後,標題行仍未顯示,它將等待,直到我強制將新的WM_PAINT msg通過將鼠標移動到標題行上。

這裏是我的子類功能:

static char* HeaderText[20] = {"A","B","C","D","E","F","G","H","I","J", 
           "K","L","M","N","O","P","Q","R","S","T"} ; 


LRESULT APIENTRY HeaderSubclassProc (HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)       
{ 
static int  y ; 
static int  xe ; 
static int  xr ; 
static int  HBtn = -1 ; 
static RECT Hrc ; 
static HPEN Pen ; 
static HPEN HPen ; 
static HBRUSH Brush ; 
static HBRUSH HBrush ; 
static TRACKMOUSEEVENT tme = {sizeof (TRACKMOUSEEVENT),TME_LEAVE,NULL, 
           HOVER_DEFAULT} ; 
HDC  hDC ; 

switch (msg) { 
    RECT rc ; 

    case IDM_INIT : 
     Pen = CreatePen (PS_SOLID,0,0xF2F2F2) ; 
     HPen = CreatePen (PS_SOLID,0,0xF88420) ; 
     Brush = CreateSolidBrush (0xD2D2D2) ; 
     HBrush = CreateSolidBrush (0xFFEFE0) ; 
     Header_GetItemRect (hwnd,19,&rc) ; 
     xr = rc.right ; 
     tme.hwndTrack = hwnd ; 
     return 0 ; 

    case WM_CLOSE : 
     DeleteObject (Pen) ; 
     DeleteObject (HPen) ; 
     DeleteObject (Brush) ; 
     DeleteObject (HBrush) ; 
     return 0 ; 

    case WM_SIZE : 
     TEXTMETRIC tm ; 
     hDC = GetDC (hwnd) ; 
     GetTextMetrics (hDC,&tm) ; 
     ReleaseDC (hwnd,hDC) ; 
     Header_GetItemRect (hwnd,0,&rc) ; 
     y = (rc.bottom - rc.top - tm.tmHeight)/2 + tm.tmAscent ; 
     xe = LOWORD (lParam) ; 
     break ; 

    case WM_MOUSELEAVE : 
     HBtn = -1 ; 
     InvalidateRect (hwnd,&Hrc,true) ; 
     return 0 ; 

    case WM_MOUSEMOVE : 
     int x ; 
     x = LOWORD (lParam) ; 
     if (HBtn > -1 && x > xr) { 
      HBtn = -1 ; 
      InvalidateRect (hwnd,&Hrc,true) ; 
      break ; 
     } /* if (HLBtn == 19 && x > xr) */ 
     for (int Btn = 0 ; Btn < 20 ; Btn++) { 
      Header_GetItemRect (hwnd,Btn,&rc) ; 
      if (x > rc.left && x < rc.right) { 
       if (Btn == HBtn) 
        break ; 
       HBtn = Btn ; 
       Hrc = rc ; 
       InvalidateRect (hwnd,NULL,true) ; 
       break ; 
      } /* if (x > rc.left && x < rc.right) */ 
     } /* for (int Btn = 0 ; Btn < 20 ; Btn++) */ 
     TrackMouseEvent (&tme) ; 
     break ; 

    case WM_PAINT : 
     PAINTSTRUCT ps ; 
     hDC = BeginPaint (hwnd,&ps) ; 
     int DefDC = SaveDC (hDC) ; 

     SelectObject (hDC,Pen) ; 
     SelectObject (hDC,Brush) ; 
     SetTextAlign (hDC,TA_BASELINE | TA_CENTER) ; 
     SetBkMode (hDC,TRANSPARENT) ; 

     for (int Btn = 0 ; Btn < 20 ; Btn++) { 
      if (Btn == HBtn) 
       continue ; 
      Header_GetItemRect (hwnd,Btn,&rc) ; 
      int x = (rc.right + rc.left)/2 ; 
      Rectangle (hDC,rc.left,rc.top,rc.right + 1,rc.bottom) ; 
      ExtTextOut (hDC,x,y,ETO_NUMERICSLATIN,&rc,HeaderText[Btn], 
          (UINT) strlen (HeaderText[Btn]),NULL) ; 
     } /* for (int Btn = 0 ; Btn < 20 ; Btn++) */ 
     Rectangle (hDC,rc.right,rc.top,xe,rc.bottom) ; 

     if (HBtn > -1) { 
      Header_GetItemRect (hwnd,HBtn,&rc) ; 
      x = (rc.right + rc.left)/2 ; 
      SelectObject (hDC,HPen) ; 
      SelectObject (hDC,HBrush) ; 
      Rectangle (hDC,rc.left + 1,rc.top + 1,rc.right,rc.bottom - 1) ; 
      ExtTextOut (hDC,x,y,ETO_NUMERICSLATIN,&rc,HeaderText[HBtn], 
          (UINT) strlen (HeaderText[HBtn]),NULL) ; 
     } /* if (HLBtn > -1) */ 

     RestoreDC (hDC,DefDC) ; 
     EndPaint (hwnd,&ps) ; 
     return 0 ; 

} /* switch (msg) */ 

return CallWindowProc ((WNDPROC) DefaultHeaderProc,hwnd,msg,wParam,lParam) ; 

} /* HeaderSubclassProc */ 
+0

也許你需要以某種方式使列表失效? – VuVirt

回答

2

你絕對不應該使用LockWindowUpdate()在所有的(有上Raymond Chen's blog解釋爲什麼許多文章)。

正確的解決辦法是發送ListView的一個WM_SETREDRAW消息禁用其拉伸,直到你與你的更新完成,然後再發送WM_SETREDRAW重新啓用繪圖,終於引發重繪與InvalidateRect()/UpdateWindow(),或RedrawWindow()

或者,use the ListView in virtual mode,特別是如果你打算展示很多物品。

+0

我試過WM_SETREDRAW並沒有解決問題。它再次適用於本機Windows標頭過程,但不適用於子標頭。它甚至使問題惡化,因爲在完成列表後,我無法以編程方式重新繪製標題。 InvalidateRect()/ UpdateWindow()和RedrawWindow()未能顯示標題。我必須手動覆蓋/揭開窗口才能顯示標題。我相信WM_PAINT的子類處理中缺少某些東西,但無法弄清楚。 – makhlouf

+0

您沒有展示如何子類化ListView標題,或者如何填充ListView項目。 –