Post 5
Slightly more flexible code. Added highlight of selected item. Demonstrates listbox refresh.
How the code works? The $LBS_OWNERDRAWVARIABLE style means that the operating system sends WM_DRAWITEM messages when the listbox has to be updated. These messages are captured by AutoIt's internal message management system. For each message the management system executes the WM_DRAWITEM function.
To delete and add rows, update texts and change row heights, use _GUICtrlListBox_ and array functions. Normally you'll not update the code directly in the WM_DRAWITEM function.
#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiListBox.au3>
Global Const $Gdi32dll = DllOpen( "gdi32.dll" )
Global Const $User32dll = DllOpen( "user32.dll" )
; DRAWITEMSTRUCT
Global Const $tagDRAWITEMSTRUCT ="uint CtlType;uint CtlID;uint itemID;uint itemAction;uint itemState;hwnd hwndItem;handle hDC;dword rcItem[4];ptr itemData"
; CtlType
Global Const $ODT_LISTBOX = 2
; itemAction
Global Const $ODA_DRAWENTIRE = 0x1
Global Const $ODA_SELECT = 0x2
Global Const $ODA_FOCUS = 0x4
; itemState
Global Const $ODS_SELECTED = 0x1
Global $iRowHeight = 16, $iMargin = 4
Global $aRows = [ [ 2, "Row 0", " Subrow 2" ], _
[ 3, "Row 1", " Subrow 2", " Subrow 3" ], _
[ 2, "Row 2", " Subrow 2" ], _
[ 1, "Row 3" ], _
[ 4, "Row 4", " Subrow 2", " Subrow 3", " Subrow 4" ], _
[ 2, "Row 5", " Subrow 2" ], _
[ 3, "Row 6", " Subrow 2", " Subrow 3" ], _
[ 2, "Row 7", " Subrow 2" ], _
[ 1, "Row 8" ], _
[ 3, "Row 9", " Subrow 2", " Subrow 3" ] ]
Example()
Func Example()
GUICreate( "Ownerdrawn Listbox", 300, 340 )
Local $idListBox = GUICtrlCreateList( "", 10, 10, 280, 280, $WS_VSCROLL+$LBS_OWNERDRAWVARIABLE ), $hListBox = GUICtrlGetHandle( $idListBox )
Local $idButton = GUICtrlCreateButton( "Modify row 4", 10, 300, 280, 30 )
; Fill listbox rows and set row height
; This tells WM_DRAWITEM function how many rows to draw
For $i = 0 To UBound( $aRows ) - 1
_GUICtrlListBox_AddString( $idListBox, $aRows[$i][1] )
_GUICtrlListBox_SetItemHeight( $idListBox, $aRows[$i][0] * $iRowHeight + $iMargin, $i )
Next
GUIRegisterMsg( $WM_DRAWITEM, "WM_DRAWITEM" )
GUISetState( @SW_SHOW )
Local $n = 0
While 1
Switch GUIGetMsg()
Case $idButton
$n += 1
$aRows[4][1] = "Modified row 4 (" & $n & ")"
_WinAPI_InvalidateRect( $hListBox ) ; Refresh
Case $GUI_EVENT_CLOSE
ExitLoop
EndSwitch
WEnd
GUIDelete()
EndFunc
Func WM_DRAWITEM( $hWnd, $iMsg, $wParam, $lParam )
Local $tDRAWITEMSTRUCT = DllStructCreate( $tagDRAWITEMSTRUCT, $lParam )
Local $CtlType = DllStructGetData( $tDRAWITEMSTRUCT, "CtlType" )
If $CtlType <> $ODT_LISTBOX Then Return $GUI_RUNDEFMSG
Local $itemID = DllStructGetData( $tDRAWITEMSTRUCT, "itemID" )
Local $itemAction = DllStructGetData( $tDRAWITEMSTRUCT, "itemAction" )
Local $itemState = DllStructGetData( $tDRAWITEMSTRUCT, "itemState" )
Local $hDC = DllStructGetData( $tDRAWITEMSTRUCT, "hDC" )
Local $iBrushColor, $iTextColor, $DT_LEFT = 0
Switch $itemAction
Case $ODA_DRAWENTIRE, $ODA_SELECT
; Item state
If $itemState = $ODS_SELECTED Then
$iBrushColor = _WinAPI_GetSysColor( $COLOR_HIGHLIGHT )
$iTextColor = 0xFFFFFF
Else
$iBrushColor = ColorConvert( 0xEAEE97 )
$iTextColor = 0x000000
EndIf
; Item rectangle
Local $tRECT = DllStructCreate( $tagRECT, DllStructGetPtr( $tDRAWITEMSTRUCT, "rcItem" ) )
; Background color
DLLCall( $Gdi32dll, "int", "SetBkMode", "hwnd", $hDC, "int", 1 ) ; 1 = $TRANSPARENT
Local $aBrush = DLLCall( $Gdi32dll, "hwnd", "CreateSolidBrush", "int", $iBrushColor )
DLLCall( $Gdi32dll, "hwnd", "SelectObject", "hwnd", $hDC, "hwnd", $aBrush[0] )
DllStructSetData( $tRECT, "Bottom", DllStructGetData( $tRECT, "Bottom" ) - 1 )
DLLCall( $User32dll, "int", "FillRect", "hwnd", $hDC, "struct*", $tRECT, "hwnd", $aBrush[0] )
DLLCall( $Gdi32dll, "int", "DeleteObject", "hwnd", $aBrush[0] )
; Text color
DllCall( $Gdi32dll, "int", "SetTextColor", "hwnd", $hDC, "int", $iTextColor )
; Left margin
DllStructSetData( $tRECT, "Left", DllStructGetData( $tRECT, "Left" ) + 4 )
; Item text 1
Local $sItemText = $aRows[$itemID][1]
DllStructSetData( $tRECT, "Top", DllStructGetData( $tRECT, "Top" ) + 2 )
DllStructSetData( $tRECT, "Bottom", DllStructGetData( $tRECT, "Top" ) + $iRowHeight )
DllCall( $User32dll, "int", "DrawText", "hwnd", $hDC, "str", $sItemText, "int", StringLen( $sItemText ), "struct*", $tRECT, "int", $DT_LEFT )
; Item text 2 - last column
For $i = 2 To UBound( $aRows, 2 ) - 1
If $aRows[$itemID][$i] Then
$sItemText = $aRows[$itemID][$i]
DllStructSetData( $tRECT, "Top", DllStructGetData( $tRECT, "Bottom" ) )
DllStructSetData( $tRECT, "Bottom", DllStructGetData( $tRECT, "Top" ) + $iRowHeight )
DllCall( $User32dll, "int", "DrawText", "hwnd", $hDC, "str", $sItemText, "int", StringLen( $sItemText ), "struct*", $tRECT, "int", $DT_LEFT )
EndIf
Next
EndSwitch
Return $GUI_RUNDEFMSG
#forceref $hWnd, $iMsg, $wParam
EndFunc
;RGB to BGR or BGR to RGB
Func ColorConvert($iColor)
Return BitOR(BitAND($iColor, 0x00FF00), BitShift(BitAND($iColor, 0x0000FF), -16), BitShift(BitAND($iColor, 0xFF0000), 16))
EndFunc