Sign in to follow this  
Followers 0
AndyS01

ListBox selection mistakenly calls menu handler

9 posts in this topic

I have a script that creates a file menu and a ListView box with several items and when I click on some of the items, the handler registered to the menu items inadvertantly gets called!

Here is my test code:

#NoTrayIcon

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

Opt("GUIOnEventMode", 1) ; Change to OnEvent mode
Opt('MustDeclareVars', 1)
Opt("GUIEventOptions", 1) ;0=default, 1=just notification, 2=GuiCtrlRead tab index

Global $hWnd_MainWin
Global $iListView_ID
Global $iListView_hWnd

Global $sNamePWDSep = Opt("GUIDataSeparatorChar")

_Main()
exit (0)

;;;;;;;;;;;;;;;;;;;;;;;;;;
; _Main() - Main function
;;;;;;;;;;;;;;;;;;;;;;;;;;
Func _Main()
    Local $row, $aItem, $iIndex, $HeaderCols, $aMasterList[7]

    $hWnd_MainWin = GUICreate("Test", 340 - 16, 300 - 16) ; Create the Main GUI

    create_menus()

    $iListView_ID = GUICtrlCreateListView("", 10, 10, 300, 200)
    $iListView_hWnd = GUICtrlGetHandle($iListView_ID)

    _GUICtrlListView_AddColumn($iListView_hWnd, "F1", 30)
    _GUICtrlListView_AddColumn($iListView_hWnd, "F2", 90)

    $HeaderCols = 2

    GUISetState(@SW_SHOW) ; show the GUI

    $aMasterList[0] = "a|Q"
    $aMasterList[1] = "b|W"
    $aMasterList[2] = "c|E"
    $aMasterList[3] = "d|R"
    $aMasterList[4] = "e|T"
    $aMasterList[5] = "f|Y"
    $aMasterList[6] = "g|U"

    For $row = 0 To UBound($aMasterList) - 1
        $aItem = StringSplit($aMasterList[$row], $sNamePWDSep)
        $iIndex = _GUICtrlListView_AddItem($iListView_hWnd, $aItem[1], -1, $row)
        For $ndx = 2 To $HeaderCols
            _GUICtrlListView_AddSubItem($iListView_hWnd, $iIndex, $aItem[$ndx], $ndx - 1)
        Next
    Next

    GUISetOnEvent($GUI_EVENT_CLOSE, 'Event_GUIClose') ; CLOSE events

    GUISetState() ; Make everything visible

    While 1
        Sleep(500)
    WEnd
EndFunc   ;==>_Main

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; create_menus() - Create the main menu and all of its submenus
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Func create_menus()
    Local $iID_Menu

    $iID_Menu = GUICtrlCreateMenu("&File")
    addMenuItem($iID_Menu, "Open", "handle_menu_open")
    addMenuItem($iID_Menu, "Save", "handle_menu_SAVE")
    addMenuItem($iID_Menu, "Save As...", "handle_menu_SAVE_AS")
    addMenuItem($iID_Menu, "Revert", "handle_menu_revert")
    addMenuItem($iID_Menu, "Exit", "handle_EXIT_btn")

EndFunc   ;==>create_menus

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; addMenuItem() - Add a menu item to a menu
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Func addMenuItem($id, $title, $handler = "")
    Local $sid

    $sid = GUICtrlCreateMenuItem($title, $id)

    If ($handler <> "") Then
        GUICtrlSetOnEvent($sid, $handler)
    EndIf
EndFunc   ;==>addMenuItem

Func ErrorPopup($msg)
    MsgBox(0 + 16, "ERROR", $msg)
    exit (1)
EndFunc   ;==>ErrorPopup

Func Event_GUIClose()
    exit (0)
EndFunc   ;==>Event_GUIClose

Func handle_EXIT_btn()
    exit (0)
EndFunc   ;==>handle_EXIT_btn

Func saveToFile()
    ErrorPopup("saveToFile() entered")
EndFunc   ;==>saveToFile

Func handle_menu_revert()
    ErrorPopup("handle_menu_revert() entered")
EndFunc   ;==>handle_menu_revert

Func handle_MENU_OPEN()
    ErrorPopup("handle_MENU_OPEN() entered")
EndFunc   ;==>handle_MENU_OPEN

Func handle_menu_SAVE()
    ErrorPopup("handle_menu_SAVE() entered")
EndFunc   ;==>handle_menu_SAVE

Func handle_menu_SAVE_AS()
    ErrorPopup("handle_menu_SAVE_AS() entered")
