wxPython 教程(三): 菜单与工具栏

总目录:wxPython 教程目录
本节内容:wxPython 菜单 工具栏
本节译自:zetcode
上一篇:wxpython 教程(二): 开始编写
下一篇:wxpython 教程 (四): 布局管理

wxPython 菜单 是 GUI 应用中的通用部件。菜单栏由多项菜单组成,顶级菜单在菜单栏上显示标签。菜单包含菜单项,菜单项在应用中执行特定的命令。菜单也可以包含子菜单,子菜单自身又包含菜单项。创建菜单栏的类有下面三个:wx.MenuBar,wx.Menu和wx.MenuItem。

简单例子

在我们的第一个例子中,我们将创建一个菜单栏,其包含“File”菜单,该菜单只包含一个菜单项。选择这一菜单项,应用会退出。

#!/usr/bin/python
# -*- coding: utf-8 -*-

'''
Translated By achen
2017/0
===
ZetCode wxPython tutorial

This example shows a simple menu.

author: Jan Bodnar
website: www.zetcode.com
last modified: September 2011
'''

import wx

class Example(wx.Frame):
    
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs) 
            
        self.InitUI()
        
    def InitUI(self):    

        menubar = wx.MenuBar()
        fileMenu = wx.Menu()
        fitem = fileMenu.Append(wx.ID_EXIT, 'Quit', 'Quit application')
        menubar.Append(fileMenu, '&File')
        self.SetMenuBar(menubar)
        
        self.Bind(wx.EVT_MENU, self.OnQuit, fitem)

        self.SetSize((300, 200))
        self.SetTitle('Simple menu')
        self.Centre()
        self.Show(True)
        
    def OnQuit(self, e):
        self.Close()

def main():
    
    ex = wx.App()
    Example(None)
    ex.MainLoop()    


if __name__ == '__main__':
    main()


上面是一个最小功能的菜单栏的例子。我们挑重点行来看一下:


menubar = wx.MenuBar()

首先我们新建了一个 menubar 对象,


fileMenu = wx.Menu()

然后我们新建一个menu对象,


fitem = fileMenu.Append(wx.ID_EXIT, 'Quit', 'Quit application')

我们将一个菜单项添加到menu对象中。第一个参数表明菜单项的ID。使用标准ID可以协助不同的操作系统更好的识别该菜单的功能,并自动为其添加对应的图标和快捷键(本例中为Ctrl+Q)。第二个参数为该菜单项的名称。最后一个参数定义了当选中菜单时应用状态栏所显示的帮助文字。这里我们没有显式的创建wx.MenuItem,而是通过Append()函数来添加它,这个方法会返回一个创建好的菜单项,其从属关系已经建立。保留这一参数可留作后面绑定事件用。


self.Bind(wx.EVT_MENU, self.OnQuit, fitem)

我们绑定了菜单项的wx.EVT_MENU事件到自定义的OnQuit()函数,这一函数将关闭程序。wx.EVT_MENU即选择菜单项事件。


menubar.Append(fileMenu, 'File')
self.SetMenuBar(menubar)

之后,我们将菜单加入到菜单栏中,&符号创建了一个加速键(accelerator key),在其之后的一个字母会带有下划线,使用Alt+F快捷键后,可通过该字母快速选择菜单项。最后,我们调用了SetMenuBar()方法,这一方法属于wx.Frame,它为Frame设定菜单栏。

tutorial wxpython-jiaocheng

图:一个简单的菜单样例

图标和快捷键

下一个例子跟上一个例子本质上是一样的,但这次我们手动创建一个菜单项,即wx.MenuItem。


#!/usr/bin/python
# -*- coding: utf-8 -*-

'''

Translated By Achen

2017/9

====
ZetCode wxPython tutorial

In this example, we manually create
a menu item.

author: Jan Bodnar
website: www.zetcode.com
last modified: September 2011
'''

import wx

APP_EXIT = 1

class Example(wx.Frame):
    
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs) 
            
        self.InitUI()
        
    def InitUI(self):

        menubar = wx.MenuBar()
        fileMenu = wx.Menu()
        qmi = wx.MenuItem(fileMenu, APP_EXIT, '&QuittCtrl+Q')
        qmi.SetBitmap(wx.Bitmap('exit.png'))
        fileMenu.AppendItem(qmi)

        self.Bind(wx.EVT_MENU, self.OnQuit, id=APP_EXIT)

        menubar.Append(fileMenu, '&File')
        self.SetMenuBar(menubar)

        self.SetSize((250, 200))
        self.SetTitle('Icons and shortcuts')
        self.Centre()
        self.Show(True)
        
    def OnQuit(self, e):
        self.Close()

