Jump to content

ListView color hover item


Terenz
 Share

Go to solution Solved by LarsJ,

Recommended Posts

Like title, this time is not an easy task :D

I want to color the item under the mouse in a ListView, after some research i have understand how to get the hover-id item but i don't have idea how to color it

The script:

#include <GUIConstantsEx.au3>
#include <ListViewConstants.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>

$hGUI = GUICreate("Hover Test", 323, 184, 208, 168)
$cInput = GUICtrlCreateInput("", 8, 24, 305, 21)
$cListView = GUICtrlCreateListView("ListView", 8, 45, 305, 129)
$hListView = GUICtrlGetHandle($cListView)

GUICtrlSendMsg(-1, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_ONECLICKACTIVATE, $LVS_EX_TRACKSELECT)
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
GUISetState(@SW_SHOW)

For $i = 0 To 10
    GUICtrlCreateListViewItem("TEST_" & $i, $cListView)
Next

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd

Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iMsg, $iwParam
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $tInfo
    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
        Case $hListView
            Switch $iCode
                Case $LVN_HOTTRACK ; Sent when the user moves the mouse over an item
                    $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam)
                    ConsoleWrite(DllStructGetData($tInfo, "Item") & @LF)
                Case $NM_CUSTOMDRAW
                    ;???
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

Thanks to all

Edited by Terenz

Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Link to comment
Share on other sites

A not so difficult way

#include <GUIConstantsEx.au3>
#include <ListViewConstants.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>

$hGUI = GUICreate("Hover Test", 323, 184, 208, 168)
$cInput = GUICtrlCreateInput("", 8, 24, 305, 21)
$cListView = GUICtrlCreateListView("ListView", 8, 45, 305, 129)
$hListView = GUICtrlGetHandle($cListView)

GUICtrlSendMsg(-1, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_ONECLICKACTIVATE, $LVS_EX_TRACKSELECT)
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
GUISetState(@SW_SHOW)

Global $items[11], $hotitem = -1
For $i = 0 To 10
    $items[$i] = GUICtrlCreateListViewItem("TEST_" & $i, $cListView)
Next

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd

Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iMsg, $iwParam
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $tInfo, $hot_item
    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
        Case $hListView
            Switch $iCode
                Case $LVN_HOTTRACK ; Sent when the user moves the mouse over an item
                    $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam)
               ;     ConsoleWrite(DllStructGetData($tInfo, "Item") & @LF)
                    $index = DllStructGetData($tInfo, "Item")
                    If $index <> $hotitem Then
                        For $i = 0 to 10
                           GuiCtrlSetColor($items[$i], 0x000000)
                        Next
                        If $index <> -1 Then GuiCtrlSetColor($items[$index], 0xff0000)
                        $hotitem = $index
                   EndIf
             EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY
Link to comment
Share on other sites

I want the difficult way :D

Jocking apart, i don't want to store all the list into an array and redim it everytime i'll add an item ( we are talk about many of that ) so i'll prefer to use WM_NOTIFY with $NM_CUSTOMDRAW

Thanks

Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Link to comment
Share on other sites

  • Solution

Here are the ideas for a solution based on custom drawn items:

#include <GUIConstantsEx.au3>
#include <ListViewConstants.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>

$hGUI = GUICreate("Hover Test", 323, 184, 208, 168)
$cInput = GUICtrlCreateInput("", 8, 24, 305, 21)
$cListView = GUICtrlCreateListView("ListView", 8, 45, 305, 129)
$hListView = GUICtrlGetHandle($cListView)

GUICtrlSendMsg(-1, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_ONECLICKACTIVATE, $LVS_EX_TRACKSELECT)
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
GUISetState(@SW_SHOW)

For $i = 0 To 10
    GUICtrlCreateListViewItem("TEST_" & $i, $cListView)
