WM_SETREDRAW阻止显示所有者绘制的Listview标题

时间:2017-09-21 16:36:25

标签: listview winapi header ownerdrawn

我遵循了使用WM_SETREDRAW而不是LockWindowUpdate()的建议,以在填充项目时抑制listview更新。在发送带有true的WM_SETREDRAW消息后,我发现我的标题行没有显示。 InvalidateRect()和UpdateWindow()组合或RedrawWindow()无法显示所有者绘制的标题。要显示标题行,我需要通过调整列表视图大小或滚动列表视图来手动强制新的WM_PAINT消息。 此行为仅限于所有者绘制的标题。如果我没有继承Header过程,则在使用true发送WM_SETREDRAW消息后,本机Window过程只显示标题行。 任何人都可以建议我的代码中缺少什么吗?

注意:

  1. 使用WM_SETREDRAW证明比LockWindowUpdae()更有效。 对于一个大的列表,填充项目并显示它们需要1.9秒 使用LockWindowUpdate()时,而不是9.6秒。我希望我可以 使用WM_SETREDRAW正确显示标题以从中受益 更好的表现。
  2. 创建列表视图而不添加项目(而不是发送 WM_SETREDRAW msg),本机Windows程序显示Header,但是 在我手动移动或移动之前,子类程序不显示它 调整窗口大小。 InvalidRect()/ UpdateWindow()无效。
  3. 以下是子类化的代码:

    static LONG_PTR   DefaultHeaderProc ;
    static char* HeaderText[] = {"A","B","C","D","E","F","G","H","I","J",
                                 "K","L","M","N","O","P","Q","R","S","T"} ;
    
    LRESULT CALLBACK ListDlgProc (HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)
    {
    static HWND     hwndHeader ;
    static HWND     hwndListView ;
    
    
    switch (msg)  {
    
        case WM_INITDIALOG :
    
            hwndListView = GetDlgItem (hDlg,IDC_LISTVIEW) ;
            hwndHeader   = ListView_GetHeader (hwndListView) ;
    
            ListView_SetExtendedListViewStyle (hwndListView,LVS_EX_GRIDLINES | 
                        LVS_EX_TRANSPARENTBKGND |LVS_EX_FULLROWSELECT) ;
    
            SendMessage (hwndListView,LVM_SETBKCOLOR,0,(LPARAM) 0xE0E0E0) ;
            SendMessage (hwndListView,LVM_SETTEXTCOLOR,0,(LPARAM) 0xC00000) ;
    
            // Initialize the LVCOLUMN structure. 
            LVCOLUMN    LvColumn ;
            ZeroMemory (&LvColumn,sizeof (LVCOLUMN)) ;
            LvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM | LVCF_TEXT ; 
            LvColumn.fmt = LVCFMT_LEFT ;
            LvColumn.cx = 63  ;
    
            // Add the columns 
            for (int i = 0 ; i < COLUMNS ; i++) { 
                LvColumn.pszText = HeaderText[i] ;
                LvColumn.iSubItem = i ; 
                if (ListView_InsertColumn(hwndListView,i,&LvColumn) == -1) 
                    return false ; 
            } /* for (int i = 0 ; i < COLUMNS ; i++) */
    
            DefaultHeaderProc = SetWindowLongPtr (hwndHeader,GWLP_WNDPROC,
                                     (LONG_PTR) HeaderSubclassProc) ;
            SendMessage (hwndHeader,IDM_INIT,0,0L) ;
            return true ;
    
        case WM_DESTROY :
            SetWindowLongPtr (hwndHeader,GWLP_WNDPROC,(LONG_PTR) DefaultHeaderProc) ;
            SetWindowLongPtr (hwndListView,GWLP_WNDPROC,(LONG_PTR) DefaultListViewProc) ;
            ListView_DeleteAllItems (hwndListView) ;
            return 0 ;
           ;
    

    以下是WM_PAINT处理的代码:

        case WM_PAINT :
            PAINTSTRUCT ps ;
            hDC = BeginPaint (hwnd,&ps) ;
    
            int DefDC = SaveDC (hDC) ;
    
            SelectObject (hDC,Font) ;
            SelectObject (hDC,Pen) ;
            SelectObject (hDC,Brush) ;
            SetBkMode (hDC,TRANSPARENT) ;
    
            for (int Btn = 0 ; Btn < 20 ; Btn++) {
                if (Btn == HBtn)
                    continue ;
                Header_GetItemRect (hwnd,Btn,&rc) ;
                Rectangle (hDC,rc.left,rc.top,rc.right + 1,rc.bottom) ;
                DrawText (hDC,HeaderText[Btn],-1,&rc,DT_CENTER | DT_VCENTER) ;
            } /* for (int Btn = 0 ; Btn < 20 ; Btn++) */
    
            if (HBtn > -1 ) {
                Header_GetItemRect (hwnd,HBtn,&rc) ;
                SelectObject (hDC,HPen) ;
                SelectObject (hDC,HBrush) ;
                Rectangle (hDC,rc.left + 1,rc.top + 1,rc.right,rc.bottom - 1) ;
                DrawText (hDC,HeaderText[HBtn],-1,&rc,DT_CENTER | DT_VCENTER) ;
            } /* if (HLBtn > -1 ) */
    
            RestoreDC (hDC,DefDC) ;
            EndPaint (hwnd,&ps) ;
            return 0 ;
    

    HBtn是&#34; hot&#34;的热度指数。鼠标悬停在标题

    上时的标题列

1 个答案:

答案 0 :(得分:0)

我尝试使用wParam = SIZE_RESTORED和lParam =自己的大小将WM_SIZE发送到Header窗口,发现Header行显示正确。

感谢Remy Lebeau,我用WM_SETREDRAW替换了LockWindowUpdate()并改进了大型列表的性能。我阅读了关于LockWindowUpdate()的Raymond Chen文章,并了解WM_SETREDRAW对于listview控件的性能提升来自于绕过“复杂的屏幕计算”。使用子类程序,需要重做一些计算。发送WM_SIZE与调整窗口大小的工作相同。控件显示完美,无需调用InvalidateRect()/ UpdateWindow()。

注意:我使用SetWindowLongPtr()将子类化方法更改为使用SetWindowSubclass(),但对我的Header显示问题没有影响。 我正在使用所有20个子项对列表进行排序,因此使用虚拟列表不是一种选择。