No announcement yet.

Size of the built-in arrow in the header of a ListView control

  • Filter
  • Time
  • Show
Clear All
new posts

  • Size of the built-in arrow in the header of a ListView control

    Starting with Windows XP (Comctl32.dll version 6) there is a very simple method to draw an up-arrow or down-arrow in the header of a ListView control.

    We just need to add a flag HDF_SORTDOWN for a down-arrow or HDF_SORTUP for an up-arrow, in the fmt field of the HDITEM structure.

    This point was discussed in this thread:

    To size the width of the columns correctly i.e. to be sure the columns are large enough including the header string and the arrow, I would like to know if there is a function that can return either:

    - The size of the column header including the arrow

    I tried the API ListView_SetColumnWidth() with %LVSCW_AUTOSIZE or %LVSCW_AUTOSIZE_USEHEADER with no success; the arrow are never included.

    Is-there any simple algorithm to compute the column width including the header text, the arrow and the necessary padding spaces.

    Thank a lot.
    Jean-Pierre LEROY

  • #2
    The HDF_SORTDOWN and HDF_SORTUP flags in a HDITEM structure do not respect the text in a column header as far as I can ascertain. If the column is too narrow for the text in the header, or specifically if LVM_SETCOLUMNWIDTH is called with LVSCW_AUTOSIZE, the text is truncated and the sort arrow displayed instead.

    As this seems to be default behaviour, I have not bothered trying to refine this. What you could do, though, is estimate or calculate what the minimum width of each column should be to allow for the text and the sort arrow. Then after a column header has been clicked, call LVM_SETCOLUMNWIDTH on that column with the pre-defined or calculated value to resize it.

    Calling the GetTextExtentPoint32 function will give you the width of the text in logical units.

    There is a HDF_FIXEDWIDTH flag which will lock the width of the column. However, it requires Vista.


    • #3

      Thank for your answer.

      To get the width of the column header I use the API ListView_GetStringWidth that returns the exact width in pixels of the specified string; then I use this value to set the column width with the ListView_SetColumnWidth.

      As mention in MSDN I have to add padding to the returned string width to be sure the header will not be truncating; nothing was mentionned clearly in the MSDN reference, but I found that if I had 15 pixels it was correct.

      For the size of the built-in arrow, I tried different values to be sure that the text is not truncated and the sort arrow displayed also; this size of the built-in arrow seems to be relative to the size of font; here is the function that I use now; I'm pretty sure there are more convenient and elegant way to do that?

      Sub ListView_ResizeAllColumnsWithArrows(ByVal hWndListView As Dword, _
                                              ByVal pWithArrow   As Long )
          Local lColumn As Long
          Local wc      As Long
          Local wc1     As Long
          Local wc2     As Long
          ' header variables
          Local hHeader     As Dword
          Local lHeaderText As Asciiz*32 
          Local HDI         As HD_ITEM
          'get a handle to the listview header component
          hHeader        = SendMessage(hWndListView, %LVM_GetHeader, 0, ByVal 0)
          ' prepare the HDI structure    
          HDI.mask       = %HDI_TEXT
          HDI.pszText    = VarPtr(lHeaderText)
          HDI.cchTextMax = SizeOf(lHeaderText)                  
          ' Set Redraw --> Off        
          SendMessage hWndListView, %WM_SETREDRAW, %FALSE, 0
          ' to set all the columns of the ListView    
          For lColumn = 0 ListView_GetColumnCount(hWndListView)-1 
              ' to retrieve the header text of the column
              Header_GetItem(hHeader, lColumn, HDI)               
              ' Size each column based on the width of the widest list item in the column.
              ListView_SetColumnWidth hWndListView, lColumn, %LVSCW_AUTOSIZE
              wc1 = ListView_GetColumnWidth( hWndListView, lColumn )
              ' Size each column based on the maximum of the column header text width + 15 pixels for padding ?        
              wc2 = ListView_GetStringWidth(hWndListView,lHeaderText)+15
              ' the padding spaces for the up-arrow or down-arrow 
              ' on the column header seems to be relative to the size of the font ?
              ' 27 pixels for MS Sans Serif size  8 
              ' 30 pixels for MS Sans Serif size 10
              ' 34 pixels for MS Sans Serif size 12
              ' 38 pixels for MS Sans Serif size 14
              ' 43 pixels for MS Sans Serif size 18
              ' 51 pixels for MS Sans Serif size 24
              If pWithArrow = %TRUE Then wc2 = wc2 + 27
              ' Size the column based on the max
              wc = Max(wc1,wc2)
              ListView_SetColumnWidth hWndListView, lColumn, wc
          Next col                      
          ' Set Redraw --> On
          SendMessage hWndListView, %WM_SETREDRAW, %TRUE, 0
          InvalidateRect hWndControl, ByVal %Null, %TRUE
          UpdateWindow hWndControl
      End Sub
      Last edited by Jean-Pierre LEROY; 9 Oct 2009, 04:06 PM.
      Jean-Pierre LEROY