创建菜单栏
用 wxPython 创建一个菜单栏,需要用到 wx.MenuBar,wxMenu 和 wx.MenuItem。

一个简单的菜单示例
# simplemenu.py
import wx
class SimpleMenu(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(250, 150))
menubar = wx.MenuBar() # 创建一个菜单栏对象
file = wx.Menu() # 创建一个菜单对象
file.Append(-1, ‘Quit’, ‘Quit application’) # 将菜单添加到菜单栏上
menubar.Append(file, ‘&File’)
self.SetMenuBar(menubar)
self.Centre()
self.Show(True)
app = wx.App()
SimpleMenu(None, -1, ’simple menu example’)
app.MainLoop()
file.Append(-1, ‘Quit’, ‘Quit application’),第一个参数是菜单项的 ID,第二个参数是菜单项的名称,第三个参数是当菜单项被选中时显示在状态栏的文字信息。注意,我们这里没有使用 wx.MenuItem 直接创建菜单项。
self.SetMenuBar(menubar)
上面的代码将菜单添加到菜单栏上。字符“&”用来设置菜单的加速键,这样,就可以通过 alt + F 来打开 File 菜单。最后,通过调用 wx.Frame 的setMenu() 设置窗口的菜单栏。

创建 dockable 菜单栏
# dockable.py
import wx
class Dockable(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title)
menubar = wx.MenuBar(wx.MB_DOCKABLE)
file = wx.Menu()
edit = wx.Menu()
view = wx.Menu()
insr = wx.Menu()
form = wx.Menu()
tool = wx.Menu()
help = wx.Menu()
menubar.Append(file, ‘&File’)
menubar.Append(edit, ‘&Edit’)
menubar.Append(view, ‘&View’)
menubar.Append(insr, ‘&Insert’)
menubar.Append(form, ‘&Format’)
menubar.Append(tool, ‘&Tools’)
menubar.Append(help, ‘&Help’)
self.SetMenuBar(menubar)
self.Centre()
self.Show(True)
app = wx.App()
Dockable(None, -1, ‘Dockable menubar’)
app.MainLoop()
仅需在 wx.MenuBar(wx.MB_DOCKABLE) 构造函数是提供一个 wx.MB_DOCKABLE 参数即可。

图标,快捷键,事件
下面,我们将进一步增加上面的菜单示例,为菜单添加图标、快捷键、事件处理。
# menuexample.py
import wx
class MenuExample(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(250, 150))
menubar = wx.MenuBar()
file = wx.Menu()
quit = wx.MenuItem(file, 1, ‘&Quit\tCtrl+Q’)
quit.SetBitmap(wx.Bitmap(‘icons/exit.png’))
file.AppendItem(quit)
self.Bind(wx.EVT_MENU, self.OnQuit, id=1)
menubar.Append(file, ‘&File’)
self.SetMenuBar(menubar)
self.Centre()
self.Show(True)
def OnQuit(self, event):
self.Close()
app = wx.App()
MenuExample(None, -1, ”)
app.MainLoop()
如果我们需要添加快捷键和图标到菜单上,必须使用 wx.MenuItem 显式创建菜单项。
quit.SetBitmap(wx.Bitmap(‘icons/exit.png’))
file.AppendItem(quit)
“&”用来指定菜单的加速键。现实中,菜单项的快捷键通常是组合键,如上面定义的“Ctrl + Q”,只需在加速键与快捷键之间添加一个制表符“\t”即可。SetBitmap() 可以设置菜单项的图标。
如果选择了 quit 菜单项或者按下相应的快捷键,wx.EVT_MENU 就会引发一个事件。我们可以用 bind() 来绑定指定事件的处理方法。在上面的例子中,绑定到 OnQuit() 方法,用来关闭应用程序。如果有多个菜单项,必须为它们定义唯一的 ID。

