Jump to content
Kira16651

List Item returns Index of -1 from $tagNMITEMACTIVATE

Recommended Posts

Kira16651

Hello,

I'm wanted to click on a List Item and get its Index (Row). In the example for _GuiCtrlListView_Create this works beautifully.

When I do the same thing in my code I always get an Index of -1. I found out in the documentation of $tagNMITEMACTIVATE that this is the case if the index is not used for the notification.

I have no idea what that means. Any idea how I could search for that or how I can set it to be used for notifications?

I put only the relevant parts of my code here:

#Region ### START Koda GUI section ### Form=q:\programme\autoit\gui_main.kxf
$hGuiWindow = GUICreate("Aktuelle Projekte", 616, 408, 592, 469)
$hGuiListview = _GUICtrlListView_Create($hGuiWindow, "Projektnummer|Kunde|Maschinentyp|Kommentar|Gewichtung|everything", 8, 40, 601, 357)
$hGuiInput = GUICtrlCreateEdit("", 8, 8, 601, 21)
GUISetState(@SW_SHOW)
_WinAPI_SetFocus(ControlGetHandle($hGuiWindow, "", $hGuiInput))
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
#EndRegion ### END Koda GUI section ###

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

    $sGuiInput = GUICtrlRead($hGuiInput) ; read what the search string is

    If StringRight($sGuiInput, 2) = @CRLF Then ; if return has been pressed in the search field ...
        GUIDelete($hGuiWindow)
        Send($sProjectNumber)
        Exit
    ElseIf $sGuiInput <> $sGuiInputPrev Then ; if the input in the search field has changed ...
        _GUICtrlListView_DeleteAllItems($hGuiListview) ; ... delete everything that was in the list box

        Local $aGuiInput = StringSplit($sGuiInput, " ", 2) ; split the search string into multiple at the space

        Local $aResults = _LiveSearchResults2D($aProjects, _ArrayToString($aGuiInput, " "), 5, 4) ; put the words into a string and search and add weight
        $sProjectNumber = $aResults[0][0] ; put the top most article number into the global variable
        ; $aResults = _2DArray_To_1D_Array_With_Strings($aResults, "|") ; todo: completely remove this
        _DisplayResultsAdvanced($hGuiListview, $aResults)

        _GUICtrlListView_SetColumnWidth($hGuiListview, 0, $LVSCW_AUTOSIZE)
        _GUICtrlListView_SetColumnWidth($hGuiListview, 1, $LVSCW_AUTOSIZE)
        _GUICtrlListView_SetColumnWidth($hGuiListview, 2, $LVSCW_AUTOSIZE)
        _GUICtrlListView_SetColumnWidth($hGuiListview, 3, $LVSCW_AUTOSIZE)
        _GUICtrlListView_SetColumnWidth($hGuiListview, 4, $LVSCW_AUTOSIZE)
    EndIf

    $sGuiInputPrev = $sGuiInput ; set the variable for the previous input for the next cycle

    Sleep(10) ; sleep a bit so that the proccess is not consuming 100% of the cpu
WEnd

Func _DisplayResultsAdvanced($hListView, $aArray, $sString = "test") ; displays the array in the list view
    For $Row = 0 To UBound($aArray) - 1 ; creates the list view items
        _GUICtrlListView_AddItem($hListView, $aArray[$Row][0], $Row)
        For $Col = 1 To UBound($aArray, 2) - 1 ; only first four columns are important here
            _GUICtrlListView_AddSubItem($hListView, $Row, $aArray[$Row][$Col], $Col)
        Next
    Next
EndFunc   ;==>_DisplayResultsAdvanced

Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iMsg, $iwParam
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListView, $tInfo
    ; Local $tBuffer
    $hWndListView = $hGuiListview
    If Not IsHWnd($hGuiListview) Then $hWndListView = GUICtrlGetHandle($hGuiListview)

    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
        Case $hWndListView
            Switch $iCode
                Case $NM_CLICK ; Sent by a list-view control when the user clicks an item with the left mouse button
                    $tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam)
                    Local $iIndex = DllStructGetData($tInfo, "Index")
                    ConsoleWrite($iIndex & @CRLF)
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

 

 

Share this post


Link to post
Share on other sites
Melba23

Kira16651,

It really helps if you post runnable code - the _LiveSearchResults2D function is missing.

Substituting a dummy array shows that you do get the correct answer if you click on the first item of each line, but not if you click on the subitems. If you set the whole line to be selected using: _GUICtrlListView_SetExtendedListViewStyle($hGuiListview, $LVS_EX_FULLROWSELECT) then you also get the correct answer even when clicking the subitems.

M23


Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see 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
Kira16651

Thanks! That is exactly what I was looking for.

