gobsor

Focus/Highlight a certain item in a ListView?

14 posts in this topic

Hello,

Why doesn't this code select/highlight (in blue 'this-row-is-selected'-colour) the first row in the ListView after loading files to it, using the 'LOAD' button?

(As far as I understood it, _GUICtrlListView_SetItemSelected() and _GUICtrlListView_SetItemFocused() should do the job)

#include <GuiConstants.au3>
#include <GuiListView.au3>
#include <File.au3>

GUICreate("test", 500, 500)
$hListView = GUICtrlCreateListView("", 5, 5, 490, 400, $LVS_SINGLESEL, $LVS_EX_GRIDLINES + $LVS_EX_FULLROWSELECT)
_GUICtrlListView_AddColumn($hListView, "#", 30)
_GUICtrlListView_AddColumn($hListView, "A", 170)
_GUICtrlListView_AddColumn($hListView, "B", 170)
$idLoad = GUICtrlCreateButton("LOAD", 295, 410, 200, 80) 
GUISetState(@SW_SHOW)

While 1
    $msg = GUIGetMsg()
    If $msg == $GUI_EVENT_CLOSE Then ExitLoop
    If $msg == $idLoad Then _load()
WEnd

Func _load()
    $path = FileSelectFolder("Browse Folder", @DesktopDir, 4)
    If Not @error Then
        $ar = _FileListToArray($path, "*.*")
        For $i = 0 To UBound($ar)-1 Step 1
            GUICtrlCreateListViewItem($i & "|" & $ar[$i] & "|" & "test", $hListView)
        Next
        $bTest_1 = _GUICtrlListView_SetItemSelected($hListView, 0, True, True) ; Tested both of these functions, in combination or each alone with different values, no effects still
        MsgBox(0, "SetItemSelected() returned:", $bTest_1)                     ;
        $bTest_2 = _GUICtrlListView_SetItemFocused($hListView, 0, True)
        MsgBox(0, "SetItemFocused() returned:", $bTest_2)
    EndIf
EndFunc ;==> _load()

In my actual project I want to highlight rows after a button is pressed or if one clicks a certain row. Not that much of a problem if I, somehow, get those functions working. Or am I failing basically here, ie. using the wrong functions?

Any help appreciated.

rgrds

Share this post


Link to post
Share on other sites



gobsor,

I have found that the only reliable way to highlight ListView rows is to use _GUICtrlListView_ClickItem to simulate mouse clicks:

#include <GuiConstants.au3>
#include <GuiListView.au3>
#include <File.au3>

GUICreate("test", 500, 500)
$hListView = GUICtrlCreateListView("", 5, 5, 490, 400, $LVS_SINGLESEL, $LVS_EX_GRIDLINES + $LVS_EX_FULLROWSELECT)
_GUICtrlListView_AddColumn($hListView, "#", 30)
_GUICtrlListView_AddColumn($hListView, "A", 170)
_GUICtrlListView_AddColumn($hListView, "B", 170)
$idLoad = GUICtrlCreateButton("LOAD", 295, 410, 200, 80)
GUISetState(@SW_SHOW)

While 1
    $msg = GUIGetMsg()
    If $msg == $GUI_EVENT_CLOSE Then ExitLoop
    If $msg == $idLoad Then _load()
WEnd

Func _load()
    $path = FileSelectFolder("Browse Folder", @DesktopDir, 4)
    If Not @error Then
        $ar = _FileListToArray($path, "*.*")
        For $i = 0 To UBound($ar)-1 Step 1
            GUICtrlCreateListViewItem($i & "|" & $ar[$i] & "|" & "test", $hListView)
        Next
        ; Simulate a mouse click on the top item
        _GUICtrlListView_ClickItem($hListView, 0) ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    EndIf
EndFunc ;==> _load()

In my actual project I want to highlight rows after a button is pressed or if one clicks a certain row

Clicking with the mouse will obviously highlight a row as it does in reality what the code above simulates. For buttons, just use code as above. :x

M23

1 person likes this

Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites

Thanks, works fine like this.

Just everytime I click on a button or input or just elsewhere, the focus/highlight gets lost. Is it possible to have at least one item focused/highlighted all the time?

(Always I press 'Move UP' or 'Move DN' the selection/highlight disappears for a millisec, when I press some other button ([bROWSE]) then it disappears at all.)

greets

Share this post