EndFunc   ;==>handle_menu_SAVE_AS

Run this script and click on some of the ListView items and notice that an Error MsgBox is displayed, saying a certain menu selection has been made.

Note that removing, adding or re-arranginh menu items seems to change which handler gets called.

Share this post


Link to post
Share on other sites



AndyS01,

Try not to mix native and UDF commands when creatign controls - it ususally ends in tears. ;) As you created the ListView with GUICtrlCreateListView, you need to add the items with GUICtrlCreateListViewItem.

This code works fine for me:

#NoTrayIcon

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

Opt("GUIOnEventMode", 1) ; Change to OnEvent mode
Opt('MustDeclareVars', 1)
Opt("GUIEventOptions", 1) ;0=default, 1=just notification, 2=GuiCtrlRead tab index

Global $hWnd_MainWin
Global $iListView_ID
Global $iListView_hWnd

Global $sNamePWDSep = Opt("GUIDataSeparatorChar")

_Main()
Exit (0)

;;;;;;;;;;;;;;;;;;;;;;;;;;
; _Main() - Main function
;;;;;;;;;;;;;;;;;;;;;;;;;;
Func _Main()
    Local $row, $aItem, $iIndex, $HeaderCols, $aMasterList[7]

    $hWnd_MainWin = GUICreate("Test", 340 - 16, 300 - 16) ; Create the Main GUI
    GUISetOnEvent($GUI_EVENT_CLOSE, 'Event_GUIClose') ; CLOSE events

    create_menus()

    $iListView_ID = GUICtrlCreateListView("F1|F2", 10, 10, 300, 200)
    $iListView_hWnd = GUICtrlGetHandle($iListView_ID)

    _GUICtrlListView_SetColumnWidth($iListView_ID, 0, 30)
    _GUICtrlListView_SetColumnWidth($iListView_ID, 1, 90)

    $aMasterList[0] = "a|Q"
    $aMasterList[1] = "b|W"
    $aMasterList[2] = "c|E"
    $aMasterList[3] = "d|R"
    $aMasterList[4] = "e|T"
    $aMasterList[5] = "f|Y"
    $aMasterList[6] = "g|U"

    For $row = 0 To UBound($aMasterList) - 1
        GUICtrlCreateListViewItem($aMasterList[$row], $iListView_ID)
    Next

    GUISetState() ; Make everything visible

    While 1
        Sleep(500)
    WEnd
EndFunc   ;==>_Main

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; create_menus() - Create the main menu and all of its submenus
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Func create_menus()
    Local $iID_Menu

    $iID_Menu = GUICtrlCreateMenu("&File")
    addMenuItem($iID_Menu, "Open", "handle_menu_open")
    addMenuItem($iID_Menu, "Save", "handle_menu_SAVE")
    addMenuItem($iID_Menu, "Save As...", "handle_menu_SAVE_AS")
    addMenuItem($iID_Menu, "Revert", "handle_menu_revert")
    addMenuItem($iID_Menu, "Exit", "handle_EXIT_btn")

EndFunc   ;==>create_menus

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; addMenuItem() - Add a menu item to a menu
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Func addMenuItem($id, $title, $handler = "")
    Local $sid

    $sid = GUICtrlCreateMenuItem($title, $id)

    If ($handler <> "") Then
        GUICtrlSetOnEvent($sid, $handler)
    EndIf
EndFunc   ;==>addMenuItem

Func ErrorPopup($msg)
    MsgBox(0 + 16, "ERROR", $msg)
    Exit (1)
EndFunc   ;==>ErrorPopup

Func Event_GUIClose()
    Exit (0)
EndFunc   ;==>Event_GUIClose

Func handle_EXIT_btn()
    Exit (0)
EndFunc   ;==>handle_EXIT_btn

Func saveToFile()
    ErrorPopup("saveToFile() entered")
EndFunc   ;==>saveToFile

Func handle_menu_revert()
    ErrorPopup("handle_menu_revert() entered")
EndFunc   ;==>handle_menu_revert

Func handle_MENU_OPEN()
    ErrorPopup("handle_MENU_OPEN() entered")
EndFunc   ;==>handle_MENU_OPEN

Func handle_menu_SAVE()
    ErrorPopup("handle_menu_SAVE() entered")
EndFunc   ;==>handle_menu_SAVE

Func handle_menu_SAVE_AS()
    ErrorPopup("handle_menu_SAVE_AS() entered")
