Last time we checked how to add a menu to our simple frame. Unfortunately, just adding it won’t make the menu useful. In order to do that we need to bind some events to it. As any interface framework, wxPython is governed by events generated by the user, being these events mouse clicks on buttons and menus, objects getting/losing focus, etc. In our case, so far, we eveidently need a event called menu event, which will tell the code what path to use when a menu is clicked.

My personal preference for binding an event to menu is to create a separate function to store these procedures, __do_binding. But by using this route we would need to change some code in the menu declaration, and to simplify things we will add the menu binding at the end of the __do_layout function.

And how we create a binding? In order to bind an object/menu to a function that will contain the executed code after the event is fired up, we need the name of the object/menu, the target function and the menu type. We already know the first and the last, we just need the function name then. Remember that we created the menu last time by using (the menu name were changed in the previous entry - it was some old code that got in the way - my mistake)

foreground_menu = filemenu.Append(-1, 'Select foreground file')
background_menu = filemenu.Append(-1, 'Select background file')
...
quitmenu = filemenu.Append(-1, 'Quit')

hence our menu names are foreground_menu, background_menu and quit_menu. Basically a wx.Bind method has this structure

self.Bind(EVENT_TYPE, handler, source)

where the handler is the function and the source is the actual source of the event. Let’s say then we want to use function on_foreground everytime someone clicks on foreground menu, and on_background everytime someone clicks on the background menu. We add a couple of lines to our layout function

self.Bind(wx.EVT_MENU, self.on_foreground, foreground_menu)
self.Bind(wx.EVT_MENU, self.on_background, background_menu)

This will tell the code where to go when these items are clicked. If you start the interface, and error will be generated because we still haven’t created the event handler functions. We should define them

def on_foreground(self, event):
    pass

def on_background(self, event):
    pass

Note that these function recieve an event parameter, which is the actual event itself. The pass line means that the function is defined but no actual code has been added, so execution can bypass it and do nothing when the function is called. Our complete code would look like

#!/usr/bin/env python

import wx
import pymot
import fasta

class pymot(wx.App):

    def __init__(self, redirect=False):
        wx.App.__init__(self, redirect)

class pymotGUI(wx.Frame):

    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id,  'Python Motif Finder', style=wx.DEFAULT_FRAME_STYLE)
        self.__do_layout()

    def __do_layout(self):

        #adding the panel
        panel = wx.Panel(self)

        #defines the menubar
        menubar = wx.MenuBar()

        #file menu
        filemenu = wx.Menu()
        foreground_menu = filemenu.Append(-1, 'Select foreground file')
        background_menu = filemenu.Append(-1, 'Select background file')
        sep = filemenu.AppendSeparator()
        quitmenu = filemenu.Append(-1, 'Quit')

        #appends the menu to the menubar and creates it
        menubar.Append(filemenu, 'File')
        self.SetMenuBar(menubar)

        self.Bind(wx.EVT_MENU, self.on_foreground, foreground_menu)
        self.Bind(wx.EVT_MENU, self.on_background, background_menu)

    def on_foreground(self, event):
        pass

    def on_background(self, event):
        pass

app = pymot()
frame = pymotGUI(parent=None, id = -1)
frame.Show()
app.MainLoop()

Next time we will make good use of the events.