Jump to content

ListView - get color of row


Zedna
 Share

Recommended Posts

How to get color of row previously created by

GUICtrlCreateListViewItem() + GUICtrlSetColor()?

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
 
GUICreate("listview items", 220, 250, 100, 200)
$listview = GUICtrlCreateListView("col1  |col2|col3  ", 10, 10, 200, 150)
$button = GUICtrlCreateButton("Value?", 75, 170, 70, 20)
$item1 = GUICtrlCreateListViewItem("item2|col22|col23", $listview)
GUICtrlSetColor(-1, 0xff0000)
$item3 = GUICtrlCreateListViewItem("item3|col32|col33", $listview)
GUISetState()
 
Do
    $msg = GUIGetMsg()
    Select
        Case $msg = $button
         MsgBox(0, "listview row color", '???')
    EndSelect
Until $msg = $GUI_EVENT_CLOSE
Link to comment
Share on other sites

I would think it's better to use....

MsgBox(4160, "Information", "Back Color ....: " & _GUICtrlListView_GetBkColor($hListView) & @CRLF & _
            "Text Color ....: " & _GUICtrlListView_GetTextColor($hListView) & @CRLF & _
            "Text Back Color: " & _GUICtrlListView_GetTextBkColor($hListView))

8)

EDIT, I thought it would give you the color you wanted....Was working on it... got close but have to leave

Sorry, that was not the answer you wanted.

Edited by Valuater

NEWHeader1.png

Link to comment
Share on other sites

Whether there is something that involves fun stuff like _SendMessage() or DllStructGetData() that would get you your required info I can't say.

What does come to mind is, if you are creating the listview, can you not maintain a small array with an entry for each row of the listview containing your color info, and reference that later when a row is clicked? Not an option for you?

Link to comment
Share on other sites

Look here:

Example_LV_Format1.1.au3 shows how to read the color value.

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

I would think it's better to use....

MsgBox(4160, "Information", "Back Color ....: " & _GUICtrlListView_GetBkColor($hListView) & @CRLF & _
            "Text Color ....: " & _GUICtrlListView_GetTextColor($hListView) & @CRLF & _
            "Text Back Color: " & _GUICtrlListView_GetTextBkColor($hListView))

8)

EDIT, I thought it would give you the color you wanted....Was working on it... got close but have to leave

Sorry, that was not the answer you wanted.

This is for coloring whole ListView not for row in ListView.

Whether there is something that involves fun stuff like _SendMessage() or DllStructGetData() that would get you your required info I can't say.

What does come to mind is, if you are creating the listview, can you not maintain a small array with an entry for each row of the listview containing your color info, and reference that later when a row is clicked? Not an option for you?

Yes of course I thought about this as about workaround but I prefer to use some clever API function call as better solution.

I investigated in ListView's examples about coloring columns to see what API is used but all examples use NM_CUSTOMDRAW notification where are related structures with clrText property.

But When I need to get color of existing row and probably can't use these structures or I don't know how.

CUSTOMDRAW column coloring example

http://www.autoitscript.com/forum/index....=&showtopic=71681&view=findpos

Edited by Zedna
Link to comment
Share on other sites

Yes of course I thought about this as about workaround but I prefer to use some clever API function call as better solution.

I investigated in ListView's examples about coloring columns to see what API is used but all examples use NM_CUSTOMDRAW notification where are related structures with clrText property.

But When I need to get color of existing row and probably can't use these structures or I don't know how.

That seems to be the standard method, intercepting WM_NOTIFY and NM_CUSTOMDRAW to individually set subitems via clrText and clrTextBk. I had one script a couple years ago that set a subitems color to red on one of about 6 different error conditions. When a user made a choice to clear the error, I didn't want to run through all 6 error tests to determine if it was red, so went on the same search you're on. I was unable to find any example of direclty querying the API to return a structure with the pertinent data.

It appears Melba23's UDF, that UEZ pointed out, uses _GUICtrlListView_SetItemParam() to embed extra info in the listview item and _GUICtrlListView_GetItemParam() to retrieve it.

Edit: PS - in the prior script I mentioned, I just opted for storing the values in an internal array.

Edited by Spiff59
Link to comment
Share on other sites

It appears Melba23's UDF, that UEZ pointed out, uses _GUICtrlListView_SetItemParam() to embed extra info in the listview item and _GUICtrlListView_GetItemParam() to retrieve it.