Link to post
Share on other sites

gobsor,

The default ListView has the $LVS_SHOWSELALWAYS style selected. But on my monitor I have to change the background colour of the ListView to make the selection visible when the ListView loses focus as the default non-active selected colour is too close to the default ListView background colour. :x

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites

Ah, okay. Would be easier to just change the default LisstView-Highlighted color. Not possible, is it?

And how do I change the color for the '_ClickItem($h, $index)' $index'th row?

Share this post


Link to post
Share on other sites

gobsor,

If you ever find out how to change the default non-active ListView selection colout, please let me know! :P

I am sure it is a system setting, but I cannot find it. Anyway, changing the ListView background colour has always worked for me.

As to changing the selected row colour, that too is a system setting - if you want to change it then _WinAPI_GetSysColor/_WinAPI_SetSysColor would be a good place to start looking. But do not blame me if you screw all the system colours while playing with them! :x

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites

Oh, I was fiddling with GUICtrlSetBkColor(), though I couldn't work out to change the last _GUICtrlListView_ClickItem() 'clicked' row's colour.

I rather keep my hands off those functions you just hooked me up with, at least until I got used to AU3 better :P

Thanks for your help :x

Share this post


Link to post
Share on other sites

I know you aren't interested in this solution, but someone in the future may be. This was adapted (mostly just updated) from (I couldn't have written it anyway).

It's a tiny bit less messy. Not as many DllCalls and some code to colour other bits omitted.

#include <GuiConstantsEx.au3>
#include <GuiListView.au3>
#include <WindowsConstants.au3>
#include <WinAPI.au3>

$GUI = GUICreate("Listview Custom Draw", 400, 300)

$cListView = GUICtrlCreateListView("Column 1|Column 2|Column 3", 2, 2, 394, 268, -1, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT))
$hListView = GUICtrlGetHandle($cListView)

; Add items
For $i = 1 To 30
    GUICtrlCreateListViewItem("Row" & $i & ": Col 1|Row" & $i & ": Col 2|Row" & $i & ": Col 3", $cListView)
Next

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

Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE

Exit

Func WM_NOTIFY($hWnd, $Msg, $wParam, $lParam)
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR

    $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
        Case $hListView
            Switch $iCode
                Case $NM_CUSTOMDRAW
                    If Not _GUICtrlListView_GetViewDetails($hWndFrom) Then Return $GUI_RUNDEFMSG
                    Local $tCustDraw = DllStructCreate('hwnd hwndFrom;int idFrom;int code;' & _
                            'dword DrawStage;hwnd hdc;long rect[4];dword ItemSpec;int ItemState;dword Itemlparam;' & _
                            'dword clrText;dword clrTextBk;int SubItem;' & _
                            'dword ItemType;dword clrFace;int IconEffect;int IconPhase;int PartID;int StateID;long rectText[4];int Align', _ ;winxp or later
                            $lParam), $iDrawStage, $iItem, $iSubitem, $hDC, $tRect, $iColor1, $iColor2, $iColor3
                    $iDrawStage = DllStructGetData($tCustDraw, 'DrawStage')
                    Switch $iDrawStage
                        Case $CDDS_PREPAINT
                            Return $CDRF_NOTIFYITEMDRAW
                        Case $CDDS_ITEMPREPAINT
                            Return $CDRF_NOTIFYSUBITEMDRAW
                        Case $CDDS_ITEMPOSTPAINT
                        Case BitOR($CDDS_ITEMPREPAINT, $CDDS_SUBITEM)
                            $iItem = DllStructGetData($tCustDraw, 'ItemSpec')
                            $iSubitem = DllStructGetData($tCustDraw, 'SubItem')
                            If _GUICtrlListView_GetItemSelected($hWndFrom, $iItem) Then
                                $hDC = _WinAPI_GetDC($hWndFrom)
                                $tRect = DllStructCreate($tagRECT)
                                If $iSubitem = 0 Then
                                    _SendMessage($hWndFrom, $LVM_GETSUBITEMRECT, $iItem, DllStructGetPtr($tRect))
                                    DllStructSetData($tRect, 1, 2)
                                    _WinAPI_FillRect($hDC, DllStructGetPtr($tRect), _WinAPI_GetStockObject($GRAY_BRUSH))
                                EndIf

                                DllStructSetData($tRect, 1, 2)
                                DllStructSetData($tRect, 2, $iSubitem)
                                _SendMessage($hWndFrom, $LVM_GETSUBITEMRECT, $iItem, DllStructGetPtr($tRect))

                                Local $sText = _GUICtrlListView_GetItemText($hWndFrom, $iItem, $iSubitem)
                                _WinAPI_SetBkMode($hDC, $TRANSPARENT)
                                DllStructSetData($tRect, 1, DllStructGetData($tRect, 1) + 2)
                                _WinAPI_DrawText($hDC, $sText, $tRect, 0x8000) ;; $DT_END_ELLIPSIS
                                _WinAPI_ReleaseDC($hWndFrom, $hDC)
                                Return $CDRF_SKIPDEFAULT
                            EndIf

                            Return $CDRF_NEWFONT
                        Case BitOR($CDDS_ITEMPOSTPAINT, $CDDS_SUBITEM)
                        Case Else
                    EndSwitch
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