EndFunc   ;==>handle_menu_SAVE_AS

I know I am using _GUICtrlListView_SetColumnWidth, but this is one of the UDF commands that you can use on a native ListView, do not ask me why though! :)

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

The problem is that in the actual script, I want to do column sorting using the Quick Sort. The only way I could see to do that was to call the _GUICtrlListView_UnRegisterSortCallBack() function. In the F1 help example for that function, it mixes the 2 methods. I went back to the original script and made the changes you suggested and, indeed, I didn't have the menu callback problem. However, the Quick Sort functionality stopped working.

I tried using _GUICtrlListView_Create() to create the ListView, but then I needed to get the ID of the ListView control for some other operations in the script and I cannot figure out how to get the ListView's ID (to convert an ID to a handle, I call GUICtrlGetHandle($id), but I could not find an operation that does the reverse). If I could solve this issue, I could try it on my actual script. And ideas?

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

AndyS01,

I needed to get the ID of the ListView control for some other operations in the script

What operations are these? There may be a way around it. :shocked:

Thanks for pointing out that the Help file example mixing the native and UDF commands - I (and many others here) try not to mix them unless I absolutely must and it is interesting to see how they have been intermixed here. I will have another look at your original script and see if I can solve the problem while retaining the ListView code as you had it. :)

M23

Edit,

I now know why the ListView items action the menu items. AutoIt uses the ControlID of a control to action OnEvent handlers. The handlers are also reacting to the Index numbers of the ListView rows - AutoIt is picking up the "ListView Row Selection" message and treating it as the same numbered "Control Actioned" message.

As a short-term fix, you can solve the problem by creating a dummy control after each ListView Item - this eats up the ControlID numbers to make sure that you "real" ControlIDs are always higher than the Index numbers of the ListView:

$iIndex = _GUICtrlListView_AddItem($iListView_hWnd, $aItem[1], -1, $row)
GUICtrlCreateDummy()

You then create the menu controls and any other controls after the ListView. Like I said, this is a short-term fix as if you have a dynamic ListView this might pose a serious problem.

So my view that you should not mix the native and UDF functions remains unchanged. As I said above, let me know why you need the ID of the ListView control and there might well be a way around it. ;)

I am off to study this whole thing a bit closer. ;)

M23

Edited by Melba23

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

Problem solved. When I created the ListBox using GUICtrlCreateListView() and added items using GUICtrlCreateListViewItem() as you suggested, after some tweaking, the Quick Sort now works.

Whew!

Thank you for your help.

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

AndyS01,

You problem solved, but a wider problem remains. ;) See above for an explanation of what was going on. :)

M23

Edit:

The bigger problem is also solved. I have just noticed that you were setting $iParam when you used _GUICtrlListView_AddItem. This is what AutoIt uses to store the ControlID when it creates ListView items with the native control - hence AutoIt thought that this was a native control and fired the event handler. If you use this:

$iIndex = _GUICtrlListView_AddItem($iListView_hWnd, $aItem[1])

to create the items, you do not get the interaction we saw earlier.

So you can now use either way to create your ListView - although as you can guess, I strongly recommend the "single source" method! :shocked:

Thnaks for that - a lot of fun sorting it out. ;)

M23

Edited by Melba23

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-Oh, the Quick Sort is now NOT doing an actual sort. It changes the direction arrow icon in the column header, but doesn't actually sort anything. Upon investigation, I see that the Quick Sort (__GUICtrlListView_Sort) uses the $param value to find the text for the items to compare. I see that the sort callback function is always being passed the $param values of 0,0 for it's parameters. It uses the $LVFI_PARAM flag in the $tagLVFINDINFO structure, so the $param must be present and must be unique among all of the ListView items. That's why I stored the row number there.

So where are we now? If I use GUICtrlCreateListViewItem() to create the ListView items, then the Quick Sort has no unique data in the $param for each item.

It looks like I have to use the _GuiCtrlListView_Create() function to create the ListView, but then I have the problem where I cannot get the control ID, which I need for other operations (such as GUICtrlSetPos() when the window gets resized).

Am I getting wrapped around the axel?

Share this post


Link to post
Share on other sites

I bit the bullet and changed the other functions to use handles instead of IDs and it looks like everything is working correctly. I still had to specify the row number in the $param value, but it didn't mess up the click handling because I no longer mix native and UDF function calls for the listbox.

Share this post


Link to post
Share on other sites

AndyS01,

Excellent news. ;)

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

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
Sign in to follow this  
Followers 0