Binding Event Handler to Menu Item

In my module I have these two lines:

menuFile.Append(101, '&Open \tCtrl-O', 'Open a knowledge base', wx.ITEM_NORMAL)
  ...
menuFile.Bind(wx.EVT_MENU, self.OnMenuFileOpen, 101)

   When I try running the application I get this error message:

     menuFile.Bind(wx.EVT_MENU, self.OnMenuFileOpen, 101)
AttributeError: 'mainFrame' object has no attribute 'OnMenuFileOpen'

   I've looked at the Wiki page and the wxWidgets book, so I tried
EVT_MENU(101, self.OnMenuFileOpen)

which generated an error about EVT_MENU not being defined.

   What is the proper syntax to bind an event handler to a menu item?

Thanks,

Rich

···

--
Richard B. Shepard, Ph.D. | Author of "Quantifying Environmental
Applied Ecosystem Services, Inc. (TM) | Impact Assessments Using Fuzzy Logic"
<http://www.appl-ecosys.com> Voice: 503-667-4517 Fax: 503-667-8863

     menuFile.Bind(wx.EVT_MENU, self.OnMenuFileOpen, 101)
AttributeError: 'mainFrame' object has no attribute 'OnMenuFileOpen'

Read your error. The 'self' object at that point lacks an
'OnMenuFileOpen' attribute/method. Are you sure you didn't mean
'menuFile.OnMenuFileOpen', or are you sure that the method has been
defined?

   I've looked at the Wiki page and the wxWidgets book, so I tried
EVT_MENU(101, self.OnMenuFileOpen)

which generated an error about EVT_MENU not being defined.

That would need to be wx.EVT_MENU(...), unless you used:
    'from wx import *'
...which would lead you back to the AttributeError on OnMenuFileOpen.

- Josiah

···

Rich Shepard <rshepard@appl-ecosys.com> wrote:

Rich,

Always try to boil your problem down to a small example. Chances are you'll find your error in the process, and if not, you'll have something complete for us to look at.

menuFile.Append(101, '&Open \tCtrl-O', 'Open a knowledge base', wx.ITEM_NORMAL)
...
menuFile.Bind(wx.EVT_MENU, self.OnMenuFileOpen, 101)

  When I try running the application I get this error message:

    menuFile.Bind(wx.EVT_MENU, self.OnMenuFileOpen, 101)
AttributeError: 'mainFrame' object has no attribute 'OnMenuFileOpen'

What kind of object is menuFile? What is self?

  What is the proper syntax to bind an event handler to a menu item?

It's a bit uglier than it should be, because a menu item is not a true wx.Window, and thus does not catch events itself, and does not have a Bind() method (I still don't see why it couldn't, but there you go). You need to catch the event in the parent frame. This is the cleanest way I think there is to do it, as I don't like to use explicit IDs (untested):