def main():
    
    ex = wx.App()
    Example(None)
    ex.MainLoop()    


if __name__ == '__main__':
    main()


在这个例子中,我们新建了一个退出菜单项,选择了自定义的图标和快捷键。


qmi = wx.MenuItem(fileMenu, APP_EXIT, 'QuittCtrl+Q')
qmi.SetBitmap(wx.Bitmap('exit.png'))
fileMenu.AppendItem(qmi)

我们创建了一个wx.MenuItem对象。‘&’符号申明了加速键,它后面的一个字母会有下划线标识。真正的快捷键由’t’后面的字母组合定义。我们定义了Ctrl+Q,如果我们按下这一快捷键,应用就会退出。使用SetBitmap()函数,我们为菜单项提供图标。AppendItem则将菜单项添加到菜单中去。


self.Bind(wx.EVT_MENU, self.OnQuit, id=APP_EXIT)

当我们选择刚才创建的菜单项时,OnQuit()函数会被调用。这里通过id来绑定,也可以通过菜单项对象来绑定,像上一个例子那样。

tutorial wxpython-jiaocheng

图:图标和快捷键

子菜单和分隔符

每个菜单可以包含子菜单,这样就可以把相似的命令放到同一组中。比如我们可以把显示或隐藏个人信息栏、地址栏、状态栏或者导航栏的功能放到一个子菜单中去。在菜单中,我们可以通过分隔符(separator)来分割不同的命令,其实就是简单的一条线。比较常用的是将新建、打开、保存等命令和打印、打印预览通过分割线分开。在下面的例子中,我们将学习如何创建子菜单和菜单分隔符。


#!/usr/bin/python
# -*- coding: utf-8 -*-

'''
Translated By Achen
2017/9
===
ZetCode wxPython tutorial

In this example, we create a submenu and a menu
separator.

author: Jan Bodnar
website: www.zetcode.com
last modified: September 2011
'''

import wx


class Example(wx.Frame):
    
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs) 
            
        self.InitUI()
        
    def InitUI(self):

        menubar = wx.MenuBar()

        fileMenu = wx.Menu()
        fileMenu.Append(wx.ID_NEW, 'New')
        fileMenu.Append(wx.ID_OPEN, 'Open')
        fileMenu.Append(wx.ID_SAVE, 'Save')
        fileMenu.AppendSeparator()

        imp = wx.Menu()
        imp.Append(wx.ID_ANY, 'Import newsfeed list...')
        imp.Append(wx.ID_ANY, 'Import bookmarks...')
        imp.Append(wx.ID_ANY, 'Import mail...')

        fileMenu.AppendMenu(wx.ID_ANY, 'Import', imp)

        qmi = wx.MenuItem(fileMenu, wx.ID_EXIT, '&QuittCtrl+W')
        fileMenu.AppendItem(qmi)

        self.Bind(wx.EVT_MENU, self.OnQuit, qmi)

        menubar.Append(fileMenu, '&File')
        self.SetMenuBar(menubar)

        self.SetSize((350, 250))
        self.SetTitle('Submenu')
        self.Centre()
        self.Show(True)
        
    def OnQuit(self, e):
        self.Close()

def main():
    
    ex = wx.App()
    Example(None)
    ex.MainLoop()    


if __name__ == '__main__':
    main()

在上面的例子中,我们创建了New、Open和Save三个标准菜单项,并使用水平分割线将他们与其他区分。另外,我们还创建了一个包含三个菜单项的子菜单。


fileMenu.Append(wx.ID_NEW, '&New')
fileMenu.Append(wx.ID_OPEN, '&Open')
fileMenu.Append(wx.ID_SAVE, '&Save')

通过上面三行,我们得到通用的菜单项:新建、打开和保存。


fileMenu.AppendSeparator()

AppendSeparator()函数添加了分隔符。


imp = wx.Menu()
imp.Append(wx.ID_ANY, 'Import newsfeed list...')
imp.Append(wx.ID_ANY, 'Import bookmarks...')
imp.Append(wx.ID_ANY, 'Import mail...')

fileMenu.AppendMenu(wx.ID_ANY, 'I&mport', imp)

子菜单同样也是wx.Menu对象,三个菜单项被添加到该菜单对象。子菜单随后通过AppendMenu()方法被添加到file菜单中。

tutorial wxpython-jiaocheng

图:子菜单例子

Check菜单项

菜单项有三种:普通菜单项、check菜单项、radio菜单项。

在下面的例子中,我们将展示check菜单项的使用。check菜单项在菜单中会呈现一个标记符。


