Jump to content

ListBox selection mistakenly calls menu handler


AndyS01
 Share

Recommended Posts

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.

Link to comment
Share on other sites

  • Moderators

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

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

 

Link to comment
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?

Link to comment
Share on other sites

  • Moderators

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

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

 

Link to comment
Share on other sites

  • Moderators

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

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

 

Link to comment
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?

Link to comment
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.

Link to comment
Share on other sites

  • Moderators

AndyS01,

Excellent news. ;)

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

 

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