Pairing Notebook Panel to Frame Menus

The wx.Notebook allows users to access different panels at different times. This page describes a way to link menus to those panels in such a way that the menus swap out, or can be disabled when the panel is not selected in the notebook.

To do this we will need:

We want to change the panel through three methods:

  1. Clicking on a tab in the notebook
  2. Selecting a tab in a menu
  3. An accelerator key

The third method will be taken care of by the second. The program has to change the menu when the tab changes, and change the tab when the menu changes.

   1 import wx
   2 
   3 class NotebookPanel(wx.Panel):
   4     # Subclass to get everything the normal panel can do
   5     def __init__(self,parent,name,menu,menuName):
   6         wx.Panel.__init__(self,parent=parent)
   7         ### Attaching the menu to the panel is one way to make sure
   8         ###  the panel and menu stay together
   9         self.Menu = menu
  10         self.MenuName = menuName
  11         ### All the panels will have the same information
  12         ### In a real-world app, delete these lines from this class
  13         ###  and populate the subclasses of this class
  14         sizer = wx.BoxSizer(wx.VERTICAL)
  15         label = wx.StaticText(self,label="This is a sample notebook panel")
  16         sizer.Add(label)
  17 
  18 class BluePanel(NotebookPanel):
  19     ### The Blue Panel has a menu
  20     def __init__(self,parent):
  21         blueMenu = wx.Menu()
  22         blueMenu.Append(wx.ID_ANY,"This is the blue menu","Dummy Help")
  23         NotebookPanel.__init__(self,
  24                                parent=parent,
  25                                name="Blue",
  26                                menu=blueMenu,
  27                                menuName="&Blue")
  28         self.SetBackgroundColour("Light Blue")
  29 
  30 class RedPanel(NotebookPanel):
  31     def __init__(self,parent):
  32         redMenu = wx.Menu()
  33         redMenu.Append(wx.ID_ANY,"This is the red menu","Dummy Help")
  34         NotebookPanel.__init__(self,
  35                                parent=parent,
  36                                name="Red",
  37                                menu=redMenu,
  38                                menuName="&Red")
  39         self.SetBackgroundColour("Red")
  40 
  41 class MyNotebook(wx.Notebook):
  42     ### For this demo, we don't need to subclass
  43     ### Notebook at all.
  44     def __init__(self,parent):
  45         wx.Notebook.__init__(self,parent=parent)
  46         self.AddPage(BluePanel(self),"Blue")
  47         self.AddPage(RedPanel(self),"Red")
  48 
  49 class MyFrame(wx.Frame):
  50     def __init__(self,parent):
  51         wx.Frame.__init__(self,parent=parent,title="Notebook and Menu Test")
  52         mbar = wx.MenuBar()
  53         self.SetMenuBar(mbar)
  54 
  55         sbar = self.CreateStatusBar()
  56         self.Notebook = MyNotebook(self)
  57 
  58         ### Create a menu that allows user to select tabs as well
  59         ###  This uses ID values of 0 and 1 for the menu items.
  60         tabmenu = wx.Menu()
  61         for p in range(self.Notebook.GetPageCount()):
  62             name = self.Notebook.GetPageText(p)
  63 
  64             tabmenu.Append(p,"%s\tCtrl+%d" % (name,p+1),"Go to the %s page" % (name))
  65             self.Bind(wx.EVT_MENU,self.GoToPage,id=p)
  66         tabmenu.AppendSeparator()
  67         tabmenu.Append(wx.ID_CLOSE,"Close\tCtrl+X","Exit the demo")
  68         self.Bind(wx.EVT_MENU,self.Goodbye,id=wx.ID_CLOSE)
  69         mbar.Append(tabmenu,"&Tabs")
  70 
  71         ### Add the current page's menu to the bar
  72         m = self.Notebook.GetCurrentPage().Menu
  73         n = self.Notebook.GetCurrentPage().MenuName
  74 
  75         mbar.Append(m,n)
  76 
  77 
  78         self.SetMenuBar(mbar)
  79         sizer = wx.BoxSizer()
  80         sizer.Add(self.Notebook,1,wx.EXPAND)
  81         self.SetSizerAndFit(sizer)
  82         self.Layout()
  83 
  84         ### The EVT_NOTEBOOX_PAGE_CHANGED is registered
  85         ###  at the frame level
  86         self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED,self.AdjustMenus)
  87         self.Bind(wx.EVT_MENU,self.OnMenu)
  88 
  89         ### This disables the currently selected menu item
  90         mbar.Enable(self.Notebook.GetSelection(),False)
  91 
  92     def GoToPage(self,evt):
  93         ### This is the reaction to selecting a tab from
  94         ###   the tab menu
  95         self.Notebook.ChangeSelection(evt.GetId())
  96         self.AdjustMenus(evt)
  97 
  98     def Goodbye(self,evt):
  99         self.Close(True)
 100 
 101     def AdjustMenus(self,evt):
 102         ### Menubar position 1 is the swapping menu
 103 
 104         m = self.Notebook.GetCurrentPage().Menu
 105         n = self.Notebook.GetCurrentPage().MenuName
 106         mbar = self.GetMenuBar()
 107         mbar.Replace(1,m,n)
 108         ### Disable current page on tab menu
 109         ### because the tabmenu item id's match the index
 110         ### of the notebook page index, this works
 111         for page in range(self.Notebook.GetPageCount()):
 112             if page == self.Notebook.GetSelection():
 113                 ### The Menubar can enable any menu item by ID alone
 114                 mbar.Enable(page,False)
 115             else:
 116                 mbar.Enable(page,True)
 117         ### If you don't enable this, trying to
 118         ###  Change a notebook panel to the current panel
 119         ###  raises an error
 120 
 121 
 122     def OnMenu(self,evt):
 123         ### While not used in this demo, if the other menus
 124         ### actually did anything, this method would catch them
 125         evt.Skip()
 126 
 127 class App(wx.App):
 128     def OnInit(self):
 129         frame = MyFrame(None)
 130         self.SetTopWindow(frame)
 131         frame.Show()
 132         return 1
 133 
 134 A = App(0)
 135 A.MainLoop()

This solution seems clunky, and it is possible to control these changes using wx.lib.pubsub.Publisher. See Controlling GUI with Publisher.

Pairing Notebook Panel to Frame Menus (last edited 2008-07-10 17:43:17 by 65)

NOTE: To edit pages in this wiki you must be a member of the TrustedEditorsGroup.