Func RGB2BGR($iColor)
    Return BitAND(BitShift(String(Binary($iColor)), 8), 0xFFFFFF)
EndFunc   ;==>RGB2BGR

Share this post


Link to post
Share on other sites

That's almost what I've been looking for, its just as fine though..

But, tbh, its pretty much code for such a little effect. I still might use it though since it enhances the oversight when the user is editing the ListView (using inputs below it in combination with a button to change the values of each row).

Each time the user clicks the input field the focus on the ListView is lost and therefore the highlight, too.

Your little work-around posted above might be very useful though, let's hope there'll be some function for it coming up in 2011 :x

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

Here is an updated version. The code has been tidied up even more, and it now selects the font to be the same as the listviews. I also commented it a bit more. Don't get your hopes up with a new function to do this in 2011... I'd be very surprised if there was one. The problem with custom draw for stuff like this is that it's designed for the user to completely take control of how the control looks, not to tweak one or two things. It looks like a lot of code now, but most of it's getting to the message. If you want to change the text colour, font, draw a border, add a shadow for the text of item for any item now then it would be a few lines of code.

 

 

#include <GuiConstantsEx.au3>
#include <GuiListView.au3>
#include <ListViewConstants.au3>
#include <WindowsConstants.au3>
#include <WinAPI.au3>
#include <StructureConstants.au3>

$GUI = GUICreate("Listview Custom Draw", 400, 300)

$cListView = GUICtrlCreateListView("Column 1|Column 2|Column 3", 2, 2, 394, 268, -1, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT))
$hListView = GUICtrlGetHandle($cListView)

; Add items
For $i = 1 To 30
    GUICtrlCreateListViewItem("Row" & $i & ": Col 1|Row" & $i & ": Col 2|Row" & $i & ": Col 3", $cListView)
Next

GUICtrlCreateInput("Click here to test focus", 50, 275, 200, 18)

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

Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE

Exit