#!/usr/bin/python
# -*- coding: utf-8 -*-

'''
Translated By Achen
2017/9
===
ZetCode wxPython tutorial

This example creates a checked
menu item.

author: Jan Bodnar
website: www.zetcode.com
last modified: September 2011
'''

import wx


class Example(wx.Frame):
    
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs) 
            
        self.InitUI()
        
    def InitUI(self):    

        menubar = wx.MenuBar()
        fileMenu = wx.Menu()
        viewMenu = wx.Menu()
        
        self.shst = viewMenu.Append(wx.ID_ANY, 'Show statubar', 
            'Show Statusbar', kind=wx.ITEM_CHECK)
        self.shtl = viewMenu.Append(wx.ID_ANY, 'Show toolbar', 
            'Show Toolbar', kind=wx.ITEM_CHECK)
            
        viewMenu.Check(self.shst.GetId(), True)
        viewMenu.Check(self.shtl.GetId(), True)

        self.Bind(wx.EVT_MENU, self.ToggleStatusBar, self.shst)
        self.Bind(wx.EVT_MENU, self.ToggleToolBar, self.shtl)

        menubar.Append(fileMenu, '&File')
        menubar.Append(viewMenu, '&View')
        self.SetMenuBar(menubar)

        self.toolbar = self.CreateToolBar()
        self.toolbar.AddLabelTool(1, '', wx.Bitmap('texit.png'))
        self.toolbar.Realize()

        self.statusbar = self.CreateStatusBar()
        self.statusbar.SetStatusText('Ready')

        self.SetSize((350, 250))
        self.SetTitle('Check menu item')
        self.Centre()
        self.Show(True)
        
        
    def ToggleStatusBar(self, e):
        
        if self.shst.IsChecked():
            self.statusbar.Show()
        else:
            self.statusbar.Hide()

    def ToggleToolBar(self, e):
        
        if self.shtl.IsChecked():
            self.toolbar.Show()
        else:
            self.toolbar.Hide()        

def main():
    
    ex = wx.App()
    Example(None)
    ex.MainLoop()    


if __name__ == '__main__':
    main()

我们新建了一个view菜单,它包括两个check菜单项,这两个菜单项可以控制显示或隐藏状态栏和工具栏。


self.shst = viewMenu.Append(wx.ID_ANY, 'Show statubar',
'Show Statusbar', kind=wx.ITEM_CHECK)
self.shtl = viewMenu.Append(wx.ID_ANY, 'Show toolbar',
'Show Toolbar', kind=wx.ITEM_CHECK)

如果我们想添加一个check菜单项,我们可以设定kind参数为wx.ITEM_CHECK,该参数默认为wx.ITEM_NORMAL。Append()方法返回一个wx.MenuItem。


viewMenu.Check(self.shst.GetId(), True)
viewMenu.Check(self.shtl.GetId(), True)

当应用开始的时候,状态栏和工具栏都应可见。所以我们使用Check()方法勾选check菜单项。

 

def ToggleStatusBar(self, e):
    
    if self.shst.IsChecked():
        self.statusbar.Show()
    else:
        self.statusbar.Hide()

我们通过check菜单项的状态来显示或隐藏状态栏,可以通过ISChecked()函数来获取check菜单项的状态。工具栏同理。

tutorial wxpython-jiaocheng

图:check菜单项

上下文菜单

上下文菜单(context menu)即在特定上下文中出现的命令列表。比如在Firefox浏览器中,当我们在一个web页面中点击右键时,就会得到一个上下文菜单,包含刷新、后退或查看页面文件等命令。当我们在菜单栏右键时,我们又会得到另一个上下文菜单,它提供管理工具栏的各种命令。上下文菜单有时也叫做弹出菜单。


#!/usr/bin/python
# -*- coding: utf-8 -*-

'''
Translated By Achen
2017/9
===
ZetCode wxPython tutorial

In this example, we create a context menu.

author: Jan Bodnar
website: www.zetcode.com
last modified: September 2011
'''

import wx

class MyPopupMenu(wx.Menu):
    
    def __init__(self, parent):
        super(MyPopupMenu, self).__init__()
        
        self.parent = parent

        mmi = wx.MenuItem(self, wx.NewId(), 'Minimize')
        self.AppendItem(mmi)
        self.Bind(wx.EVT_MENU, self.OnMinimize, mmi)

        cmi = wx.MenuItem(self, wx.NewId(), 'Close')
        self.AppendItem(cmi)
        self.Bind(wx.EVT_MENU, self.OnClose, cmi)


    def OnMinimize(self, e):
        self.parent.Iconize()

    def OnClose(self, e):
        self.parent.Close()
        

