调整列表视图大小时如何设置标题宽度等于其列表视图控件宽度?

Posted

技术标签:

【中文标题】调整列表视图大小时如何设置标题宽度等于其列表视图控件宽度?【英文标题】:How to set header width equal to its list view control width when list view is resized? 【发布时间】:2019-08-25 10:57:06 【问题描述】:

当使用 win32 api 调整列表视图的大小时,我想将列表视图中标题的宽度设置为其列表视图控件的宽度。所以我使用ListView_SetColumnWidth() 将其宽度设置为等于其控件的宽度,但它不起作用。

这是WinMain()里面的代码:

InitCommonControls();
hwndList1 = CreateWindow(WC_LISTVIEW , L"" ,  WS_VISIBLE | WS_CHILD | LVS_REPORT | WS_BORDER  | WS_VSCROLL, 10 , 10 , width , height, hwnd, NULL, GetModuleHandle(NULL), 0); 

//Sub classing the list control
SetWindowSubclass(hwndList1 ,ListProc,0 ,NULL);

SendMessage(hwndList1,LVM_SETEXTENDEDLISTVIEWSTYLE,LVS_EX_FULLROWSELECT,LVS_EX_FULLROWSELECT);
hHeader1=ListView_GetHeader(hwndList1);

GetClientRect(hwndList1 , &rect1);
CreateColumn(hwndList1 , 0 , (char*)L"MASTER" , rect1.right );

//enable arrows
EnableScrollBar(hwndList1 , SB_VERT , ESB_ENABLE_BOTH);

//scroll down
SendMessage(hwndList1, WM_VSCROLL, SB_BOTTOM, 0L);

这是ListProc()

//the list proc
LRESULT CALLBACK ListProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,UINT_PTR, DWORD_PTR )
switch(msg)

    case WM_NOTIFY :
     if (((LPNMHDR) lp)->code == NM_CUSTOMDRAW)
     

         LPNMCUSTOMDRAW lpcd = (LPNMCUSTOMDRAW)lp;
         switch(lpcd->dwDrawStage)
         
            case CDDS_PREPAINT :
                return CDRF_NOTIFYITEMDRAW;
            case CDDS_ITEMPREPAINT:
            

                    SetBkColor(lpcd->hdc, RGB(0, 135, 234));
                    SetTextColor(lpcd->hdc, RGB(255, 255, 245));
                return CDRF_NEWFONT;
            
                break;
        
    

break;

    case WM_NCPAINT:
    
     RECT rc;
     GetWindowRect(hwnd, &rc);
     OffsetRect(&rc, -rc.left, -rc.top);
     auto hdc = GetWindowDC(hwnd);
     auto hpen = CreatePen(PS_SOLID, 1, RGB(201, 201, 201));
     auto oldpen = SelectObject(hdc, hpen);
     SelectObject(hdc, GetStockObject(NULL_BRUSH));
     Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
     SelectObject(hdc, oldpen);
     DeleteObject(oldpen);
     ReleaseDC(hwnd, hdc);
     return 0;
    

    case WM_NCDESTROY:
     RemoveWindowSubclass(hwnd, ListProc, 0);
     break;
 

 return DefSubclassProc(hwnd, msg, wp, lp);
  

父窗口过程的代码为WndProc()

//The window procedure
LRESULT CALLBACK WndProc( HWND hwnd , UINT msg , WPARAM wParam , LPARAM lParam)
  switch(msg)
   case WM_SIZE:
    int nHeight , nWidth;

    width =(int)((nWidth /2) * 0.8);
    height =(int)((nHeight/2) * 0.7);

    if( wParam == SIZE_RESTORED ) 

     SetWindowPos(hwndList1, 0 , 10, 10 , width, height,SWP_NOZORDER|SWP_NOMOVE); 

    RECT Rc;
    GetClientRect(hwndList1, &Rc);
    ListView_SetColumnWidth(hwndList1, 0, Rc.right - Rc.left);
    

    else if ( wParam == SIZE_MAXIMIZED )
     
        SetWindowPos(hwndList1, 0 , 20, 20, width, height,0); 
        RECT Rc;
        GetClientRect(hwndList1, &Rc);
        ListView_SetColumnWidth(hwndList1, 0, Rc.right - Rc.left);//
      
    
    break;
    case WM_NOTIFY:
    if(((LPNMHDR)lParam)->code == NM_CUSTOMDRAW) 
            LPNMLVCUSTOMDRAW  lplvcd = (LPNMLVCUSTOMDRAW)lParam;
            switch(lplvcd->nmcd.dwDrawStage) 
                case CDDS_PREPAINT:
                    return CDRF_NOTIFYITEMDRAW;

                case CDDS_ITEMPREPAINT:

                    if (((int)lplvcd->nmcd.dwItemSpec%2)==0) 
                        lplvcd->clrText   = RGB(0,0,0);
                        lplvcd->clrTextBk = RGB(255, 255, 255);
                     else 
                        lplvcd->clrText   = RGB(0,0,0);
                        lplvcd->clrTextBk = RGB(255,255,255);
                    
                    return CDRF_NEWFONT;

            

    
    return TRUE;

    case WM_COMMAND: 
     switch(LOWORD(wParam))
        case ID_FILE_EXIT:
            PostMessage(hwnd, WM_CLOSE , 0 , 0);
            break;
        case ID_ABOUT:
        
          int ret=DialogBox( GetModuleHandle(NULL) , MAKEINTRESOURCE(ID_ABOUT) , hwnd , AboutDlgProc );

        
        break;
     
     break;

    case WM_CLOSE:
     DestroyWindow( hwnd );
     break;

    case WM_DESTROY:
     PostQuitMessage(0);
     break;

    default:
     return DefWindowProc( hwnd , msg , wParam , lParam );
  
  return 0;
 