子菜单
在下面的例子中,我们将创建子菜单和菜单项分隔条。
# submenu.py
import wx
ID_QUIT = 1
class SubmenuExample(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(350, 250))
menubar = wx.MenuBar()
file = wx.Menu()
file.Append(-1, ‘&New’)
file.Append(-1, ‘&Open’)
file.Append(-1, ‘&Save’)
file.AppendSeparator()
imp = wx.Menu()
imp.Append(-1, ‘Import newsfeed list…’)
imp.Append(-1, ‘Import bookmarks…’)
imp.Append(-1, ‘Import mail…’)
file.AppendMenu(-1, ‘I&mport’, imp)
quit = wx.MenuItem(file, ID_QUIT, ‘&Quit\tCtrl+W’)
quit.SetBitmap(wx.Bitmap(‘icons/exit.png’))
file.AppendItem(quit)
self.Bind(wx.EVT_MENU, self.OnQuit, id=ID_QUIT)
menubar.Append(file, ‘&File’)
self.SetMenuBar(menubar)
self.Centre()
self.Show(True)
def OnQuit(self, event):
self.Close()
app = wx.App()
SubmenuExample(None, -1, ‘Submenu’)
app.MainLoop()
简单的调用 file.AppendSeparator() 即可添加一个分隔条。使用 AppendMenu() 就可以像将一个菜单(子菜单)添加到另一个菜单上。

菜单项的分类
有三种菜单项:
- normal item
- check item
- radio item
# checkmenuitem.py
import wx
ID_STAT = 1
ID_TOOL = 2
class CheckMenuItem(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(350, 250))
menubar = wx.MenuBar()
file = wx.Menu()
view = wx.Menu()
self.shst = view.Append(ID_STAT, ‘Show statubar’, ‘Show Statusbar’, kind=wx.ITEM_CHECK)
self.shtl = view.Append(ID_TOOL, ‘Show toolbar’, ‘Show Toolbar’, kind=wx.ITEM_CHECK)
view.Check(ID_STAT, True)
view.Check(ID_TOOL, True)
self.Bind(wx.EVT_MENU, self.ToggleStatusBar, id=ID_STAT)
self.Bind(wx.EVT_MENU, self.ToggleToolBar, id=ID_TOOL)
menubar.Append(file, ‘&File’)
menubar.Append(view, ‘&View’)
self.SetMenuBar(menubar)
self.toolbar = self.CreateToolBar()
self.toolbar.AddLabelTool(3, ”, wx.Bitmap(‘icons/quit.png’))
self.statusbar = self.CreateStatusBar()
self.Centre()
self.Show(True)
def ToggleStatusBar(self, event):
if self.shst.IsChecked():
self.statusbar.Show()
else:
self.statusbar.Hide()
def ToggleToolBar(self, event):
if self.shtl.IsChecked():
self.toolbar.Show()
else:
self.toolbar.Hide()
app = wx.App()
CheckMenuItem(None, -1, ‘check menu item’)
app.MainLoop()
self.shtl = view.Append(ID_TOOL, ‘Show toolbar’, ‘Show Toolbar’, kind=wx.ITEM_CHECK)
设置 Append() 的 kind 参数为 wx.ITEM_CHECK 即可创建一个 check 菜单项,kind 的默认值为 wx.ITEM_NORMAL。Append() 方法将返回一个 wx.MenuItem 对象。
view.Check(ID_TOOL, True)
使用菜单项的 Check() 方法即可设置 check 菜单项的状态。
if self.shst.IsChecked():
self.statusbar.Show()
else:
self.statusbar.Hide()
我们全用 IsChecked() 方法取得 check 菜单项的状态,且以此为根据来显示或者隐藏状态栏。