class Example(wx.Frame):
    
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs) 
            
        self.InitUI()
        
    def InitUI(self):

        self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)

        self.SetSize((250, 200))
        self.SetTitle('Context menu')
        self.Centre()
        self.Show(True)
        
    def OnRightDown(self, e):
        self.PopupMenu(MyPopupMenu(self), e.GetPosition())

def main():
    
    ex = wx.App()
    Example(None)
    ex.MainLoop()    


if __name__ == '__main__':
    main()

在这个例子中,我们为主窗口新建了上下文菜单,他有两个菜单项,一个用来最小化应用,另一个结束应用。


class MyPopupMenu(wx.Menu):
 
    def __init__(self, parent):
        super(MyPopupMenu, self).__init__()

我们创建了一个单独的类叫做MyPopupMenu,它继承自wx.Menu。


mmi = wx.MenuItem(self, wx.NewId(), 'Minimize')
self.AppendItem(mmi)
self.Bind(wx.EVT_MENU, self.OnMinimize, mmi)

上面代码新建了菜单项、添加到上下文菜单并绑定了事件处理函数。


self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)

如果我们在frame中点击右键,将调用OnRightDown()方法,这是通过绑定wx.EVT_RIGHT_DOWN事件来绑定的。


def OnRightDown(self, e):
self.PopupMenu(MyPopupMenu(self), e.GetPosition())

在OnRightDown()函数中,我们调用了PopupMenu()方法,这个方法来自于wx.Frame。第一个参数是要显示的菜单,第二个参数为显示的位置。为了让上下文菜单显示在鼠标光标处,我们需要得到鼠标位置。事件对象的GetPosition()方法可以得到这一信息。

tutorial wxpython-jiaocheng

图:上下文菜单

工具栏

菜单将所有命令整合在一起,而工具栏可以为常用命令提供更方面的入口。我们可以使用frame部件的CreateToolBar()函数来新建工具栏。

#!/usr/bin/python
# -*- coding: utf-8 -*-

'''
Translated By Achen
2017/9
===
ZetCode wxPython tutorial

This example creates a simple toolbar.

author: Jan Bodnar
website: www.zetcode.com
last modified: September 2011
'''

import wx

class Example(wx.Frame):
    
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs) 
            
        self.InitUI()
        
    def InitUI(self):    

        toolbar = self.CreateToolBar()
        qtool = toolbar.AddLabelTool(wx.ID_ANY, 'Quit', wx.Bitmap('texit.png'))
        toolbar.Realize()

        self.Bind(wx.EVT_TOOL, self.OnQuit, qtool)

        self.SetSize((250, 200))
        self.SetTitle('Simple toolbar')
        self.Centre()
        self.Show(True)
        
    def OnQuit(self, e):
        self.Close()

def main():
    
    ex = wx.App()
    Example(None)
    ex.MainLoop()    


if __name__ == '__main__':
    main()

在例子中,我们新建了包含一个工具的工具栏。当我们点击这一工具时,程序将退出 。


toolbar = self.CreateToolBar()

我们新建了toolbar。默认情况下,工具栏是水平、无边框且显示图标的。


qtool = toolbar.AddLabelTool(wx.ID_ANY, 'Quit', wx.Bitmap('texit.png'))

我们调用AddLabelTool()方法来新建工具栏的工具。第一个参数为ID,第二个参数为工具的标签,第三个为工具的图标。需要注意的是,标签默认情况下不会显示,仅会显示图标。


toolbar.Realize()

在我们把工具项放到工具栏之后,我们调用Realize()方法。在Linux中,该方法的调用不是必须的,但在windows却是必须的。


self.Bind(wx.EVT_TOOL, self.OnQuit, qtool)

为了处理工具栏事件,我们使用wx.EVT_TOOL事件绑定器。

tutorial wxpython-jiaocheng

图:简单的工具栏

如果我们想创建多个工具栏,必须用不一样的方式:


#!/usr/bin/python
# -*- coding: utf-8 -*-

'''
Translated By Achen
2017/9
===
ZetCode wxPython tutorial

In this example, we create two horizontal 
toolbars. 

author: Jan Bodnar
website: www.zetcode.com
last modified: September 2011
'''

import wx