I looked at it and finally it stores all items/columns properties in global array anyway ItemParam store only pointer to structure/array for each item/column.

But as far as I know Autoit uses internally ItemParam property for its internal job so if you use nativeGUICtrlCreateListViewItem() then you can't use/overwrite ItemParam structure because Autoit can miss this information.So in case of using ItemParam you must create Listview items by UDF _GUICtrlListView_AddItem() which is unfortunally slower than native one.I prefer not using global array of colors for each row and don't want to use slower UDF for creating ListView items so ItemParam is not way for me either.Is there any way to get color of existing row in ListView created by native GUICtrlCreateListViewItem()?If there will not any soluion I will use global array of colors for each row but I'm curious about some clever simple API solution.

Link to comment
Share on other sites

What do you want to achieve? When you set any color you know it already because you can save it in any data structure!

Br,

UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

What do you want to achieve? When you set any color you know it already because you can save it in any data structure!

My project is viewer with advanced filterig/searching around CSV file(s).

I have got global two dimensional array of data parsed from CSV - rows and columns.

Color of each row is calculated at time of parsing CSV data so it's stored in this global array (as last column).

In GUI there are controls for quick filtering - In Filter() function I go through my global array (rows/columns) and rows which pass filter options add from array to ListView by GUICtrlCreateListViewItem(), some of rows (based on other option "Coloring: ON/OFF") can be colored by GUICtrlSetColor()

I need to get color of actual row when I do Export of Listview (filtered) content to XML/HTML output,

so in this case I can't use directly global array because in ListView there is only subset of filtered rows,

so I must create at each filtering another helper array of filtered rows and their colors (which will slow down each filtering)

just for the case of not so often called export to XML/HTML.

That's why I would prefer to get color of row from ListView directly at time of export to XML/HTML.

I need to keep my Filter() function as fast as possible because there are thousands of rows so filtering should be quick.

Edited by Zedna
Link to comment
Share on other sites

How about a 3D array where the 3rd dimension holds the color value or even more information?

I don't know what the impact is to the speed of a 3D array compared with a 2D array.

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

How about a 3D array where the 3rd dimension holds the color value or even more information?

I don't know what the impact is to the speed of a 3D array compared with a 2D array.

I fill color as last column in 2D array at the moment I fill 2D array by values from parsed CSV.

As I said problem is that Export is done from ListView (not from this array) which is only filtered subset of array.

EDIT:

I have written workaround with another global helper array of ListView's rows/colors created in my Filter() function when creating ListView items

and used at time of Export to XML/HTML but as I said it slows down my Filter() function so I prefer some way of getting colors from ListView when doing export.

Edited by Zedna
Link to comment
Share on other sites

@Zedna

This code is just a curiosity, not a workable solution.

Returns the items text and background colours, but one time only.

The first time the mouse is hovered over the items the colour is returned,

but not on subsequent mouse hovering or if new items are coloured,

then the mouse is hovered over the new and previously coloured items.

Edit: Why not?

#include <GuiConstantsEx.au3>
#include <GuiListView.au3>
#include <WindowsConstants.au3>
Opt("MustDeclareVars", 1)
Global $GUI = GUICreate("Listview Custom Draw")
Global $cListView = GUICtrlCreateListView("Column 1|Column 2|Column 3", 2, 2, 396, 396)
_GUICtrlListView_SetTextBkColor($cListView, 0xF0F0F0)
_GUICtrlListView_SetBkColor($cListView, 0xF0F0F0)
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()
 
Global $ctrlID = _GUICtrlListView_GetItemParam($cListView, 4)
GUICtrlSetColor($ctrlID, 0x5A5B5C)
GUICtrlSetBkColor($ctrlID, 0xDDDD07)
$ctrlID = _GUICtrlListView_GetItemParam($cListView, 6)
GUICtrlSetColor($ctrlID, 0xFBFBFB)
GUICtrlSetBkColor($ctrlID, 0x494949)
Sleep(3000)
__GUICtrlListView_HoverItem($cListView, 4)
__GUICtrlListView_HoverItem($cListView, 6)
 
Sleep(3000)
Global $ctrlID = _GUICtrlListView_GetItemParam($cListView, 8)
GUICtrlSetColor($ctrlID, 0xF9F9F9)
GUICtrlSetBkColor($ctrlID, 0x246810)
$ctrlID = _GUICtrlListView_GetItemParam($cListView, 9)
GUICtrlSetColor($ctrlID, 0xDADADA)
GUICtrlSetBkColor($ctrlID, 0x090909)
Sleep(3000)
__GUICtrlListView_HoverItem($cListView, 4)
__GUICtrlListView_HoverItem($cListView, 6)
__GUICtrlListView_HoverItem($cListView, 8)
__GUICtrlListView_HoverItem($cListView, 9)
 