Sorry about the code, thought it would be too much of a mess if I posted everything.

For completeness sake here the complete code and an example csv file which is also used.

Keep in mind I just got this working for the first time so it's probably still buggy. It's still a work in progress.

; ------- Version History ----------------------------
; Author       | Date       | Version | New features in this Version
; Tobias Beitz | 2015-05-29 | 0.01    | Created the file.
;
; ------- Script Description -------------------------
;
; opens a window where the user can type things in a search bar and search for projects
; the results are weighted with the best result at the top
; pressing return will insert the project number
; pressing esc will close the window
; users can also just click the project to insert the project number
;
; ----------------------------------------------------

;######## todo #######
; - display all the projects even if nothing was typed yet
; - if nothing is in the input, display all the projects again unsorted
; - if you press tab you switch to all projects ever instead of just current projects

;##### stuff we need for this script
#include <File.au3>
#include <Array.au3>
#include <MsgBoxConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <Misc.au3>

;##### stuff needed for the gui
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIListBox.au3>
#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <GuiImageList.au3>

#Region ### START Koda GUI section ### Form=q:\programme\autoit\gui_main.kxf
$hGuiWindow = GUICreate("Aktuelle Projekte", 700, 500)
$hGuiInput = GUICtrlCreateEdit("", 8, 8, 700 - 16 - 150, 21, BitOR($ES_AUTOVSCROLL, $ES_AUTOHSCROLL, $ES_WANTRETURN))
$hGuiListview = _GUICtrlListView_Create($hGuiWindow, "Projektnummer|Kunde|Maschinentyp|Maschinennummer|Kommentar|Gewichtung|everything", 8, 37, 700 - 16, 500 - 45)
_GUICtrlListView_SetExtendedListViewStyle($hGuiListview, $LVS_EX_FULLROWSELECT)
$hGuiButtonSwitchMode = GUICtrlCreateButton("zeig alle Projekte", 700 - 8 - 150, 8, 150, 21)
GUISetState(@SW_SHOW)
_WinAPI_SetFocus(ControlGetHandle($hGuiWindow, "", $hGuiInput))
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
#EndRegion ### END Koda GUI section ###

;####### global variables
Global $aProjects
_ReadFileToArray("./aktuelle_projekte_liste.csv")
Global $sGuiInput = "" ; read input
Global $sGuiInputPrev = "" ; save previous input
Global $sProjectNumber = "" ; the project number we want to know/insert
Global $sMachineNumber = "" ; the machine number we want to know/insert
Global $sMode = "current" ; the mode we are in. "current" = only show current projects. "all" = show all projects
Global $iClickedIndex = -1 ; if -1 then nothing happens, if >= 0 then insert project number from the indexed row
Global $aResults ; results array of the live search

_FilterAndDisplayArrayInListView($hGuiListview, "", $aProjects) ; show an initial unfiltered and unsorted list

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $hGuiButtonSwitchMode
            If $sMode = "current" Then
                $sMode = "all"
                GUICtrlSetData($hGuiButtonSwitchMode, "zeig aktuelle Projekte")
                WinSetTitle($hGuiWindow, "", "Alle Projekte")
                _ReadFileToArray("./alle_projekte_liste.csv")
            ElseIf $sMode = "all" Then
                $sMode = "current"
                GUICtrlSetData($hGuiButtonSwitchMode, "zeig alle Projekte")
                WinSetTitle($hGuiWindow, "", "Aktuelle Projekte")
                _ReadFileToArray("./aktuelle_projekte_liste.csv")
            EndIf
            ; repopulate the list view and filter it and sort it and stuff
            Local $aGuiInput = StringSplit($sGuiInput, " ", 2) ; split the search string into multiple at the space
            _FilterAndDisplayArrayInListView($hGuiListview, $aGuiInput, $aProjects)
    EndSwitch

    $sGuiInput = GUICtrlRead($hGuiInput) ; read what the search string is

    if $iClickedIndex >= 0 Then ; if we clicked on a list item
        $sProjectNumber = $aResults[$iClickedIndex][0] ; put the top most project number into the global variable
        $sMachineNumber = $aResults[$iClickedIndex][3] ; put the top most machine number into the global variable
    EndIf

    If StringRight($sGuiInput, 2) = @CRLF or $iClickedIndex >= 0 Then ; if return has been pressed in the search field or we clicked a list item ...
        If _IsPressed(10) Then ; if shift is pressed ...
            GUIDelete($hGuiWindow)
            Send($sMachineNumber) ; ... send machine number ...
            Exit
        Else
            GUIDelete($hGuiWindow)
            Send($sProjectNumber) ; ... otherwise send project number
            Exit
        EndIf
    ElseIf $sGuiInput <> $sGuiInputPrev Then ; if the input in the search field has changed ...
        Local $aGuiInput = StringSplit($sGuiInput, " ", 2) ; split the search string into multiple at the space
        _FilterAndDisplayArrayInListView($hGuiListview, $aGuiInput, $aProjects)
    EndIf

    $sGuiInputPrev = $sGuiInput ; set the variable for the previous input for the next cycle

    Sleep(10) ; sleep a bit so that the proccess is not consuming 100% of the cpu
