The following code was committed by Chris Barker on the wxPython-users mailing list. Popup menu is here implemented in a separate class. This way, you don't have to manually check, if the events were already bound.
What Objects are Involved
wxSimpleApp - this class serves as a entry point to the application
wxMenu - used for implementing the Popup Menu
wxMenuItem - all items from Popup Menu are created with this class
wxWindow - we create four different windows in one Frame
wxFrame - a toplevel window and a container for our four windows
The example implements a Popup Menu in a single frame. This frame is divided into four windows. If you right click on a Frame, a context menu pops up. Context menu consists of three commands. If you select any of them, a message is sent to the console. It will say the item you selected plus the color of the window where you clicked with the mouse. This example shows the power of the object oriented programming. Imagine you would have to do it the other way, by calculating manually the position of the pointer! (to find out the colour) Application just knows it... Notice that the popup menu is implemented as a new class.
There is one subtle thing in the code that needs some clarification. You only bound an event to a method once. It resides in event table afterwards. If it is done in the constructor, everything is ok. But when you bound an event in a method, you do it every time the method gets invoked. That's why there needs to be a condition in the beginning of the method. To ensure binding is done only once.
Taken from the Demo:
if not hasattr(self, "popupID1"): self.popupID1 = wx.NewId() self.popupID2 = wx.NewId() self.Bind(wx.EVT_MENU, self.OnPopupOne, id=self.popupID1) self.Bind(wx.EVT_MENU, self.OnPopupTwo, id=self.popupID2)
Thus, with a Popup Menu implemented in a special class, you get a more elegant code.
1 #!/usr/bin/python 2 3 import wx 4 5 app = wx.PySimpleApp() 6 7 class MyPopupMenu(wx.Menu): 8 def __init__(self, WinName): 9 wx.Menu.__init__(self) 10 11 self.WinName = WinName 12 13 item = wx.MenuItem(self, wx.NewId(), "Item One") 14 self.AppendItem(item) 15 self.Bind(wx.EVT_MENU, self.OnItem1, item) 16 17 item = wx.MenuItem(self, wx.NewId(),"Item Two") 18 self.AppendItem(item) 19 self.Bind(wx.EVT_MENU, self.OnItem2, item) 20 21 item = wx.MenuItem(self, wx.NewId(),"Item Three") 22 self.AppendItem(item) 23 self.Bind(wx.EVT_MENU, self.OnItem3, item) 24 25 def OnItem1(self, event): 26 print "Item One selected in the %s window"%self.WinName 27 28 def OnItem2(self, event): 29 print "Item Two selected in the %s window"%self.WinName 30 31 def OnItem3(self, event): 32 print "Item Three selected in the %s window"%self.WinName 33 34 class MyWindow(wx.Window): 35 def __init__(self, parent, color): 36 wx.Window.__init__(self, parent, -1) 37 38 self.color = color 39 40 self.SetBackgroundColour(color) 41 self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) 42 43 def OnRightDown(self,event): 44 menu = MyPopupMenu(self.color) 45 self.PopupMenu(menu, event.GetPosition()) 46 menu.Destroy() 47 48 class MyFrame(wx.Frame): 49 def __init__(self): 50 wx.Frame.__init__(self,None, -1, "Test", size=(300, 200)) 51 52 sizer = wx.GridSizer(2,2,5,5) 53 54 sizer.Add(MyWindow(self,"blue"),1,wx.GROW) 55 sizer.Add(MyWindow(self,"yellow"),1,wx.GROW) 56 sizer.Add(MyWindow(self,"red"),1,wx.GROW) 57 sizer.Add(MyWindow(self,"green"),1,wx.GROW) 58 59 self.SetSizer(sizer) 60 61 self.Show() 62 63 64 frame = MyFrame() 65 app.SetTopWindow(frame) 66 app.MainLoop()