我错过了什么?还有其他方法吗?

谢谢!

【问题讨论】:

“但它不起作用。” 不是简明的问题描述。请在此处按要求发布minimal reproducible example。 哪个窗口的 WndProc() 的一部分?列表视图的父级?但是您首先在哪里调整列表视图的大小?或者你的子类列表视图,这是来自子类 proc ? @πάντα ῥεῖ 我更新了 WM_NOTIFY, WM_CTLCOLORSTATIC 被发送到父窗口,而不是窗口本身。所以在ListProcHeaderProc 中处理它的代码毫无意义。不清楚你的所有子类 - 在你的情况下不需要。为什么 SIZE_RESTOREDSIZE_MAXIMIZED 有两个不同的 if 而两者的代码相同? 您需要为SIZE_RESTOREDSIZE_MAXIMIZED 设置一个大小写,但不需要两个重复的代码。和 print (比如DbgPrint )来自WM_SIZE 案例的所有值,ListView_SetColumnWidth 的结果(可能是在ListView_GetColumnWidth 之后进行调试调用) - 这就是这个问题的研究方式跨度> 【参考方案1】:

使用GetClientRect 查找控件的内部矩形。示例:

case WM_SIZE:

    //resize the listview control first
    //calculate width/height
    SetWindowPos(hwndList1, NULL, 0, 0, width, height, SWP_NOZORDER|SWP_NOMOVE);

    RECT rc;
    GetClientRect(hwndList1, &rc);
    ListView_SetColumnWidth(hwndList1, 0, rc.right - rc.left);//rc.left is zero
    break;

客户矩形可以比窗口矩形小一点。

您可以使用宽度/高度来设置列表视图控件的大小,使用SetWindowPosMoveWindow。这将对应于GetWindowRect。但是你想要列宽的客户矩形。

您还可以子类化列表视图控件并在listview_proc 中响应WM_SIZE

WM_SIZE 在用户调整主窗口大小时发送。首次打开窗口时默认不触发。首次初始化窗口时,您可能需要调用ListView_SetColumnWidth


另请注意,您无法在ListProc 中处理自定义绘制。您必须从ListProc 中删除WM_NOTIFY 部分,仅将其添加到WndProc

建议修改:

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

    switch(msg)
    
    case WM_SIZE:
    
        int nWidth = LOWORD(lParam);
        int nHeight = HIWORD(lParam);
        int width = (int)((nWidth / 2) * 0.8);
        int height = (int)((nHeight / 2) * 0.7);
        SetWindowPos(hwndList1, 0, 20, 20, width, height, SWP_NOZORDER);
        RECT rc;
        GetClientRect(hwndList1, &rc);
        ListView_SetColumnWidth(hwndList1, 0, rc.right - rc.left);
    
    break;
    case WM_NOTIFY:
        if(((LPNMHDR)lParam)->code == NM_CUSTOMDRAW)
        
            LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;
            switch(lplvcd->nmcd.dwDrawStage)
            
            case CDDS_PREPAINT:
                return CDRF_NOTIFYITEMDRAW;
            case CDDS_ITEMPREPAINT:
                lplvcd->clrText = RGB(255, 0, 0);
                lplvcd->clrTextBk = RGB(255, 255, 0);
                return CDRF_NEWFONT;
            
        
        break;
    ...

【讨论】:

谢谢,但是当我最大化父窗口时它仍然不起作用,列表视图控件比标题更宽。我更新了有问题的代码,你能看看吗? 您似乎忘记在第二版代码中初始化nWidthnHeight。这将导致未定义的行为。建议将编译器的警告级别设置为 4 或更高。确保解决所有编译器警告,例如未初始化的变量。同时从ListProc中删除自定义抽奖 @Barmak:只是好奇,是否有关于删除自定义绘图的动机的信息,或者替代实现应该如何进行?谢谢。 :) @LaurieSearn 问题是关于调整标题的大小,它与自定义绘制无关,所以我建议删除自定义绘制部分以简化问题。否则在 ListView 控件中使用自定义绘制就可以了。

以上是关于调整列表视图大小时如何设置标题宽度等于其列表视图控件宽度?的主要内容,如果未能解决你的问题,请参考以下文章

当视图宽度发生变化时,如何使 UILabel 正确调整其尺寸?

键盘向上时如何调整列表视图的大小?

如何根据内容自动调整卡片视图的大小

如何设置约束,以使视图的宽度至少等于某个宽度时为0

UIView - 调整大小以适应内容

iOS 约束。如何通过约束设置图像视图高度比率等于图像比率?