Func WM_NOTIFY($hWnd, $Msg, $wParam, $lParam)
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR

    $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    
    Switch $hWndFrom
        Case $hListView
            Switch $iCode
                Case $NM_CUSTOMDRAW
                    If Not _GUICtrlListView_GetViewDetails($hWndFrom) Then Return $GUI_RUNDEFMSG ; Not in details mode

                    Local $tCustDraw, $iDrawStage, $iItem, $iSubitem, $hDC, $tRect, $iColor1, $iColor2, $iColor3

                    $tCustDraw = DllStructCreate($tagNMLVCUSTOMDRAW, $lParam)
                    $iDrawStage = DllStructGetData($tCustDraw, 'dwDrawStage')

                    Switch $iDrawStage
                        Case $CDDS_PREPAINT
                            Return $CDRF_NOTIFYITEMDRAW
                        Case $CDDS_ITEMPREPAINT
                            Return $CDRF_NOTIFYSUBITEMDRAW
                        Case $CDDS_ITEMPOSTPAINT
                            ; Not handled
                        Case BitOR($CDDS_ITEMPREPAINT, $CDDS_SUBITEM)
                            $iItem = DllStructGetData($tCustDraw, 'dwItemSpec')
                            $iSubitem = DllStructGetData($tCustDraw, 'iSubItem')

                            If _GUICtrlListView_GetItemSelected($hWndFrom, $iItem) Then ; Item to draw is selected
                                $hDC = _WinAPI_GetDC($hWndFrom)
                                $tRect = DllStructCreate($tagRECT)

                                ; We draw the background when we draw the first item.
                                If $iSubitem = 0 Then
                                    ; We must send the message as we want to use the struct. _GUICtrlListView_GetSubItemRect returns an array.
                                    _SendMessage($hWndFrom, $LVM_GETSUBITEMRECT, $iItem, DllStructGetPtr($tRect))

                                    DllStructSetData($tRect, "Left", 2)
                                    _WinAPI_FillRect($hDC, DllStructGetPtr($tRect), _WinAPI_GetStockObject($GRAY_BRUSH)) ; Change the bush here. You can use GDI+ to make your own.
                                EndIf

                                DllStructSetData($tRect, "Left", 2)
                                DllStructSetData($tRect, "Top", $iSubitem)
                                _SendMessage($hWndFrom, $LVM_GETSUBITEMRECT, $iItem, DllStructGetPtr($tRect))

                                Local $sText = _GUICtrlListView_GetItemText($hWndFrom, $iItem, $iSubitem)
                                _WinAPI_SetBkMode($hDC, $TRANSPARENT) ; It uses the background drawn for the first item.

                                ; Select the font we want to use
                                _WinAPI_SelectObject($hDC, _SendMessage($hWndFrom, $WM_GETFONT))

                                If $iSubitem = 0 Then
                                    DllStructSetData($tRect, "Left", DllStructGetData($tRect, "Left") + 2)
                                Else
                                    DllStructSetData($tRect, "Left", DllStructGetData($tRect, "Left") + 6)
                                EndIf
                                _WinAPI_DrawText($hDC, $sText, $tRect, BitOR($DT_VCENTER, $DT_END_ELLIPSIS, $DT_SINGLELINE))

                                _WinAPI_ReleaseDC($hWndFrom, $hDC)

                                Return $CDRF_SKIPDEFAULT ; Don't do default processing
                            EndIf

                            Return $CDRF_NEWFONT ; Let the system do the drawing for non-selected items
                        Case BitOR($CDDS_ITEMPOSTPAINT, $CDDS_SUBITEM)
                            ; Not handled
                    EndSwitch
            EndSwitch
    EndSwitch

    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

Func RGB2BGR($iColor)
    Return BitAND(BitShift(String(Binary($iColor)), 8), 0xFFFFFF)
EndFunc   ;==>RGB2BGR

 

Mat

Edit: See here for an updated version which includes sorting. 

Edited by Mat
Added link to updated code.

Share this post


Link to post
Share on other sites

Thanks you!

Its just as fine as a 'normal' highlight. At least it does its job and prevents the user from getting confused in what row he currently is. Will use your code and put it into my little tool when I find some time the upcoming days.

Greetings

Share this post


Link to post
Share on other sites

Hey mat,

Your code work beautiful except that it covers the list-box icon gfx when your list's elements contains list-boxes.

Why doesn't _GUICtrlListView_SetItemFocused work as it should? :)


Take it from this Quadriplegic, life is beautiful. Don't know what a quadriplegic is? Check out my short bio.Starting an online business.

Share this post


Link to post
Share on other sites

#13 ·  Posted (edited)

@Mat Is it possible to change selecting style? I just want to make dotted border of selected listview item with transparent bg color (which work with $LVS_EX_SUBITEMIMAGES ExStyle)

Edited by maniootek

Share this post


Link to post
Share on other sites

 

@LeXarT, @maniootek, Modifying the code to work with images (incl. subitem images) could be a little tricky, as it will require custom drawing the images. It's a very long time since I looked at this and I'm in the middle of exams at the moment, but I'll add it on to the todo list. 

In summary though, drawing images is the same as drawing text items. You have to work out what needs redrawing, and where it is, then draw it to the context. 

Steps are as follows: Start with the HBITMAP. Now this can either be loaded every time you draw or preloaded and stored somewhere (I suspect the latter may be better?). Create a compatible DC for the context you are drawing to (CreateCompatibleDC()), SelectObject() to select the bitmap into the new DC you've created, BitBlt() to the listview DC, then cleanup (last stage might have to use one of the other Blt functions to use transparent backgrounds on the icons).

For storing HBITMAPs, first guess would be to store them in the lParam of the items, if multiple are needed then that can point to a structure (of course being careful to free everything in response to deleting the window). However, I expect this is not how it's done by the listview normally so perhaps isn't the right way.

Mat

Share this post


Link to post
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