class Example(wx.Frame):
    
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs) 
            
        self.InitUI()
        
    def InitUI(self):    

        vbox = wx.BoxSizer(wx.VERTICAL)

        toolbar1 = wx.ToolBar(self)
        toolbar1.AddLabelTool(wx.ID_ANY, '', wx.Bitmap('tnew.png'))
        toolbar1.AddLabelTool(wx.ID_ANY, '', wx.Bitmap('topen.png'))
        toolbar1.AddLabelTool(wx.ID_ANY, '', wx.Bitmap('tsave.png'))
        toolbar1.Realize()

        toolbar2 = wx.ToolBar(self)
        qtool = toolbar2.AddLabelTool(wx.ID_EXIT, '', wx.Bitmap('texit.png'))
        toolbar2.Realize()

        vbox.Add(toolbar1, 0, wx.EXPAND)
        vbox.Add(toolbar2, 0, wx.EXPAND)

        self.Bind(wx.EVT_TOOL, self.OnQuit, qtool)
        
        self.SetSizer(vbox)

        self.SetSize((300, 250))
        self.SetTitle('Toolbars')
        self.Centre()
        self.Show(True)
        
    def OnQuit(self, e):
        self.Close()

def main():
    
    ex = wx.App()
    Example(None)
    ex.MainLoop()    


if __name__ == '__main__':
    main()

在上面的例子中,我们新建了两个水平的工具栏


toolbar1 = wx.ToolBar(self)
...
toolbar2 = wx.ToolBar(self)

我们新建了两个工具栏对象,并将他们放到了一个竖直box中。关于sizer我们将在后面详细讨论。

tutorial wxpython-jiaocheng

图:多个工具栏

开启、禁用

在下面的例子中,我们将展示如何启用、禁用工具栏的按钮。同时,我们还将展示如何添加分割线。


#!/usr/bin/python
# -*- coding: utf-8 -*-

'''
Translated By Achen
2017/9
===
ZetCode wxPython tutorial

In this example, we create two horizontal 
toolbars. 

author: Jan Bodnar
website: www.zetcode.com
last modified: September 2011
'''

import wx

class Example(wx.Frame):
    
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs) 
            
        self.InitUI()
        
    def InitUI(self):    

        self.count = 5

        self.toolbar = self.CreateToolBar()
        tundo = self.toolbar.AddLabelTool(wx.ID_UNDO, '', wx.Bitmap('tundo.png'))
        tredo = self.toolbar.AddLabelTool(wx.ID_REDO, '', wx.Bitmap('tredo.png'))
        self.toolbar.EnableTool(wx.ID_REDO, False)
        self.toolbar.AddSeparator()
        texit = self.toolbar.AddLabelTool(wx.ID_EXIT, '', wx.Bitmap('texit.png'))
        self.toolbar.Realize()

        self.Bind(wx.EVT_TOOL, self.OnQuit, texit)
        self.Bind(wx.EVT_TOOL, self.OnUndo, tundo)
        self.Bind(wx.EVT_TOOL, self.OnRedo, tredo)

        self.SetSize((250, 200))
        self.SetTitle('Undo redo')
        self.Centre()
        self.Show(True)
        
    def OnUndo(self, e):
        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, e):
        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 OnQuit(self, e):
        self.Close()

def main():
    
    ex = wx.App()
    Example(None)
    ex.MainLoop()    


if __name__ == '__main__':
    main()

在这个例子中,我们有三个工具栏按钮。一个按钮用来退出应用,其余两个按钮的功能为撤销和反撤销,在程序中模拟撤销、反撤销的功能。模拟了4次改变,撤销和反撤销功能也需要对应的启用或禁用。


self.toolbar.EnableTool(wx.ID_REDO, False)
self.toolbar.AddSeparator()

在最开始,撤销按钮是禁用的。我们调用EnableTool()函数,并传递False参数来实现。调用AddSeparator()函数可以添加一条竖线来分隔不同的工具项。


 
 def OnUndo(self, e):
 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)

我们模拟了撤销和反撤销的功能。如果没有什么可以撤销的,撤销按钮需要禁用。类似的逻辑也体现在OnRedo()中。

tutorial wxpython-jiaocheng

图:撤销、反撤销

 

在本节教程中,我们学习了菜单和工具栏。


上一篇:wxpython教程(二): 开始编写        下一篇:wxpython 教程 (四): 布局管理

《wxPython 教程(三): 菜单与工具栏》有1个想法

  1. 本章的内容“图标和快捷键”,第36行代码‘ qmi = wx.MenuItem(fileMenu, APP_EXIT, ‘&QuittCtrl+Q’)’应无法实现图中效果。
    参考原文https://zetcode.com/wxpython/menustoolbars/,如想实现图中效果应为‘ qmi = wx.MenuItem(fileMenu, APP_EXIT, ‘&Quit\tCtrl+Q’)’。

发表评论

电子邮件地址不会被公开。 必填项已用*标注