上下文菜单(Context menu)
上下文菜单有时被称为弹出菜单或者右键菜单。
import wx
class MyPopupMenu(wx.Menu):
def __init__(self, parent):
wx.Menu.__init__(self)
self.parent = parent
minimize = wx.MenuItem(self, wx.NewId(), ‘Minimize’)
self.AppendItem(minimize)
self.Bind(wx.EVT_MENU, self.OnMinimize, id=minimize.GetId())
close = wx.MenuItem(self, wx.NewId(), ‘Close’)
self.AppendItem(close)
self.Bind(wx.EVT_MENU, self.OnClose, id=close.GetId())
def OnMinimize(self, event):
self.parent.Iconize()
def OnClose(self, event):
self.parent.Close()
class ContextMenu(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(250, 150))
self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
self.Center()
self.Show()
def OnRightDown(self, event):
self.PopupMenu(MyPopupMenu(self), event.GetPosition())
app = wx.App()
frame = ContextMenu(None, -1, ‘context menu’)
app.MainLoop()
def __init__(self, parent):
wx.Menu.__init__(self)
上面创建另外一个 wx.Menu 菜单对象,并定义了两个命令: 关闭和最小化窗口。
我们将按下右键的事件绑定到 OnRightDown() 方法。
self.PopupMenu(MyPopupMenu(self), event.GetPosition())
在 OnRightDown() 方法中,调用 PopuMenu() 方法显示上下文菜单,第一个参数用来指定显示的菜单对象,第二个参数指定上下文菜单显示的位置,这里指定是鼠标的位置 —— 使用 GetPosition() 即可取得当前鼠标的位置。
工具栏
工具栏提供了一个快速的执行常用命令的通道。
通过调 frame 的 CreateToolBar() 方法即可创建一个工具栏。
# simpletoolbar.py
import wx
class SimpleToolbar(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(300, 200))
toolbar = self.CreateToolBar()
toolbar.AddLabelTool(wx.ID_EXIT, ”, wx.Bitmap(‘../icons/exit.png’))
toolbar.Realize()
self.Bind(wx.EVT_TOOL, self.OnExit, id=wx.ID_EXIT)
self.Centre()
self.Show(True)
def OnExit(self, event):
self.Close()
app = wx.App()
SimpleToolbar(None, -1, ’simple toolbar’)
app.MainLoop()
使用 AddLabelTool() 方法创建一个工具栏按钮。
对于 Windows 系统,当添加按钮后,我们必须调用 Realize() 方法。在 Linux 下则不必。
绑定工具栏的事件。

对于创建多个工具栏,必须按照跟上面不同的方式:
# toolbars.py
import wx
class Toolbars(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(300, 200))
vbox = wx.BoxSizer(wx.VERTICAL)
toolbar1 = wx.ToolBar(self, -1)
toolbar1.AddLabelTool(wx.ID_ANY, ”, wx.Bitmap(‘../icons/new.png’))
toolbar1.AddLabelTool(wx.ID_ANY, ”, wx.Bitmap(‘../icons/open.png’))
toolbar1.AddLabelTool(wx.ID_ANY, ”, wx.Bitmap(‘../icons/save.png’))
toolbar1.Realize()
toolbar2 = wx.ToolBar(self, -1)
toolbar2.AddLabelTool(wx.ID_EXIT, ”, wx.Bitmap(‘../icons/exit.png’))
toolbar2.Realize()
vbox.Add(toolbar1, 0, wx.EXPAND)
vbox.Add(toolbar2, 0, wx.EXPAND)
self.Bind(wx.EVT_TOOL, self.OnExit, id=wx.ID_EXIT)
self.SetSizer(vbox)
self.Centre()
self.Show(True)
def OnExit(self, event):
self.Close()
app = wx.App()
Toolbars(None, -1, ‘toolbars’)
app.MainLoop()
…
toolbar2 = wx.ToolBar(self, -1)
将两个工具栏放于一个 vertical box 中。