WEnd

;######### functions

Func _ReadFileToArray($sFilePath)
    Global $aProjects = _CSV_2_2DArray($sFilePath) ; Inhalt der csv datei einlesen und im array speichern
    ReDim $aProjects[UBound($aProjects)][7]
    For $Row = 0 To UBound($aProjects) - 1 ; for each row ...
        Local $sEverything = "" ; todo: add comments
        For $Col = 0 To 5
            $sEverything = $sEverything & " " & $aProjects[$Row][$Col]
        Next
        $aProjects[$Row][6] = $sEverything
    Next
EndFunc

Func _FilterAndDisplayArrayInListView($hGuiListview, $aGuiInput, $aArray)
    _GUICtrlListView_DeleteAllItems($hGuiListview) ; ... delete everything that was in the list box

    $aResults = _LiveSearchResults2D($aArray, _ArrayToString($aGuiInput, " "), 6, 5) ; put the words into a string and search and add weight
    $sProjectNumber = $aResults[0][0] ; put the top most project number into the global variable
    $sMachineNumber = $aResults[0][3] ; put the top most machine number into the global variable
    _DisplayResultsAdvanced($hGuiListview, $aResults)

    _GUICtrlListView_SetColumnWidth($hGuiListview, 0, $LVSCW_AUTOSIZE)
    _GUICtrlListView_SetColumnWidth($hGuiListview, 1, $LVSCW_AUTOSIZE)
    _GUICtrlListView_SetColumnWidth($hGuiListview, 2, $LVSCW_AUTOSIZE)
    _GUICtrlListView_SetColumnWidth($hGuiListview, 3, $LVSCW_AUTOSIZE)
    _GUICtrlListView_SetColumnWidth($hGuiListview, 4, $LVSCW_AUTOSIZE)
    _GUICtrlListView_SetColumnWidth($hGuiListview, 5, $LVSCW_AUTOSIZE)
    _GUICtrlListView_SetColumnWidth($hGuiListview, 6, $LVSCW_AUTOSIZE)
EndFunc   ;==>_FilterAndDisplayArrayInListView

Func _2DArray_To_1D_Array_With_Strings($aArray, $sDelimiter) ; takes 2d $aArray and converts each element into a string with the given $sDelimiter
    Local $sSubString ; each row will be seperately saved in this string
    Local $aReturnArray[UBound($aArray)] ; the array that will be returned

    Local $Rows = UBound($aArray) - 1
    Local $Columns = UBound($aArray, 2) - 1

    If $Rows < 2 Then
        Return "ERROR in 2d array to 1d array ... function"
    EndIf

    For $Row = 0 To $Rows
        $sSubString = $aArray[$Row][0] ; put first element in substring
        For $Col = 1 To $Columns
            $sSubString = $sSubString & $sDelimiter & $aArray[$Row][$Col] ; add the next thing to the substring
        Next
        $aReturnArray[$Row] = $sSubString ; put the substring into the row
    Next
    Return $aReturnArray
EndFunc   ;==>_2DArray_To_1D_Array_With_Strings

Func _CSV_2_2DArray($file, $delim = ";") ; loads csv, returns 2d array
    Local $aLines
    Local $hFile = _FileReadToArray($file, $aLines, 0)

    Local $a2DArray[UBound($aLines)][UBound(StringSplit($aLines[0], $delim)) - 1]
    Local $aSubstring
    For $line = 0 To UBound($aLines) - 1
        $aSubstring = StringSplit($aLines[$line], $delim)
        For $Col = 1 To $aSubstring[0]
            $a2DArray[$line][$Col - 1] = $aSubstring[$Col]
        Next
    Next
    Return $a2DArray
EndFunc   ;==>_CSV_2_2DArray