Next

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd

Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iMsg, $iwParam
    Local Static $iHot = -1, $iHotPrev = -1
    Local $hWndFrom, $iCode, $tNMHDR, $tInfo
    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
        Case $hListView
            Switch $iCode
                Case $LVN_HOTTRACK ; Sent when the user moves the mouse over an item
                    $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam)
                    $iHot = DllStructGetData($tInfo, "Item")
                    If $iHot <> $iHotPrev Then
                        ;ConsoleWrite($iHot & @LF)
                        If $iHot <> -1 Then _GUICtrlListView_RedrawItems( $hListView, $iHot, $iHot )
                        If $iHotPrev <> -1 Then _GUICtrlListView_RedrawItems( $hListView, $iHotPrev, $iHotPrev )
                        If $iHot <> $iHotPrev And $iHot <> -1 Then $iHotPrev = $iHot
                    EndIf

                Case $NM_CUSTOMDRAW
                  Local $tNMLVCUSTOMDRAW = DllStructCreate( $tagNMLVCUSTOMDRAW, $ilParam )
                  Local $dwDrawStage = DllStructGetData( $tNMLVCUSTOMDRAW, "dwDrawStage" )

                  Switch $dwDrawStage                               ; Holds a value that specifies the drawing stage

                    Case $CDDS_PREPAINT                             ; Before the paint cycle begins
                      Return $CDRF_NOTIFYITEMDRAW                   ; Notify the parent window of any ITEM-related drawing operations

                    Case $CDDS_ITEMPREPAINT                         ; Before painting an item
                      Return $CDRF_NOTIFYSUBITEMDRAW                ; Notify the parent window of any SUBITEM-related drawing operations

                    Case BitOR( $CDDS_ITEMPREPAINT, $CDDS_SUBITEM ) ; Before painting a subitem
                      Local $dwItemSpec = DllStructGetData( $tNMLVCUSTOMDRAW, "dwItemSpec" )  ; Item index
                      ;Local $iSubItem   = DllStructGetData( $tNMLVCUSTOMDRAW, "iSubItem"   ) ; Subitem index
                      ;Local $uItemState = DllStructGetData( $tNMLVCUSTOMDRAW, "uItemState" ) ; Item state
                      If $dwItemSpec = $iHot Then ; Hot row
                        DllStructSetData( $tNMLVCUSTOMDRAW, "ClrText",   0x000000 )
                        DllStructSetData( $tNMLVCUSTOMDRAW, "ClrTextBk", 0x00FF00 )
                      Else ; Other rows
                        DllStructSetData( $tNMLVCUSTOMDRAW, "ClrText",   0x000000 )
                        DllStructSetData( $tNMLVCUSTOMDRAW, "ClrTextBk", 0xFFFFFF )
                      EndIf
                      Return $CDRF_NEWFONT                          ; $CDRF_NEWFONT must be returned after changing font or colors
                  EndSwitch
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY
It's not a complete solution.
Link to comment
Share on other sites

Thank you. The example below is better.

  • Handles multiple columns. Takes care of horizontal movement of the cursor in the same row through different columns.
  • The hot state is item specific. Subitems doesn't matter. Custom draw is handled in the item case. The subitem case is deleted.
  • Hot state is properly set. Even if you leave and enter the listview through the same item (e.g. on the left side).
  • Hot state is reset when the cursor is moved out of the listview.
#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>

Opt( "MustDeclareVars", 1 )

Global $hGUI, $iGUIw = 350, $iGUIh = 400, $fCursorInListView = False
Global $hLV, $iLVx = 2, $iLVy = 2, $iLVw = $iGUIw - 4, $iLVh = $iGUIh - 4
Global $iHot = -1, $iHotPrev = -1

Example()