Do
Until GUIGetMsg() = -3
Exit
Func __GUICtrlListView_HoverItem($hWnd, $iIndex, $sButton = "left", $fMove = False, $iClicks = 1, $iSpeed = 1)
If $Debug_LV Then __UDF_ValidateClassName($hWnd, $__LISTVIEWCONSTANT_ClassName)
If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)
_GUICtrlListView_EnsureVisible($hWnd, $iIndex, False)
Local $tRect = _GUICtrlListView_GetItemRectEx($hWnd, $iIndex, $LVIR_LABEL)
Local $tPoint = _WinAPI_PointFromRect($tRect, True)
$tPoint = _WinAPI_ClientToScreen($hWnd, $tPoint)
Local $iX, $iY
_WinAPI_GetXYFromPoint($tPoint, $iX, $iY)
Local $iMode = Opt("MouseCoordMode", 1)
Local $aPos = MouseGetPos()
_WinAPI_ShowCursor(False)
MouseMove($iX, $iY, 0)
MouseMove($aPos[0], $aPos[1], 0)
_WinAPI_ShowCursor(True)
Opt("MouseCoordMode", $iMode)
EndFunc   ;==>__GUICtrlListView_HoverItem
 
Func WM_NOTIFY($hWnd, $Msg, $wParam, $lParam)
Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR
$tNMHDR = DllStructCreate($tagNMHDR, $lParam)
$hWndFrom = DllStructGetData($tNMHDR, "hWndFrom")
$iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
$iCode = DllStructGetData($tNMHDR, "Code")
Switch $iIDFrom
  Case $cListView
   Switch $iCode
    Case $LVN_DELETEITEM
     _WinAPI_InvalidateRect($hWndFrom, 0, 0)
    Case $NM_CUSTOMDRAW
     Local $tCustDraw = DllStructCreate($tagNMLVCUSTOMDRAW, $lParam)
     Local $iItem = DllStructGetData($tCustDraw, "dwItemSpec")
     Switch DllStructGetData($tCustDraw, "dwDrawStage")
      Case $CDDS_PREPAINT
       Return BitOR($CDRF_NOTIFYITEMDRAW, $CDRF_NOTIFYPOSTPAINT)
      Case $CDDS_POSTPAINT
       Local $iCnt = _GUICtrlListView_GetItemCount($cListView)
       Local $iTxtCol = "0x" & StringRegExpReplace(Hex(DllStructGetData($tCustDraw, "clrText"), 6), "(.{2})(.{2})(.{2})", "\3\2\1")
       Local $iBkCol = "0x" & StringRegExpReplace(Hex(DllStructGetData($tCustDraw, "clrTextBk"), 6), "(.{2})(.{2})(.{2})", "\3\2\1")
       If $iTxtCol <> 0 And $iItem <= $iCnt Then
        ConsoleWrite('-$iItem: ' & $iItem & " Txt: " & $iTxtCol & " Bk: " & $iBkCol & @CRLF)
       EndIf
     EndSwitch
   EndSwitch
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY
Edited by rover

I see fascists...

Link to comment
Share on other sites

each time you add an item using GUICtrlCreateListViewItem() when applying the filter

get the items unique ID with _GUICtrlListView_MapIndexToID() and add it to your array

when reading from the listview use the ID to identify items that have a colour value in your array

I see fascists...

Link to comment
Share on other sites

@rover

Thanks for nice example!

Unfortunately this is very ineficient way for many rows because you need to physically redraw listview for each row.

I think this your way doesn't work for other then first try because system (Windows) somehow cached once rendered rows and it know rows didn't change - probably.

I tried modification of your script to use just RedrawWindow API instead of MouseMove but it doesn't work, anyway here is my script:

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

Global $lv_item ; filled before calling WM_NOTIFY
Global $lv_color ; filled in WM_NOTIFY

