Jump to content

Custom drawn TreeViews and ListViews


LarsJ
 Share

Recommended Posts

weirddave, any approach can work depending on what you're trying to achieve. I am not sure what the maximum number of listview items is, but it is possible to check the value beforehand for example and then set the text/bg colour based on value.

I modified my example a bit. Now when you press the Add button it adds the item with a random letter (c or d) in Column 2 and colours it based on the value:

#include <GUIConstants.au3>
#include <WindowsConstants.au3>
#include <FontConstants.au3>
#include <GuiListView.au3>
#include <WinAPI.au3>

Global $idLast1 = -1, $idLast2 = -1 ; Last and second last row
$MyGUI = GUICreate("listview items", 320, 200, 0,-1, -1)
_WinAPI_SetClassLongEx($MyGUI, -26, BitAND(_WinAPI_GetClassLongEx($MyGUI, -26), BitNOT(1), BitNOT(2)))
$idListview = GUICtrlCreateListView("A|B|C", 10, 10, 250, 155, 0x200)
_GUICtrlListView_SetExtendedListViewStyle($idListview, $LVS_EX_DOUBLEBUFFER)

$hLV = ControlGetHandle($MyGUI, "", $idListview)
$idButton = GUICtrlCreateButton("Add", 125, 175, 70, 20)
$hListview = GUICtrlGetHandle( $idListview )

$hDC = _WinAPI_GetDC($hLV)
$hFont = _SendMessage($hLV, $WM_GETFONT)
$hObject = _WinAPI_SelectObject($hDC, $hFont)
$lvLOGFONT = DllStructCreate($tagLOGFONT)
$aRet = DllCall('gdi32.dll', 'int', 'GetObjectW', 'ptr', $hFont, 'int', DllStructGetSize($lvLOGFONT), 'ptr', DllStructGetPtr($lvLOGFONT))
_WinAPI_SelectObject($hDC, $hObject)
_WinAPI_ReleaseDC($hLV, $hDC)
$hLVfont = _WinAPI_CreateFontIndirect($lvLOGFONT)
$iWeight = BitOR( DllStructGetData($lvLOGFONT, "Weight"), $FW_BOLD)
DllStructSetData( $lvLOGFONT, "Weight", $iWeight)
$hLVfontBold = _WinAPI_CreateFontIndirect($lvLOGFONT)

GUIRegisterMsg( $WM_NOTIFY, "WM_NOTIFY" )
GUISetState(@SW_SHOW)

while 1
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
            ExitLoop
        Case $idButton
        $Letter = Chr(Random(Asc("c"), Asc("d"), 1))
        $idLast1 = GUICtrlCreateListViewItem("a|b|"&$Letter, $idListview)
        $itemcount = _GUICtrlListView_GetItemCount( $hListview ) - 1
        _GUICtrlListView_RedrawItems( $hListview, $itemcount, $itemcount)
    EndSwitch
wend

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam
    Local $tNMHDR, $hWndFrom, $iCode
    $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iCode = DllStructGetData($tNMHDR, "Code")

    Switch $hWndFrom
        Case $hLV
            Switch $iCode
                Case $NM_CUSTOMDRAW
                    Local $tNMLVCUSTOMDRAW = DllStructCreate($tagNMLVCUSTOMDRAW, $lParam)
                    Local $dwDrawStage = DllStructGetData($tNMLVCUSTOMDRAW, "dwDrawStage")
                    Switch $dwDrawStage
                        Case $CDDS_PREPAINT
                            Return $CDRF_NOTIFYITEMDRAW
                        Case $CDDS_ITEMPREPAINT
                            Return $CDRF_NOTIFYSUBITEMDRAW
                        Case BitOR( $CDDS_ITEMPREPAINT, $CDDS_SUBITEM )
                            Local $iSubItem = DllStructGetData($tNMLVCUSTOMDRAW, "iSubItem")
                            Local $dwItemSpec = DllStructGetData($tNMLVCUSTOMDRAW, "dwItemSpec")
                            Local $hDC = DllStructGetData($tNMLVCUSTOMDRAW, "HDC")
                            Switch $iSubItem
                                Case 2
                                    _WinAPI_SelectObject($hDC, $hLVfont)
                                    If _GUICtrlListView_GetItemText($hLV, $dwItemSpec, $iSubItem) = "c" Then
                                        DllStructSetData( $tNMLVCUSTOMDRAW, "ClrText", ColorConvert(0x000000))
                                        DllStructSetData( $tNMLVCUSTOMDRAW, "ClrTextBk", ColorConvert(0x01DF01))
                                    ElseIf _GUICtrlListView_GetItemText($hLV, $dwItemSpec, $iSubItem) = "d" Then
                                        DllStructSetData( $tNMLVCUSTOMDRAW, "ClrText", ColorConvert(0x000000))
                                        DllStructSetData( $tNMLVCUSTOMDRAW, "ClrTextBk", ColorConvert(0xFF0000))
                                    EndIf
                                Case Else
                                    _WinAPI_SelectObject($hDC, $hLVfont)
                                    DllStructSetData( $tNMLVCUSTOMDRAW, "ClrText", ColorConvert(0x000000))
                                    DllStructSetData( $tNMLVCUSTOMDRAW, "ClrTextBk", ColorConvert(0xFFFFFF))
                            EndSwitch
                            Return $CDRF_NEWFONT
                    EndSwitch
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc

