Introduction
Make a popup menu when you right-click something.
What Objects are Involved
Source Component |
Component that was clicked. |
Menu Launcher |
Event handler, launches the menu. |
Menu |
Popup menu itself. |
Menu Handlers |
Menu responses to selection. |
Process Overview
Register source's EVT_s to invoke launcher.
Launcher creates wxMenu.
Launcher packs menu with Append.
Launcher registers menu handlers with EVT_MENU, on the menu.
Launcher displays menu with call to PopupMenu, invoked on the source component, passing event's GetPoint.
The GetPoint tells PopupMenu where to place the PopupMenu. (That is: Where the user right-clicked, the popup menu should appear.)
Special Concerns
In general:
I don't know why PopupMenu isn't a global function. You must call it in the context of a wxWindow.
The code below:
- There may be a way to communicate the list item clicked on to the menu handler via the event object, rather than the App object.
Code Sample
1 from wxPython.wx import *
2
3
4
5 menu_titles = [ "Open",
6 "Properties",
7 "Rename",
8 "Delete" ]
9
10 menu_title_by_id = {}
11 for title in menu_titles:
12 menu_title_by_id[ wxNewId() ] = title
13
14
15
16 list_title = "files"
17 list_items = [ "binding.py",
18 "clipboard.py",
19 "config.py",
20 "debug.py",
21 "dialog.py",
22 "dispatch.py",
23 "error.py", ]
24
25
26
27 class App( wxPySimpleApp ):
28 def OnInit( self ):
29 # build frame
30 frame = wxFrame(NULL, -1, "Hello from wxPython")
31 self.frame = frame # we'll use in RightClickCb
32
33 # build list
34 list = wxListCtrl( frame, -1, style=wxLC_REPORT )
35 list.InsertColumn( 0, list_title )
36 for x in list_items: list.InsertStringItem(0,x)
37
38 ### 1. Register source's EVT_s to invoke launcher. ###
39 EVT_LIST_ITEM_RIGHT_CLICK( list, -1, self.RightClickCb )
40
41 # clear variables
42 self.list_item_clicked = None
43
44 # show & run
45 frame.Show(1)
46 return 1
47
48 def RightClickCb( self, event ):
49 # record what was clicked
50 self.list_item_clicked = right_click_context = event.GetText()
51
52 ### 2. Launcher creates wxMenu. ###
53 menu = wxMenu()
54 for (id,title) in menu_title_by_id.items():
55 ### 3. Launcher packs menu with Append. ###
56 menu.Append( id, title )
57 ### 4. Launcher registers menu handlers with EVT_MENU, on the menu. ###
58 EVT_MENU( menu, id, self.MenuSelectionCb )
59
60 ### 5. Launcher displays menu with call to PopupMenu, invoked on the source component, passing event's GetPoint. ###
61 self.frame.PopupMenu( menu, event.GetPoint() )
62 menu.Destroy() # destroy to avoid mem leak
63
64 def MenuSelectionCb( self, event ):
65 # do something
66 operation = menu_title_by_id[ event.GetId() ]
67 target = self.list_item_clicked
68 print 'Perform "%(operation)s" on "%(target)s."' % vars()
69
70 app = App()
71 app.MainLoop()
Comments
Commit code improvements above, comment freely below. -- LionKimbro 2003-08-21 14:40:27
Experiment with the icons {3}. Ideally, I'd get around to installing working Java on Mozilla, and then I could just diagram this process exactly like I want to... -- LionKimbro 2003-10-17 11:59:29
The above code has some problem in wx 2.5.3.1, in right click callback a call to event.GetText() returns empty string. Same for 2.6.0.0, so I think it's some "backward incompatibility" with wx... ;). -- Jarek Zgoda
wx.Menu objects need to be explicitly destroyed (e.g. menu.Destroy()) in this situation. Otherwise, they will rack up the USER Objects count on Windows; eventually crashing a program when USER Objects is maxed out. -- U. Artie Eoff 2008-10-06 12:02:00