class MyFrame(....)
     def __init__(........

         ....

         FileMenu = wx.Menu(self, ....)

         ....
  
         Item = Menu.Append(wx.ID_ANY, "Open" )
         self.Bind(wx.EVT_MENU, self.OnFileOpen, Item)

     .....

     def OnFileOpen(self, event):
         DoWhatEver()

To dissect the Bind() call:

Bind an event in this Frame, Look for a wx.EVT_MENU event, when you see one that comes from Item, call ThisFrame's OnFileOpen command.

I think that third parameter can be the ID of the control the event comes from also, but I prefer to use reference to the control itself, as I don't like explicit IDs.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Read your error. The 'self' object at that point lacks an 'OnMenuFileOpen'
attribute/method.

Josiah,

   This much I understand. How to write the line so the method is recognized
is what I don't understand.

Are you sure you didn't mean 'menuFile.OnMenuFileOpen', or are you sure
that the method has been defined?

   I just tried 'menuFile.OnMenuFileOpen' and received the same error. The
method is defined starting at line 209 in the file (and the above is at line
29).

That would need to be wx.EVT_MENU(...), unless you used:

   Oops! I should have seen that.

Thanks,

Rich

···

On Mon, 21 Nov 2005, Josiah Carlson wrote:

--
Richard B. Shepard, Ph.D. | Author of "Quantifying Environmental
Applied Ecosystem Services, Inc. (TM) | Impact Assessments Using Fuzzy Logic"
<http://www.appl-ecosys.com> Voice: 503-667-4517 Fax: 503-667-8863

Line locations make no difference as long as the object's methods have
been created before you access them. As others have asked:
    On what class is OnMenuFileOpen defined?
    On what type of class is 'self'?
    What type of class is 'menuFile'?

Answering those questions may help you fix it yourself.

- Josiah

···

Rich Shepard <rshepard@appl-ecosys.com> wrote:

On Mon, 21 Nov 2005, Josiah Carlson wrote:
> Are you sure you didn't mean 'menuFile.OnMenuFileOpen', or are you sure
> that the method has been defined?

   I just tried 'menuFile.OnMenuFileOpen' and received the same error. The
method is defined starting at line 209 in the file (and the above is at line
29).

Always try to boil your problem down to a small example. Chances are you'll
find your error in the process, and if not, you'll have something complete
for us to look at.

Chris,

   Perhaps this will help (all within class mainFrame, which is a wx.Frame):

    menuFile = wx.Menu(self)

    menuFile.Append(self, 101, '&Open \tCtrl-O', 'Open a knowledge base', wx.ITEM_NORMAL)

    menuFile.Bind(wx.EVT_MENU, self.OnMenuFileOpen, 101)

What kind of object is menuFile? What is self?

   I believe that menuFile is an instance of wx.Menu(); I thought that 'self'
refered to the menu item, in this case with ID == 101.

   Now the error I'm getting is:

   File "/mnt/usr2/fuzzy/eikos/ui/eikosFrame1.py", line 16, in __init__
     menuFile = wx.Menu(self, "")
   File "/usr/lib/python2.4/site-packages/wx-2.6-gtk2-ansi/wx/_core.py", line 10194, in __init__
     newobj = _core_.new_Menu(*args, **kwargs)
TypeError: String or Unicode type required

   When I look at the API docs, in wx.Menu-class.html I see nothing about
binding the event handler to the item (ID specified or not). In
wx.MenuEvent-class.html I read about menu items being opened, closed, or
highlighted. Still not what I need. In wx.MenuItem-class.html I cannot find a
reference to binding wx.EVT_MENU to a selected item.

   Greping wx.EVT_MENU in that directory finds only the open, close, and
highlight references in wx.MenuEvent-class.html.

   So, I've tried to find the documentation for this and so far have failed at
the attempt. The Wiki page has a single event binding and that didn't work
for me, either.

It's a bit uglier than it should be, because a menu item is not a true
wx.Window, and thus does not catch events itself, and does not have a
Bind() method (I still don't see why it couldn't, but there you go). You
need to catch the event in the parent frame. This is the cleanest way I
think there is to do it, as I don't like to use explicit IDs (untested):

       FileMenu = wx.Menu(self, ....)
       ....
          Item = Menu.Append(wx.ID_ANY, "Open" )
       self.Bind(wx.EVT_MENU, self.OnFileOpen, Item)

   So, what do I add to the instance FileMenu after 'self'? And, do I need to
make a separate assignment of menu.Append for each item in my menu?

   .....

   def OnFileOpen(self, event):
       DoWhatEver()

   What I have is:

     def OnMenuFileOpen(self, event):
         dlg = wx.FileDialog(self, "Choose a file", ".", "", "*.*", wx.OPEN)
         try:
             if dlg.ShowModal() == wx.ID_OK:
                 filename = dlg.GetPath()
                 self.model.LoadFile(filename)
                 self.FileName = filename
                 self.SetTitle(('Eikos - %s') % filename)
         finally:
             dlg.Destroy()

   Am I getting closer?

Thanks,

Rich

···

On Mon, 21 Nov 2005, Chris Barker wrote:

--
Richard B. Shepard, Ph.D. | Author of "Quantifying Environmental
Applied Ecosystem Services, Inc. (TM) | Impact Assessments Using Fuzzy Logic"
<http://www.appl-ecosys.com> Voice: 503-667-4517 Fax: 503-667-8863

Line locations make no difference as long as the object's methods have
been created before you access them.

   I mentioned the line numbers only to indicate their relative positions in
the file.

As others have asked:
   On what class is OnMenuFileOpen defined?

   A wx.Frame, I believe:

class mainFrame(wx.Frame):
   def __init__(self, parent, ID, title):
     wx.Frame.__init__(self, None, -1, title='Eikos', pos=wx.Point(349, 199),
     size=wx.Size(853, 616), style=wx.DEFAULT_FRAME_STYLE)

     # Menu

     menuBar = wx.MenuBar()

     menuFile = wx.Menu(self)
     ...

     menuFile.Append(self, 101, '&Open \tCtrl-O', 'Open a knowledge base', wx.ITEM_NORMAL)
     menuFile.Append(self, 102, '&Save \tCtrl-S', 'Save knowledge base', wx.ITEM_NORMAL)
     ...
     menuFile.Bind(wx.EVT_MENU, self.OnMenuFileOpen, 101)
     menuFile.Bind(wx.EVT_MENU, self.OnMenuFileSave, 102)

   On what type of class is 'self'?

   I believe that this is also a wx.Frame.

   What type of class is 'menuFile'?

   wx.Menu.

Answering those questions may help you fix it yourself.

   If it was that clear to me I would not have asked for clarification. This
is all new to me and I'm finding the docs a bit sparse.

Rich

···

On Tue, 22 Nov 2005, Josiah Carlson wrote:

--
Richard B. Shepard, Ph.D. | Author of "Quantifying Environmental
Applied Ecosystem Services, Inc. (TM) | Impact Assessments Using Fuzzy Logic"
<http://www.appl-ecosys.com> Voice: 503-667-4517 Fax: 503-667-8863

Chris/Josiah,

   The problem was boiled so much it is like a limp noodle.

   I used wxGlade to set up part of the menu so I could see the syntax and
approach Alberto uses. Then I modified my file to match. I also made the main
file and the main frame into one file rather than Boa's two files.

   Now I have to clean up the call to wx.Panel and wx.Notebook, but the menu
and menu event binding errors have been overcome.

Thanks for your patience,

Rich

···

On Mon, 21 Nov 2005, Chris Barker wrote:

Always try to boil your problem down to a small example. Chances are you'll
find your error in the process, and if not, you'll have something complete
for us to look at.

--
Richard B. Shepard, Ph.D. | Author of "Quantifying Environmental
Applied Ecosystem Services, Inc. (TM) | Impact Assessments Using Fuzzy Logic"
<http://www.appl-ecosys.com> Voice: 503-667-4517 Fax: 503-667-8863