Func ColorConvert($iColor)
    Return BitOR(BitAND($iColor, 0x00FF00), BitShift(BitAND($iColor, 0x0000FF), -16), BitShift(BitAND($iColor, 0xFF0000), 16))
EndFunc
Link to comment
Share on other sites

Dumb question time, Is WM_NOTIFY recalculating the colour for each item every time based on 'c' or 'd', Or is the subitem actually having its colour set once and remembered? My earlier efforts seemed to suggest they were all being calculated every time.

Cheers

Link to comment
Share on other sites

Dumb question time, Is WM_NOTIFY recalculating the colour for each item every time based on 'c' or 'd', Or is the subitem actually having its colour set once and remembered? My earlier efforts seemed to suggest they were all being calculated every time.

Cheers

 

Easiest way to check if this is the case is to add a ConsoleWrite statement within the WM_NOTIFY function.

I can tell you that every item is redrawn when it is visible (also on window restore etc). Check it out for yourself:

#include <GUIConstants.au3>
#include <WindowsConstants.au3>
#include <FontConstants.au3>
#include <GuiListView.au3>
#include <WinAPI.au3>

Global $idLast1 = -1, $idLast2 = -1 ; Last and second last row
$MyGUI = GUICreate("listview items", 320, 200, 0,-1, -1)
_WinAPI_SetClassLongEx($MyGUI, -26, BitAND(_WinAPI_GetClassLongEx($MyGUI, -26), BitNOT(1), BitNOT(2)))
$idListview = GUICtrlCreateListView("A|B|C", 10, 10, 250, 155, 0x200)
_GUICtrlListView_SetExtendedListViewStyle($idListview, $LVS_EX_DOUBLEBUFFER)

$hLV = ControlGetHandle($MyGUI, "", $idListview)
$idButton = GUICtrlCreateButton("Add", 125, 175, 70, 20)
$hListview = GUICtrlGetHandle( $idListview )

$hDC = _WinAPI_GetDC($hLV)
$hFont = _SendMessage($hLV, $WM_GETFONT)
$hObject = _WinAPI_SelectObject($hDC, $hFont)
$lvLOGFONT = DllStructCreate($tagLOGFONT)
$aRet = DllCall('gdi32.dll', 'int', 'GetObjectW', 'ptr', $hFont, 'int', DllStructGetSize($lvLOGFONT), 'ptr', DllStructGetPtr($lvLOGFONT))
_WinAPI_SelectObject($hDC, $hObject)
_WinAPI_ReleaseDC($hLV, $hDC)
$hLVfont = _WinAPI_CreateFontIndirect($lvLOGFONT)
$iWeight = BitOR( DllStructGetData($lvLOGFONT, "Weight"), $FW_BOLD)
DllStructSetData( $lvLOGFONT, "Weight", $iWeight)
$hLVfontBold = _WinAPI_CreateFontIndirect($lvLOGFONT)

GUIRegisterMsg( $WM_NOTIFY, "WM_NOTIFY" )
GUISetState(@SW_SHOW)

