图形用户界面

跨平台PythonGUI工具包——wxPython

丰富的平台

在编写Python GUI程序前,需要决定使用哪个GUI平台。
简单来说,平台是图形组件的一个特定集合,可以通过叫做GUI工具包的给定Python模块进行访问。

工具包 描述
Tkinter 使用Tk平台。很容易得到。半标准
wxpython 基于wxWindows。跨平台越来越流行
Python Win 只能在Windows上使用,使用了本机的Windows GUI功能
Java Swing 只能用于Jython。使用本机的Java GUI
PyGTK 使用GTK平台,在Linux上很流行
PyQt 使用Qt平台,跨平台

以上选择按照个人喜好进行,但是Python之父Guido van Rossum最爱wxPython。

下载和安装wxPython

wxPython下载页面
使用pip install -U wxPython即可安装

创建示例GUI应用程序

  • 它允许打开给定文件名的文本文件
  • 它允许编辑文本文件
  • 它允许保存文本文件
  • 它允许退出程序

开始

首先需要导入wx模块:
import wx
编写wxPython程序的方法很多,但不可避免的事情是创建应用程序对象。基本的应用程序类叫做ex.App,它负责幕后所有的初始化。
最简单的wxPython程序:

import wx
app = wx.App()      #如果wx.App无法工作,可以将它替换为wx.PySimpleApp
app.MainLoop()

窗口和组件

窗口(window)也称为框架(Frame),它是wx.Frame类的实例。wx框架中的部件都是由他们的父部件使用构造函数的第一个参数创建的。

import wx
app = wx.App()
win = wx.Frame(None)
win.Show()
app.MainLoop()

在框架上增加按钮也很简单——只要使用win作为父参数实例化wx.Button即可:

import wx
app = wx.App()
win = wx.Frame(None)
btn = wx.Button(win)
win.Show()
app.MainLoop()

标签、标题和位置

可以在创建部件的时候使用构造函数的label参数设定它们的标签。同样,也可以使用title参数设定框架的标题。这里推荐使用关键字参数,因为不需要记住顺序。

import wx

app = wx.App()
win = wx.Frame(None, title = 'Simple Editor')

loadButton = wx.Button(win, label = 'Open')

saveButton = wx.Button(win, label = 'Save')

win.Show()

app.MainLoop()

这里只显示一个按钮,不是我们想要的,因为没有设置pos和size尺寸,所以连个按钮重叠了。

import wx

app = wx.App()
win = wx.Frame(None, title='My first GUI', size=(410,335))
win.Show()

loadButton = wx.Button(win, label='Open', pos=(225,5), size=(80,25))
saveButton = wx.Button(win, label='Save', pos=(315, 5), size=(80,25))

filename = wx.TextCtrl(win, pos=(5,5), size=(210, 25))

contents = wx.TextCtrl(win, pos=(5, 35), size=(390, 260), style=wx.TE_MULTILINE | wx.HSCROLL)

app.MainLoop()

这里创建了两个文本控件(text control, wx.TextCtrl对象),每个都是用了自定义风格。默认的文本控件是文本框,就是一行可编辑的文本,没有滚动条,为了创建文本区(text area)只要使用style参数调整风格即可。style参数的值实际上是个整数,但不用直接指定,可以使用按位或运算符OR(或管道运算符)联合wx模块中具有特殊名字的风格来指定。
wx.TE_MULTILINE——获取多行文本区
垂直滚动条(默认就有)
wx.HSCROLL——水平滚动条

更智能的布局

以上每个组件的位置和大小都显示设定的,但是没有明确在窗口大小变化的时候,它们的行为是什么。指定行为的方法有很多,在wx内进行布局的最简单方法是使用尺寸器,最容易使用的工具就是wx.BoxSizer.
尺寸器会管理组建的尺寸,只要将部件添加到尺寸器上,再加上一些布局参数,然后让尺寸器自己去管理父组件的尺寸。背景组件(wx.Panel)

import wx

app = wx.App()
win = wx.Frame(None,title='My first GUI', size=(410,335))
bkg = wx.Panel(win)

loadButton = wx.Button(bkg, label='Open')
saveButton = wx.Button(bkg, label='Save')
contents = wx.TextCtrl(bkg, style=wx.TE_MULTILINE | wx.HSCROLL)
filename = wx.TextCtrl(bkg)

hbox = wx.BoxSizer()
hbox.Add(filename, proportion=1, flag=wx.EXPAND)
hbox.Add(loadButton, proportion=0, flag=wx.LEFT, border=5)
hbox.Add(saveButton, proportion=0, flag=wx.LEFT, border=5)

vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(hbox, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
vbox.Add(contents, proportion=1, flag=wx.EXPAND | wx.LEFT | wx.BOTTOM | wx.RIGHT, border=5)

bkg.SetSizer(vbox)
win.Show()

app.MainLoop()

wx.BoxSizer的构造函数带有一个决定它是水平还是垂直的参数(wx.HORIZONTAL和wx.VERTICAL),默认为水平。Add方法有几个参数,proportion参数根据在窗口改变 大小时所分配的空间设置比例。1代表改变大小,0代表不变化。flag参数类似于构造函数中的style参数,可以使用按位或运算符连接构造符号常量对其进行构造。

事件处理

在GUI术语中,用户执行的动作(比如点击)叫做事件(event)。你需要让程序注意这些事件,并作出反应。可以将函数绑定到所涉及的事件可能发生的组件上。当事件发生时,函数会被调用。利用部件的Bind方法可以将事件处理函数链接到给定的事件上。

假设一个负责打开文件的函数,并将其命名为load。然后可以像下面这样将该函数作为loadButton的事件处理函数。

loadButton.Bind(wx.EVT_BUTTON, load)

wx.EVT_BUTTON表示一个按钮事件
wx框架对于各种事件都有这样的事件常量。

完成了的程序

def load(event):
    file = open(filename.GetValue())
    contents.SetValue(file.read())
    file.close()
def save(event):
     file = open(filename.GetValue(), 'w')
     file.write(contents.GetValue())
     file.close()

最终的GUI程序

import wx
def load(event):
    file = open(filename.GetValue())
    contents.SetValue(file.read())
    file.close()

def save(event):
    file = open(filename.GetValue(), 'w')
    file.write(contents.GetValue())
    file.close()

app = wx.App()
win = wx.Frame(None, title="Simple Editor", size=(410, 335))

bkg = wx.Panel(win)

loadButton = wx.Button(bkg, label='Open')
loadButton.Bind(wx.EVT_BUTTON, load)

saveButton = wx.Button(bkg, label='Save')
saveButton.Bind(wx.EVT_BUTTON, save)

filename = wx.TextCtrl(bkg)
contents = wx.TextCtrl(bkg, style=wx.TE_MULTILINE | wx.HSCROLL)

hbox = wx.BoxSizer()
hbox.Add(filename, proportion=1, flag=wx.EXPAND)
hbox.Add(loadButton, proportion=0, flag=wx.LEFT, border=5)
hbox.Add(saveButton, proportion=0, flag=wx.LEFT, border=5)

vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(hbox, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
vbox.Add(contents, proportion=1,
         flag=wx.EXPAND | wx.LEFT | wx.BOTTOM | wx.RIGHT, border=5)

bkg.SetSizer(vbox)
win.Show()

app.MainLoop()

但是我宁愿用......

使用Tkinter

使用Jython和Swing

使用其它开发包

小结

  • 图形用户界面
  • Python的GUI平台
  • wxPython
  • 事件处理

推荐阅读更多精彩内容