有时,我们需要创建一垂直放置的工具栏:
# verticaltoolbar.py
import wx
class VerticalToolbar(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(240, 300))
toolbar = self.CreateToolBar(wx.TB_VERTICAL)
toolbar.AddLabelTool(wx.ID_ANY, ”, wx.Bitmap(‘../icons/select.gif’))
toolbar.AddLabelTool(wx.ID_ANY, ”, wx.Bitmap(‘../icons/freehand.gif’))
toolbar.AddLabelTool(wx.ID_ANY, ”, wx.Bitmap(‘../icons/shapeed.gif’))
toolbar.AddLabelTool(wx.ID_ANY, ”, wx.Bitmap(‘../icons/pen.gif’))
toolbar.AddLabelTool(wx.ID_ANY, ”, wx.Bitmap(‘../icons/rectangle.gif’))
toolbar.AddLabelTool(wx.ID_ANY, ”, wx.Bitmap(‘../icons/ellipse.gif’))
toolbar.AddLabelTool(wx.ID_ANY, ”, wx.Bitmap(‘../icons/qs.gif’))
toolbar.AddLabelTool(wx.ID_ANY, ”, wx.Bitmap(‘../icons/text.gif’))
toolbar.Realize()
self.Centre()
self.Show(True)
def OnExit(self, event):
self.Close()
app = wx.App()
VerticalToolbar(None, -1, ‘vertical toolbar’)
app.MainLoop()
提供一个 wx.TB_VERTICAL 参数即可创建一个垂直放置的工具栏。

在下面的例子中,我们将演示 Enable/Disable 工具栏按钮,以及添加分隔条:
# enabledisable.py
import wx
class EnableDisable(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(250, 150))
self.count = 5
self.toolbar = self.CreateToolBar()
self.toolbar.AddLabelTool(wx.ID_UNDO, ”, wx.Bitmap(‘../icons/undo.png’))
self.toolbar.AddLabelTool(wx.ID_REDO, ”, wx.Bitmap(‘../icons/redo.png’))
self.toolbar.EnableTool(wx.ID_REDO, False)
self.toolbar.AddSeparator()
self.toolbar.AddLabelTool(wx.ID_EXIT, ”, wx.Bitmap(‘../icons/exit.png’))
self.toolbar.Realize()
self.Bind(wx.EVT_TOOL, self.OnExit, id=wx.ID_EXIT)
self.Bind(wx.EVT_TOOL, self.OnUndo, id=wx.ID_UNDO)
self.Bind(wx.EVT_TOOL, self.OnRedo, id=wx.ID_REDO)
self.Centre()
self.Show(True)
def OnUndo(self, event):
if self.count > 1 and self.count <= 5:
self.count = self.count – 1
if self.count == 1:
self.toolbar.EnableTool(wx.ID_UNDO, False)
if self.count == 4:
self.toolbar.EnableTool(wx.ID_REDO, True)
def OnRedo(self, event):
if self.count < 5 and self.count >= 1:
self.count = self.count + 1
if self.count == 5:
self.toolbar.EnableTool(wx.ID_REDO, False)
if self.count == 2:
self.toolbar.EnableTool(wx.ID_UNDO, True)
def OnExit(self, event):
self.Close()
app = wx.App()
EnableDisable(None, -1, ‘enable disable’)
app.MainLoop()
在例子中,我们创建了三个工具栏按钮 —— 退出、撤销、重做按钮。而 撤销、重做按钮是 Disable 的。
self.toolbar.AddSeparator()
调用 EnableTool() 方法使重做按钮 Disable。简单调用 AddSparator() 即可添加分隔条。
if self.count > 1 and self.count <= 5:
self.count = self.count – 1
if self.count == 1:
self.toolbar.EnableTool(wx.ID_UNDO, False)
if self.count == 4:
self.toolbar.EnableTool(wx.ID_REDO, True)
我们模拟了撤销和重做的功能,最多可以返回4次的改变。如果没有可以撤销的,撤销按钮将会被设置为 Disable。当第一次按下撤销按钮之后,重做按钮被设置为 Enable。上面的逻辑同样适合于 OnRedo() 方法。