Func Example()

  $hGUI = GUICreate( "Hot item", $iGUIw, $iGUIh )

  Local $idLV = GUICtrlCreateListView( "Column 0|Column 1|Column 2|Column 3", $iLVx, $iLVy, $iLVw, $iLVh )
  GUICtrlSendMsg( $idLV, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_ONECLICKACTIVATE, $LVS_EX_TRACKSELECT )
  $hLV = GUICtrlGetHandle( $idLV )
  For $i = 0 To 99
    GUICtrlCreateListViewItem( "Cell " & $i & ".0" & "|Cell " & $i & ".1" & "|Cell " & $i & ".2" & "|Cell " & $i & ".3", $idLV )
  Next

  Local $hHeader = _GUICtrlListView_GetHeader( $hLV )
  Local $aPos = WinGetPos( $hHeader )
  $iLVy += $aPos[3]
  $iLVh -= $aPos[3]

  GUIRegisterMsg( $WM_NOTIFY, "WM_NOTIFY" )

  GUISetState()

  Local $aInfo, $aTest
  While 1
    Switch GUIGetMsg()
      Case $GUI_EVENT_CLOSE
        Exit
    EndSwitch
  WEnd

EndFunc

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

  Switch $hWndFrom

    Case $hLV

      Switch $iCode

        Case $LVN_HOTTRACK
            Local $tInfo = DllStructCreate( $tagNMLISTVIEW, $lParam )
            $iHot = DllStructGetData( $tInfo, "Item" )
            If $iHot <> $iHotPrev Then
              If Not $fCursorInListView Then
                AdlibRegister( "ResetHotRow", 100 )
                $fCursorInListView = True
              EndIf
              If $iHot <> -1 Then _GUICtrlListView_RedrawItems( $hLV, $iHot, $iHot )
              If $iHotPrev <> -1 Then _GUICtrlListView_RedrawItems( $hLV, $iHotPrev, $iHotPrev )
              If $iHot <> $iHotPrev Then
                If $iHot <> -1 Then
                  $iHotPrev = $iHot
                ElseIf $iHotPrev <> -1 Then
                  $iHot = $iHotPrev
                  _GUICtrlListView_RedrawItems( $hLV, $iHot, $iHot )
                EndIf
              EndIf
            EndIf

        Case $NM_CUSTOMDRAW
          Local $tNMLVCUSTOMDRAW = DllStructCreate( $tagNMLVCUSTOMDRAW, $lParam )
          Local $dwDrawStage = DllStructGetData( $tNMLVCUSTOMDRAW, "dwDrawStage" )

          Switch $dwDrawStage             ; Holds a value that specifies the drawing stage

            Case $CDDS_PREPAINT           ; Before the paint cycle begins
              Return $CDRF_NOTIFYITEMDRAW ; Notify the parent window of any ITEM-related drawing operations

            Case $CDDS_ITEMPREPAINT       ; Before painting an item
              Local $dwItemSpec = DllStructGetData( $tNMLVCUSTOMDRAW, "dwItemSpec" )  ; Item index
              If $dwItemSpec = $iHot Then ; Hot row
                DllStructSetData( $tNMLVCUSTOMDRAW, "ClrText",   0x000000 )
                DllStructSetData( $tNMLVCUSTOMDRAW, "ClrTextBk", 0xFFE8D8 ) ; Light blue, BGR
              Else ; Other rows
                DllStructSetData( $tNMLVCUSTOMDRAW, "ClrText",   0x000000 )
                DllStructSetData( $tNMLVCUSTOMDRAW, "ClrTextBk", 0xFFFFFF )
              EndIf
              Return $CDRF_NEWFONT        ; $CDRF_NEWFONT must be returned after changing font or colors

          EndSwitch

      EndSwitch

  EndSwitch

  Return $GUI_RUNDEFMSG
EndFunc

Func ResetHotRow()
  Local $aPos = GUIGetCursorInfo()
  If $aPos[0] < $iLVx Or $aPos[0] > $iLVx + $iLVw Or _
     $aPos[1] < $iLVy Or $aPos[1] > $iLVy + $iLVh Then
        $iHot = -1
        _GUICtrlListView_RedrawItems( $hLV, $iHotPrev, $iHotPrev )
        AdlibUnRegister( "ResetHotRow" )
        $fCursorInListView = False
        $iHotPrev = -1
  EndIf
EndFunc

One issue: There is a narrow area between first and second column, which is not hottrack enabled. The hot state is not updated when the cursor is moved vertically in this area. No problem between the other columns. The cause of this issue is probably, that the first column has a special role: It represents the items. All the other columns are alike. They represent the subitems.

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...