[wxPython] EVT_MENU generates extra events when check true

Trying to debug an error, I discovered that EVT_MENU will generate 2 events
for every click of a menu that's marked as "checkable". You can distinguish
between the events by checking event.GetInt(), but I didn't find any
documentation that mentioned this need. Possibly adding verbage to:

    wxMenu "Event Handling"
    wxCommandEvent EVT_MENU entry

Also general documentation comment, should link from
command-event-generating controls directly to the wxCommandEvent page, since
that's where you get information about the events being generated. i.e. See
Also would include wxCommandEvent.

Not sure what the constants 0,1 and 106 for the GetInt() values are actually
representing, incidentally.

Here's a test program showing the values generated...

Enjoy,
Mike

8<______ test_menu_check.py ____________
from wxPython.wx import *

import os, string

class SetBuilder( wxFrame ):
    previewWindow = None
    propertiesWindow = None
    processWindow = None
    codeWindow = None
    menuData = [
        ("&File", [
            ("&New Set","Create a new Set", "OnSetNew", None,None, FALSE),
            ("&Open Set...","Open an existing Set", "OnSetOpen", None,None,
FALSE),
            ("&Save Set","Save the current Set", "OnSetSave", None,None,
FALSE),
            ("Save Set &As...","Save the current Set to a new name",
"OnSetSaveAs", None,None, FALSE),
            ("","","", None, None, FALSE),
            ("&Reload","Reload the world from disk file", "OnReload",
None,None, FALSE),
            ("","","", None, None, FALSE),
            ("E&xit\t<Alt-F4>", "Exit Set Builder", "OnExit", None,
(wxACCEL_ALT , WXK_F4 ), FALSE),
        ]),
        ("&Window", [
            ("Pre&view","Preview set in Cortona", "OnPreviewWindow",
None,None, TRUE),
            ("&Process Editor","Edit the SceneGraph's OnLoad processes",
"OnProccessWindow", None,None, TRUE),
        ]),
    ]
    def __init__(
        self, parent = NULL, id = -1, title="Set Builder",
        pos = wxDefaultPosition, size = (500,150),
        style=wxDEFAULT_FRAME_STYLE , name = "SetBuilder",
        object = None,
    ):
        wxFrame.__init__( self, parent, id, title, pos, size, style, name )
        self._buildMenus()

    def OnPreviewWindow( self, event ):
        '''Show/hide the preview window'''
        if event.IsChecked():
            # the window should now be visible
            print 'was checked', event, event.IsSelection(), event.GetInt()
        else:
            print 'not checked', event, event.IsSelection(), event.GetInt()
        event.Skip()
    ### Utility functions
    def _buildMenus (self):
        self.menu = menubar = wxMenuBar()
        self.menumapping = {}
        accelerators = []
        for name, children in self.menuData:
            menu=wxMenu ()
            for text,description,method, ID, acceleratordata, checkable in
children:
                if not text:
                    menu.AppendSeparator ()
                else:
                    if ID is None:
                        ID =wxNewId()
                    item = wxMenuItem (menu,ID,text ,description, checkable)
                    if checkable:
                        self.menumapping [(name,text)] = item
                    menu.AppendItem ( item )
## menu.SetHelpString(ID, description)
                    if hasattr( self, method):
                        EVT_MENU(self, ID, getattr (self, method))
                    else:
                        print "unknown method", method
                    if acceleratordata:
                        accelerators.append ( acceleratordata+(ID,) )
            menubar.Append (menu, name)
            self.menumapping [name] = menu
        self.SetAcceleratorTable( wxAcceleratorTable (accelerators))
        self.SetMenuBar(menubar)

if __name__ == "__main__":
    __file__ = '.'
    class DemoApp(wxPySimpleApp):
        def OnInit(self):
            self.mainframe = SetBuilder( )
            self.mainframe.Show(TRUE )
            return true

    def test( ):
        app = DemoApp()
        app.MainLoop()
    print 'Creating dialog'
    test( )

···

__________________________________
Mike C. Fletcher
Designer, VR Plumber
http://members.home.com/mcfletch

Trying to debug an error, I discovered that EVT_MENU will generate 2

events

for every click of a menu that's marked as "checkable".

It's because you have event.Skip() in the OnPreviewWindow method. Take that
out and you'll only get one event. The program flow is basically like this:

1. Windows sends WM_COMMAND to the frame's message handler.

2. It turns it into a command event and looks for an event handler.

3. Your handler is called, which sets the skip flag

4. Because of the flag the event handler search continues finding no other
handlers.

5. Any message not handled by the frame is passed to the wxWindow class'
message handler.

6. Since WM_COMMAND is seriously overloaded in MSW for lots of different
control types wxWindow also processes WM_COMMAND, so the whole thing is done
again from that perspective.

···

--
Robin Dunn
Software Craftsman
robin@AllDunn.com Java give you jitters?
http://wxPython.org Relax with wxPython!