Global $GUI = GUICreate("Listview Custom Draw", 300, 400)
Global $cListView = GUICtrlCreateListView("Column 1|Column 2|Column 3", 2, 2, 396, 330)
Global $hListView = GUICtrlGetHandle($cListView)
Global $cbutton = GUICtrlCreateButton("Get colors", 100, 350, 100, 20)
For $i = 1 To 15
    GUICtrlCreateListViewItem("Row" & $i & ": Col 1|Row" & $i & ": Col 2|Row" & $i & ": Col 3", $cListView)
    ; some coloring of items
    $color = 0x0
    If Mod($i, 2) Then $color = 0xFF0000
    If Not Mod($i, 4) Then $color = 0x0000FF
    If Not Mod($i, 3) Then $color = 0x00FF00
    GUICtrlSetColor(-1, $color)
Next
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
GUISetState()

While 1
    $msg = GUIGetMsg()
    If $msg = $GUI_EVENT_CLOSE Then ExitLoop
    If $msg = $cbutton Then GetColors()
WEnd
Exit

Func GetColors()
    $colors = ''
    For $i = 1 To _GUICtrlListView_GetItemCount($cListView)
        $color = GetColor($i)
        $colors &= 'LV item=' & $i & ' color=' & $color & @CRLF
    Next
    MsgBox(0, 'ListView Item Colors', $colors)
EndFunc   ;==>GetColors

Func GetColor($index)
    $lv_item = $index ; set global variable
    _GUICtrlListView_EnsureVisible($hListView, $index, False)
;~    _WinAPI_InvalidateRect($hListView, 0, 0)
    _WinAPI_RedrawWindow($hListView) ; invoke $NM_CUSTOMDRAW
    $lv_item = -1
    Return $lv_color ; read global variable
EndFunc   ;==>GetColor

Func WM_NOTIFY($hWnd, $msg, $wParam, $lParam)
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR
    $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    $hWndFrom = DllStructGetData($tNMHDR, "hWndFrom")
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $iIDFrom

        Case $cListView
            Switch $iCode

                Case $NM_CUSTOMDRAW
                    Local $tCustDraw = DllStructCreate($tagNMLVCUSTOMDRAW, $lParam)
                    Local $iItem = DllStructGetData($tCustDraw, "dwItemSpec")

;~                     $tmp = "0x" & StringRegExpReplace(Hex(DllStructGetData($tCustDraw, "clrText"), 6), "(.{2})(.{2})(.{2})", "\3\2\1")
;~                     ConsoleWrite('NM_CUSTOMDRAW iItem: ' & $iItem & " Txt: " & $tmp & @CRLF)

                    Switch DllStructGetData($tCustDraw, "dwDrawStage")
                        Case $CDDS_PREPAINT
;~                             $tmp = "0x" & StringRegExpReplace(Hex(DllStructGetData($tCustDraw, "clrText"), 6), "(.{2})(.{2})(.{2})", "\3\2\1")
;~                             ConsoleWrite('CDDS_PREPAINT iItem: ' & $iItem & " Txt: " & $tmp & @CRLF)
                            Return BitOR($CDRF_NOTIFYITEMDRAW, $CDRF_NOTIFYPOSTPAINT)

                        Case $CDDS_POSTPAINT
;~                             $tmp = "0x" & StringRegExpReplace(Hex(DllStructGetData($tCustDraw, "clrText"), 6), "(.{2})(.{2})(.{2})", "\3\2\1")
;~                             ConsoleWrite('CDDS_POSTPAINT iItem: ' & $iItem & " Txt: " & $tmp & @CRLF)

                            If $lv_item <> -1 And $lv_item = $iItem Then
                                $lv_color = "0x" & StringRegExpReplace(Hex(DllStructGetData($tCustDraw, "clrText"), 6), "(.{2})(.{2})(.{2})", "\3\2\1")
;~                                 ConsoleWrite('-$ 2 iItem: ' & $iItem & " Txt: " & $lv_color & @CRLF)
                            EndIf
                    EndSwitch
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY
Link to comment
Share on other sites

@rover

Thanks for nice example!

Unfortunately this is very ineficient way for many rows because you need to physically redraw listview for each row.

I think this your way doesn't work for other then first try because system (Windows) somehow cached once rendered rows and it know rows didn't change - probably.

I tried modification of your script to use just RedrawWindow API instead of MouseMove but it doesn't work, anyway here is my script:

I couldn't get any of the usual redraw/paint/invalidate methods to work with this.

As you can see, most of the items report incorrect colours, and the returned item index from the struct is sometimes a large invalid number.

This just isn't a supported feature.

be seeing you...

I see fascists...

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