Func _LiveSearchResults2D($aArray, $sString, $iColumn = 0, $iAddToWeight = -1) ; searches for string in array in column. returns array matches with first column with the weight of the match
    ; $aArray: the 2d array that is being searched through
    ; $sString: the search string
    ; $iColumn: the column that is being searched through
    ; $iAddToWeight: if -1 a new first column will be added with the weight. if bigger the column with that number will be used as the weight

    Local $iWeight ; the weight
    Local $sWord ; the word, that is being checked, not the search string
    If $iAddToWeight = -1 Then ; add extra column for the weight
        Local $aReturnArray[UBound($aArray)][UBound($aArray, 2) + 1]; the array that is going to be returned
    Else ; no extra column since the first one will be interpreted as the weight
        Local $aReturnArray[UBound($aArray)][UBound($aArray, 2)]; the array that is going to be returned
    EndIf

    For $i = 0 To UBound($aArray) - 1 ; compare each element in the array with the search string
        $sWord = $aArray[$i][$iColumn] ; put the search word into the variable
        If $iAddToWeight = -1 Then
            $aReturnArray[$i][$iColumn + 1] = $sWord ; put the article number into the temp array. we work only with that since we don't need the rest
        Else
            $aReturnArray[$i][$iColumn] = $sWord ; put the article number into the temp array. we work only with that since we don't need the rest
        EndIf

        If $iAddToWeight = -1 Then
            $iWeight = 0 ; set the initial weight to 0
        Else
            $iWeight = $aArray[$i][$iAddToWeight] ; set the initial weight to whatever is in the first column
        EndIf

        If $sWord = $sString Then ; if string is an exact match
            $iWeight += 1000
        Else ; if the string is not an exact match
            Local $aSplitString = StringSplit($sString, " ", 2) ; split the search string into multiple words, if there are any
            For $s = 0 To UBound($aSplitString) - 1 ; search and add weight for each word typed in
                Local $sSubString = $aSplitString[$s] ; save the substring in this variable
                If StringInStr($sWord, $sSubString, 2) Then ; if the string is a substring (case doesn't matter), it will be evaluated further
                    $iWeight += 100 ; if the substring has been found, add weight

                    ; add: 77   string has same left word boundry
                    If StringRegExp($sWord, "(?i)(^|#| )" & $sSubString) = 1 Then
                        $iWeight += 77
                    EndIf
                    ; add: 54   string has same right word boundry
                    If StringRegExp($sWord, "(?i)" & $sSubString & "($|#| )") = 1 Then
                        $iWeight += 54
                    EndIf
                Else
                    $iWeight -= 50 ; if nothing was found, decrease the weight by 100. this is needed when multiple words have been typed. one adds lots of weight, the other reduces it. so only relevant strings remain on top.
                EndIf
            Next
        EndIf

        If $iAddToWeight = -1 Then ; add things 1 column to the right, since we add the weight in the first column
            $aReturnArray[$i][0] = $iWeight - StringLen($sWord); add the weight to the array in column 0
            For $tempCol = 1 To UBound($aReturnArray, 2) - 1 ; fill the array with the things in the other array
                $aReturnArray[$i][$tempCol] = $aArray[$i][$tempCol - 1]
            Next
        Else ; add things in the same column
            For $tempCol = 0 To UBound($aReturnArray, 2) - 1 ; fill the array with the things in the other array
                $aReturnArray[$i][$tempCol] = $aArray[$i][$tempCol]
                $aReturnArray[$i][$iAddToWeight] = $iWeight - StringLen($sWord); add the weight to the array
            Next
        EndIf
    Next
    If $iAddToWeight = -1 Then
        _ArraySort($aReturnArray, 1, 0, 0, 0) ; sort the first column, decending (sorts by weight)
    Else
        _ArraySort($aReturnArray, 1, 0, 0, $iAddToWeight) ; sort the first column, decending (sorts by weight)
    EndIf

    Return $aReturnArray
EndFunc   ;==>_LiveSearchResults2D

Func _DisplayResultsAdvanced($hListView, $aArray, $sString = "test") ; displays the array in the list view
    For $Row = 0 To UBound($aArray) - 1 ; creates the list view items
        _GUICtrlListView_AddItem($hListView, $aArray[$Row][0], $Row)
        For $Col = 1 To UBound($aArray, 2) - 1 ; only first four columns are important here
            _GUICtrlListView_AddSubItem($hListView, $Row, $aArray[$Row][$Col], $Col)
        Next
    Next
EndFunc   ;==>_DisplayResultsAdvanced

Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    #horseref $hWnd, $iMsg, $iwParam
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListView, $tInfo
    ; Local $tBuffer
    $hWndListView = $hGuiListview
    If Not IsHWnd($hGuiListview) Then $hWndListView = GUICtrlGetHandle($hGuiListview)

    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
        Case $hWndListView
            Switch $iCode
                Case $NM_CLICK ; Sent by a list-view control when the user clicks an item with the left mouse button
                    $tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam)
                    $iClickedIndex = DllStructGetData($tInfo, "Index")
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

 

aktuelle_projekte_liste.csv

alle_projekte_liste.csv

Edited by Kira16651

Share this post


Link to post
Share on other sites
Melba23

Kira16651,

Glad I could help - and welcome to the AutoIt forums, by the way.

M23

 


Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see 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

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

×