while 1
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
            ExitLoop
        Case $idButton
        $Letter = Chr(Random(Asc("c"), Asc("d"), 1))
        $idLast1 = GUICtrlCreateListViewItem("a|b|"&$Letter, $idListview)
        $itemcount = _GUICtrlListView_GetItemCount( $hListview ) - 1
        _GUICtrlListView_RedrawItems( $hListview, $itemcount, $itemcount)
    EndSwitch
wend

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam
    Local $tNMHDR, $hWndFrom, $iCode
    $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iCode = DllStructGetData($tNMHDR, "Code")

    Switch $hWndFrom
        Case $hLV
            Switch $iCode
                Case $NM_CUSTOMDRAW
                    Local $tNMLVCUSTOMDRAW = DllStructCreate($tagNMLVCUSTOMDRAW, $lParam)
                    Local $dwDrawStage = DllStructGetData($tNMLVCUSTOMDRAW, "dwDrawStage")
                    Switch $dwDrawStage
                        Case $CDDS_PREPAINT
                            Return $CDRF_NOTIFYITEMDRAW
                        Case $CDDS_ITEMPREPAINT
                            Return $CDRF_NOTIFYSUBITEMDRAW
                        Case BitOR( $CDDS_ITEMPREPAINT, $CDDS_SUBITEM )
                            Local $iSubItem = DllStructGetData($tNMLVCUSTOMDRAW, "iSubItem")
                            Local $dwItemSpec = DllStructGetData($tNMLVCUSTOMDRAW, "dwItemSpec")
                            Local $hDC = DllStructGetData($tNMLVCUSTOMDRAW, "HDC")
                            ConsoleWrite('Drawing ListView item: ' & $dwItemSpec & ', SubItem: ' & $iSubItem & @CRLF)
                            Switch $iSubItem
                                Case 2
                                    _WinAPI_SelectObject($hDC, $hLVfont)
                                    If _GUICtrlListView_GetItemText($hLV, $dwItemSpec, $iSubItem) = "c" Then
                                        DllStructSetData( $tNMLVCUSTOMDRAW, "ClrText", ColorConvert(0x000000))
                                        DllStructSetData( $tNMLVCUSTOMDRAW, "ClrTextBk", ColorConvert(0x01DF01))
                                    ElseIf _GUICtrlListView_GetItemText($hLV, $dwItemSpec, $iSubItem) = "d" Then
                                        DllStructSetData( $tNMLVCUSTOMDRAW, "ClrText", ColorConvert(0x000000))
                                        DllStructSetData( $tNMLVCUSTOMDRAW, "ClrTextBk", ColorConvert(0xFF0000))
                                    EndIf
                                Case Else
                                    _WinAPI_SelectObject($hDC, $hLVfont)
                                    DllStructSetData( $tNMLVCUSTOMDRAW, "ClrText", ColorConvert(0x000000))
                                    DllStructSetData( $tNMLVCUSTOMDRAW, "ClrTextBk", ColorConvert(0xFFFFFF))
                            EndSwitch
                            Return $CDRF_NEWFONT
                    EndSwitch
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc

Func ColorConvert($iColor)
    Return BitOR(BitAND($iColor, 0x00FF00), BitShift(BitAND($iColor, 0x0000FF), -16), BitShift(BitAND($iColor, 0xFF0000), 16))
EndFunc
Link to comment
Share on other sites

I see, it does the clever bit of only having to redraw what's needed, but it doesn't remember what colour it was. My fault and OK codes are dependent on the item which is reporting, which it stored in an array, this shouldn't cause too much overhead :)

I can see that my earlier code change effectively from:

_GUICtrlListView_RedrawItems( $hListview, 0, $itemcount)

to:

_GUICtrlListView_RedrawItems( $hListview, $itemcount, $itemcount)

is well worth doing (it actually seems redundant, I commented it out and it was fine)

[some time passes.....]

I have now integrated this into my code and it only goes and flippin' works :D

Cheers for all the help :)

My log window can log events which happen at the same time (the events are fed from an FPGA via USB) and therefore have an identical timestamp (there can be tens of items with the same timestamp). What I'd like to do is give the first 2 columns (the first being the timestamp) alternating shades every time the timestamp changes. I can't think of a simple way to do this without going through the entire list looking at all the timestamps every time there's an update.

I've attached a pic of the monster you guys have helped create, your help is much appreciated :)

Cheers

post-44915-0-21534800-1426065593_thumb.p

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...