wxPython 快速指南



wxPython - 简介

wxPython 是一个 Python 包装器,用于流行的跨平台 GUI 工具包 wxWidgets(用 C++编写)。由 Robin Dunn 和 Harri Pasanen 开发,wxPython 实现为一个 Python 扩展模块。

就像 wxWidgets 一样,wxPython 也是一个自由软件。它可以从官方网站 http://wxpython.org 下载。许多操作系统的二进制文件和源代码都可以在此网站下载。

wxPython API 中的主要模块包括一个核心模块。它包含wxObject 类,它是 API 中所有类的基类。控件模块包含 GUI 应用程序开发中使用的所有窗口部件。例如,wx.Button、wx.StaticText(类似于标签)、wx.TextCtrl(可编辑文本控件)等。

wxPython API 有 GDI(图形设备接口)模块。它是一组用于在窗口部件上绘图的类。字体、颜色、画笔等类都是它的一部分。所有容器窗口类都在 Windows 模块中定义。

wxPython 的官方网站还托管 Project Phoenix——一个针对 Python 3.* 的 wxPython 新实现。它专注于提高速度、可维护性和可扩展性。该项目始于 2012 年,目前仍处于测试阶段。

wxPython - 环境配置

Windows

Windows 操作系统(32 位和 64 位)的预构建二进制文件可在 http://www.wxpython.org/download.php 页面上找到。最新的安装程序版本如下:wxPython3.0-win32-3.0.2.0-py27.exe(适用于 32 位 Python 2.7) wxPython3.0-win64-3.0.2.0-py27.exe(适用于 64 位 Python 2.7)

wxPython 演示、示例和 wxWidgets 文档也可在同一页面下载。

wxPython3.0-win32-docs-demos.exe

Linux

许多 Linux 发行版的 wxPython 二进制文件可以在其各自的存储库中找到。将需要使用相应的包管理器来下载和安装。例如,在 Debian Linux 上,以下命令应该能够安装 wxPython。

sudo apt-get install python-wxgtk3.0

MacOS

MacOS 的预构建二进制文件(磁盘映像形式)可在官方网站的下载页面上找到。

wxPython - Hello World

一个简单的 GUI 应用程序,显示 Hello World 消息,使用以下步骤构建:

  • 导入 wx 模块。

  • 定义 Application 类的对象。

  • 创建一个顶级窗口作为 wx.Frame 类的对象。标题和大小参数在构造函数中给出。

  • 虽然可以在 Frame 对象中添加其他控件,但无法管理它们的布局。因此,将一个 Panel 对象放入 Frame 中。

  • 添加一个 StaticText 对象,以在窗口内的所需位置显示“Hello World”。

  • 通过 show() 方法激活框架窗口。

  • 进入 Application 对象的主事件循环。

import wx 
 
app = wx.App() 
window = wx.Frame(None, title = "wxPython Frame", size = (300,200)) 
panel = wx.Panel(window) 
label = wx.StaticText(panel, label = "Hello World", pos = (100,50)) 
window.Show(True) 
app.MainLoop()

上述代码产生以下输出:

Hello World

wxFrame 对象是最常用的顶级窗口。它派生自wxWindow 类。框架是一个窗口,其大小和位置可以由用户更改。它有一个标题栏和控制按钮。如果需要,可以启用菜单栏、工具栏和状态栏等其他组件。wxFrame 窗口可以包含任何不是对话框或另一个框架的框架。

wxPython - GUI构建工具

通过手动编码创建美观的 GUI 可能很繁琐。一个可视化 GUI 设计器工具始终很方便。许多针对 wxPython 的 GUI 开发 IDE 都可用。以下是一些:

  • wxFormBuilder
  • wxDesigner
  • wxGlade
  • BoaConstructor
  • gui2py

wxFormBuilder 是一个开源的、跨平台的所见即所得 GUI 构建器,可以将 wxWidget GUI 设计转换为 C++、Python、PHP 或 XML 格式。这里简要介绍了 wxFormBuilder 的使用方法。

首先,需要从 http://sourceforge.net/projects/wxformbuilder/ 下载并安装最新版本的 wxFormBuilder。打开应用程序后,中间会出现一个带有空白灰色区域的新项目。

为项目命名,并选择 Python 作为代码生成语言。这在对象属性窗口中完成,如下图所示:

Object Properties

然后从组件调色板的“窗体”选项卡中选择 Frame。

Choose Frame

从“布局”选项卡中添加一个垂直 wxBoxSizer。

Add wxBoxSizer

在 Box 中添加必要的控件,并使用合适的标题。这里添加了一个 StaticText(标签)、两个 TextCtrl 对象(文本框)和一个 wxButton 对象。框架如下图所示:

Add Controls

在这三个控件上启用 Expand 和 Stretch。在 wxButton 对象的对象属性中,将函数 findsquare() 分配给 OnButtonClick 事件。

Three Controls

保存项目并按 F8 生成已开发 GUI 的 Python 代码。将生成的代码文件命名为 Demo.py

在可执行的 Python 脚本中,导入 demo.py 并定义 FindSquare() 函数。声明 Application 对象并启动主事件循环。以下是可执行代码:

import wx 
  
#import the newly created GUI file 
import demo  
class CalcFrame(demo.MyFrame1): 
   def __init__(self,parent): 
      demo.MyFrame1.__init__(self,parent)  
		
   def FindSquare(self,event): 
      num = int(self.m_textCtrl1.GetValue()) 
      self.m_textCtrl2.SetValue (str(num*num)) 
        
app = wx.App(False) 
frame = CalcFrame(None) 
frame.Show(True) 
#start the applications 
app.MainLoop() 

上述代码产生以下输出:

GUI Builder Output

wxPython - 主要类

原始 wxWidgets(用 C++编写)是一个庞大的类库。该库中的 GUI 类使用 wxPython 模块移植到 Python,该模块试图尽可能准确地镜像原始 wxWidgets 库。因此,wxPython 中的 wx.Frame 类与 C++ 版本中的 wxFrame 类的工作方式非常相似。

wxObject 是大多数类的基类。wxApp(在 wxPython 中为 wx.App)的对象表示应用程序本身。生成 GUI 后,应用程序通过 MainLoop() 方法进入事件循环。下图描述了 wxPython 中最常用的 GUI 类的类层次结构。

wxWindow Hierarchy wxGDIObject Hierarchy wxSizer Hierarchy wxButton Hierarchy
序号 类和描述
1 wx.Frame

wx.Frame 类有一个没有参数的默认构造函数。

2 wx.Panel

wx.Panel 类通常放在 wxFrame 对象内。此类也继承自 wxWindow 类。

3 wx.StaticText

wx.StaticText 类对象呈现一个包含只读文本的控件。因为它不会产生任何事件,所以它可以被称为被动控件。

4 TextCtrl

在 wxPython 中,wx.TextCtrl 类的对象用于此目的。它是一个可以显示和编辑文本的控件。

5 RadioButton & RadioBox

每个按钮(wx.RadioButton 类的对象)在圆形按钮旁边都有一个文本标签。wxPython API 还包含 wx.RadioBox 类。它的对象为该组提供边框和标签。

6 wx.CheckBox

复选框显示一个小的带标签的矩形框。单击时,矩形内会出现一个复选标记,以指示已做出选择。

7 ComboBox & Choice 类

wx.ComboBox 对象提供一个项目列表供选择。可以将其配置为下拉列表或永久显示。wxPython API 包含 wx.Choice 类,其对象也是一个永久只读的下拉列表。

8 Wx.Gauge

Wx.Gauge 类对象显示一个垂直或水平条,以图形方式显示递增的数量。

9 wx.Slider

wxPython API 包含 wx.Slider 类。它提供与滚动条相同的功能。滑块提供了一种方便的方法来处理通过滑块特定的 wx.EVT_SLIDER 事件绑定器拖动滑块。

10 wx.MenuBar

顶级窗口标题栏下方的水平条用于显示一系列菜单。它是 wxPython API 中 wx.MenuBar 类的对象。

11 wx.Toolbar

如果 wx.Toolbar 对象的 style 参数设置为 wx.TB_DOCKABLE,则它将变为可停靠的。也可以使用 wxPython 的 AUIToolBar 类构造浮动工具栏。

12 Wx.Dialog

虽然 Dialog 类对象看起来像 Frame,但它通常用作父框架顶部的弹出窗口。Dialog 的目的是从用户那里收集一些数据并将其发送到父框架。

13 wx.Notebook

wx.Notebook 窗口部件提供一个选项卡式控件。框架中的一个 Notebook 对象具有一个或多个选项卡(称为页面),每个页面都有一个显示控件布局的面板。

14 wx.SplitterWindow

此类的对象是一个布局管理器,它包含两个子窗口,其大小可以通过拖动它们之间的边界来动态更改。Splitter 控件提供一个可以拖动以调整控件大小的句柄。

15 HTMLWindow

wxHTML 库包含用于解析和显示 HTML 内容的类。虽然这并非旨在成为一个功能齐全的浏览器,但 wx.HtmlWindow 对象是一个通用的 HTML 查看器。

16 ListBox & ListCtrl

wx.ListBox 窗口部件显示一个垂直可滚动的字符串列表。默认情况下,列表中可以选择单个项目。ListCtrl 窗口部件是一个高度增强的列表显示和选择工具。可以在报表视图、列表视图或图标视图中显示多列列表。

wxPython - 事件处理

与以顺序方式执行的控制台模式应用程序不同,基于 GUI 的应用程序是事件驱动的。函数或方法是响应用户操作(例如单击按钮、从集合中选择项目或鼠标单击等,称为事件)而执行的。

应用程序运行期间发生的事件相关数据存储为从wx.Event派生的子类的对象。显示控件(例如按钮)是特定类型事件的源,并产生与其关联的Event类对象。例如,单击按钮会发出wx.CommandEvent。此事件数据将分派到程序中的事件处理程序方法。wxPython 具有许多预定义的事件绑定器。事件绑定器封装了特定窗口小部件(控件)、其关联的事件类型和事件处理程序方法之间的关系。

例如,要在按钮单击事件上调用程序的OnClick() 方法,需要以下语句:

self.b1.Bind(EVT_BUTTON, OnClick)

Bind() 方法由所有显示对象从wx.EvtHandler 类继承。这里的EVT_.BUTTON 是绑定器,它将按钮单击事件与OnClick() 方法关联。

示例

在以下示例中,由拖动顶级窗口(在本例中为wx.Frame 对象)引起的MoveEvent 与使用wx.EVT_MOVE 绑定器的OnMove() 方法连接。代码显示一个窗口。如果使用鼠标移动它,则其瞬时坐标将显示在控制台上。

import wx
  
class Example(wx.Frame): 
            
   def __init__(self, *args, **kw): 
      super(Example, self).__init__(*args, **kw)  
      self.InitUI() 
           
   def InitUI(self): 
      self.Bind(wx.EVT_MOVE, self.OnMove) 
      self.SetSize((250, 180)) 
      self.SetTitle('Move event') 
      self.Centre() 
      self.Show(True)
		   
   def OnMove(self, e): 
      x, y = e.GetPosition() 
      print "current window position x = ",x," y= ",y 
         
ex = wx.App() 
Example(None) 
ex.MainLoop()   

上述代码产生以下输出:

Move Event

当前窗口位置 x = 562 y = 309

当前窗口位置 x = 562 y = 309

当前窗口位置 x = 326 y = 304

当前窗口位置 x = 384 y = 240

当前窗口位置 x = 173 y = 408

当前窗口位置 x = 226 y = 30

当前窗口位置 x = 481 y = 80

下表列出了一些从wx.Event 继承的子类:

序号 事件和描述
1

wxKeyEvent

按下或释放按键时发生

2

wxPaintEvent

每当需要重绘窗口内容时生成

3

wxMouseEvent

包含有关任何由于鼠标活动(例如鼠标按钮按下或拖动)而发生的事件的数据

4

wxScrollEvent

与可滚动控件(如wxScrollbar 和wxSlider)相关联

5

wxCommandEvent

包含源自许多窗口小部件(如按钮、对话框、剪贴板等)的事件数据。

6

wxMenuEvent

不同的菜单相关事件,不包括菜单命令按钮单击

7

wxColourPickerEvent

wxColourPickerCtrl 生成的事件

8

wxDirFilePickerEvent

FileDialog 和 DirDialog 生成的事件

wxPython 中的事件分为两种类型:基本事件和命令事件。基本事件停留在其起源的窗口中。大多数 wxWidgets 生成命令事件。命令事件可以传播到窗口或窗口,这些窗口在类层次结构中位于源窗口之上。

示例

以下是事件传播的一个简单示例。完整的代码是:

import wx
  
class MyPanel(wx.Panel): 
     
   def __init__(self, parent): 
      super(MyPanel, self).__init__(parent)
		
      b = wx.Button(self, label = 'Btn', pos = (100,100)) 
      b.Bind(wx.EVT_BUTTON, self.btnclk) 
      self.Bind(wx.EVT_BUTTON, self.OnButtonClicked) 
		
   def OnButtonClicked(self, e): 
         
      print 'Panel received click event. propagated to Frame class' 
      e.Skip()  
		
   def btnclk(self,e): 
      print "Button received click event. propagated to Panel class" 
      e.Skip()
		
class Example(wx.Frame):

   def __init__(self,parent): 
      super(Example, self).__init__(parent)  
         
      self.InitUI() 

   def InitUI(self):
	
      mpnl = MyPanel(self) 
      self.Bind(wx.EVT_BUTTON, self.OnButtonClicked)
		
      self.SetTitle('Event propagation demo') 
      self.Centre() 
      self.Show(True)
		
   def OnButtonClicked(self, e): 
         
      print 'click event received by frame class' 
      e.Skip()
		
ex = wx.App() 
Example(None) 
ex.MainLoop()

在上面的代码中,有两个类。MyPanel,一个wx.Panel 子类和Example,一个wx.Frame 子类,它是程序的顶级窗口。一个按钮放在面板中。

此Button 对象绑定到一个事件处理程序btnclk(),该处理程序将其传播到父类(在本例中为MyPanel)。按钮单击生成一个CommandEvent,可以通过Skip() 方法将其传播到其父级。

MyPanel 类对象还将接收到的事件绑定到另一个处理程序OnButtonClicked()。此函数又将其传递给其父级Example 类。上述代码产生以下输出:

Event Handling Output

Button received click event. Propagated to Panel class. 
Panel received click event. Propagated to Frame class. 
Click event received by frame class.

wxPython - 布局管理

可以通过指定以像素为单位测量的绝对坐标,将GUI 窗口小部件放置在容器窗口内。坐标相对于其构造函数的size 参数定义的窗口尺寸。窗口小部件在窗口内的位置由其构造函数的pos 参数定义。

import wx  

app = wx.App() 
window = wx.Frame(None, title = "wxPython Frame", size = (300,200)) 
panel = wx.Panel(window) 
label = wx.StaticText(panel, label = "Hello World", pos = (100,50)) 
window.Show(True) 
app.MainLoop()

但是,这种绝对定位由于以下原因并不合适:

  • 即使调整窗口大小,窗口小部件的位置也不会改变。

  • 在具有不同分辨率的不同显示设备上的外观可能不一致。

  • 布局修改很困难,因为它可能需要重新设计整个表单。

wxPython API 提供布局类,用于更优雅地管理容器内窗口小部件的位置。布局管理器相对于绝对定位的优点是:

  • 窗口内的窗口小部件会自动调整大小。
  • 确保在具有不同分辨率的显示设备上外观一致。
  • 可以动态添加或删除窗口小部件,而无需重新设计。

在wxPython 中,布局管理器称为Sizer。Wx.Sizer 是所有sizer 子类的基类。让我们讨论一些重要的sizer,例如wx.BoxSizer、wx.StaticBoxSizer、wx.GridSizer、wx.FlexGridSizer 和wx.GridBagSizer。

序号 Sizer 和描述
1 BoxSizer

此sizer 允许以行方式或列方式排列控件。BoxSizer 的布局由其orientation 参数(wxVERTICAL 或wxHORIZONTAL)确定。

2 GridSizer

顾名思义,GridSizer 对象呈现一个二维网格。控件按从左到右、从上到下的顺序添加到网格槽中。

3 FlexiGridSizer

此sizer 也具有二维网格。但是,它在单元格中布置控件方面提供了更多灵活性。

4 GridBagSizer

GridBagSizer 是一个多功能的sizer。它提供了比FlexiGridSizer 更多的增强功能。子窗口小部件可以添加到网格内的特定单元格。

5 StaticBoxSizer

StaticBoxSizer 将box sizer 放入静态框中。它在框周围提供一个边框,以及顶部的标签。

wxPython - 按钮

按钮窗口小部件在任何GUI 界面中使用最广泛。它捕获用户生成的单击事件。它最明显的用途是触发与其绑定的处理程序函数。

wxPython 类库提供了不同类型的按钮。有一个简单传统的按钮,wx.Button 类对象,它带有文本作为其标题。还提供了一个双状态按钮,名为wx.ToggleButton。其按下或弹起状态可以通过事件处理程序函数识别。

另一种类型的按钮,wx.BitmapButton 显示位图(图像)作为其表面的图标。

wx.Button 类和wx.ToggleButton 类的构造函数采用以下参数:

Wx.Button(parent, id, label, pos, size, style)

这些是wx.Button 类的一些重要方法:

序号 方法和描述
1

SetLabel()

以编程方式设置按钮的标题

2

GetLabel()

返回按钮的标题

3

SetDefault()

将按钮设置为顶级窗口的默认按钮。模拟按下Enter 键时的单击事件

wx.ToggleButton 类的两个重要方法是:

序号 方法和描述
1

GetValue()

返回切换按钮的状态(开/关)

2

SetValue()

以编程方式设置按钮的状态

为了创建位图按钮,首先需要根据图像文件构造位图对象。

最常用的wx.Bitmap 类构造函数的变体如下:

Wx.Bitmap(fiiename, wx.BITMAP_TYPE)

一些预定义的位图类型常量是:

wx.BITMAP_TYPE_BMP
wx.BITMAP_TYPE_ICO
wx.BITMAP_TYPE_CUR
wx.BITMAP_TYPE_TIFF
wx.BITMAP_TYPE_TIF
wx.BITMAP_TYPE_GIF
wx.BITMAP_TYPE_PNG
wx.BITMAP_TYPE_JPEG
wx.BITMAP_TYPE_PCX
wx.BITMAP_TYPE_ICON
wx.BITMAP_TYPE_ANY

此位图对象用作wx.BitmapButton 类构造函数的参数之一。

Wx.BitmapButton(parent, id, bitmap, pos, size, style)

在某些操作系统平台上,位图按钮可以同时显示位图和标签。SetLabel() 方法分配标题。在其他平台上,它用作内部标签。

普通按钮和位图按钮都会发出wx.CommandEvent。EVT_BUTTON 绑定器将处理程序函数与其关联。

另一方面,切换按钮使用wx.TOGGLEBUTTON 绑定器进行事件处理。

在以下示例中,所有三种类型的按钮都放置在面板的垂直box sizer 中。

使用以下语句创建简单的按钮对象:

self.btn = wx.Button(panel, -1, "click Me")

切换按钮由以下语句构造:

self.tbtn = wx.ToggleButton(panel , -1, "click to on")

这些按钮使用以下语句添加到垂直sizer 中:

vbox.Add(self.btn,0,wx.ALIGN_CENTER) 
vbox.Add(self.tbtn,0,wx.EXPAND|wx.ALIGN_CENTER)

注意:由于wx.EXPAND 标志,切换按钮占据了框架的整个宽度。

使用EVT_BUTTON 和EVT_TOGGLEBUTTON 绑定器,它们与各自的处理程序关联。

self.btn.Bind(wx.EVT_BUTTON,self.OnClicked) 
self.tbtn.Bind(wx.EVT_TOGGLEBUTTON,self.OnToggle)

三个位图按钮添加到水平box sizer 中。这些按钮显示图像作为其标题的图标。

bmp = wx.Bitmap("NEW.BMP", wx.BITMAP_TYPE_BMP) 
self.bmpbtn = wx.BitmapButton(panel, id = wx.ID_ANY, bitmap = bmp,
   size = (bmp.GetWidth()+10, bmp.GetHeight()+10))
  
bmp1 = wx.Bitmap("OPEN.BMP", wx.BITMAP_TYPE_BMP) 
self.bmpbtn1 = wx.BitmapButton(panel, id = wx.ID_ANY, bitmap = bmp1,
   size = (bmp.GetWidth()+10, bmp.GetHeight()+10))
  
bmp2 = wx.Bitmap("SAVE.BMP", wx.BITMAP_TYPE_BMP) 
self.bmpbtn2 = wx.BitmapButton(panel, id = wx.ID_ANY, bitmap = bmp2,
   size = (bmp.GetWidth()+10, bmp.GetHeight()+10))

这三个按钮的单击事件定向到OnClicked() 方法。

self.bmpbtn.Bind(wx.EVT_BUTTON, self.OnClicked) 
self.bmpbtn1.Bind(wx.EVT_BUTTON, self.OnClicked) 
self.bmpbtn2.Bind(wx.EVT_BUTTON, self.OnClicked)

这些按钮的内部标签分别设置为NEW、OPEN 和SAVE。

OnClicked() 事件处理程序函数检索导致单击事件的源按钮的标签。该标签将打印在控制台上。

def OnClicked(self, event): 
   btn = event.GetEventObject().GetLabel() 
   print "Label of pressed button = ",btn 

单击切换按钮时,将触发OnToggle() 事件处理程序。其状态由GetValue() 方法读取,并据此设置按钮的标题。

def OnToggle(self,event): 
   state = event.GetEventObject().GetValue() 
   if state == True: 
      print "off" 
      event.GetEventObject().SetLabel("click to off") 
   else: 
      print "on" 
      event.GetEventObject().SetLabel("click to on")

完整的代码清单如下:

import wx 
class Mywin(wx.Frame): 
   def __init__(self, parent, title): 
      super(Mywin, self).__init__(parent, title = title,size = (200,150))  
      panel = wx.Panel(self) 
      vbox = wx.BoxSizer(wx.VERTICAL) 
         
      self.btn = wx.Button(panel,-1,"click Me") 
      vbox.Add(self.btn,0,wx.ALIGN_CENTER) 
      self.btn.Bind(wx.EVT_BUTTON,self.OnClicked) 
         
      self.tbtn = wx.ToggleButton(panel , -1, "click to on") 
      vbox.Add(self.tbtn,0,wx.EXPAND|wx.ALIGN_CENTER) 
      self.tbtn.Bind(wx.EVT_TOGGLEBUTTON,self.OnToggle) 
         
      hbox = wx.BoxSizer(wx.HORIZONTAL) 
         
      bmp = wx.Bitmap("NEW.BMP", wx.BITMAP_TYPE_BMP) 
      self.bmpbtn = wx.BitmapButton(panel, id = wx.ID_ANY, bitmap = bmp,
         size = (bmp.GetWidth()+10, bmp.GetHeight()+10)) 
			
      hbox.Add(self.bmpbtn,0,wx.ALIGN_CENTER) 
      self.bmpbtn.Bind(wx.EVT_BUTTON,self.OnClicked) 
      self.bmpbtn.SetLabel("NEW") 
         
      bmp1 = wx.Bitmap("OPEN.BMP", wx.BITMAP_TYPE_BMP) 
      self.bmpbtn1 = wx.BitmapButton(panel, id = wx.ID_ANY, bitmap = bmp1,
         size = (bmp.GetWidth()+10, bmp.GetHeight()+10)) 
			
      hbox.Add(self.bmpbtn1,0,wx.ALIGN_CENTER) 
      self.bmpbtn1.Bind(wx.EVT_BUTTON,self.OnClicked) 
      self.bmpbtn1.SetLabel("OPEN") 
         
      bmp2 = wx.Bitmap("SAVE.BMP", wx.BITMAP_TYPE_BMP) 
      self.bmpbtn2 = wx.BitmapButton(panel, id = wx.ID_ANY, bitmap = bmp2,
         size = (bmp.GetWidth()+10, bmp.GetHeight()+10))
			
      hbox.Add(self.bmpbtn2,0,wx.ALIGN_CENTER) 
      self.bmpbtn2.Bind(wx.EVT_BUTTON,self.OnClicked)
      self.bmpbtn2.SetLabel("SAVE") 
         
      vbox.Add(hbox,1,wx.ALIGN_CENTER) 
      panel.SetSizer(vbox) 
        
      self.Centre() 
      self.Show() 
      self.Fit()  
		
   def OnClicked(self, event): 
      btn = event.GetEventObject().GetLabel() 
      print "Label of pressed button = ",btn 
		
   def OnToggle(self,event): 
      state = event.GetEventObject().GetValue() 
		
      if state == True: 
         print "Toggle button state off" 
         event.GetEventObject().SetLabel("click to off") 
      else: 
         print " Toggle button state on" 
         event.GetEventObject().SetLabel("click to on") 
             
app = wx.App() 
Mywin(None,  'Button demo') 
app.MainLoop()

上述代码产生以下输出:

Buttons Output

按下按钮的标签 = click Me

切换按钮状态关闭

切换按钮状态打开

按下按钮的标签 = NEW

按下按钮的标签 = OPEN

按下按钮的标签 = SAVE

wxPython - 可停靠窗口

wxAui 是wxWidgets API 中集成的先进用户界面库。Wx.aui.AuiManager 是AUI 框架中的核心类。

AuiManager 使用每个面板在wx.aui.AuiPanelInfo 对象中的信息来管理与特定框架关联的面板。让我们了解PanelInfo 对象控制对接和浮动行为的各种属性。

将可停靠窗口放在顶级框架中涉及以下步骤:

首先,创建一个AuiManager 对象。

self.mgr = wx.aui.AuiManager(self)

然后,设计一个具有所需控件的面板。

pnl = wx.Panel(self) 
pbox = wx.BoxSizer(wx.HORIZONTAL) 
text1 = wx.TextCtrl(pnl, -1, "Dockable", style = wx.NO_BORDER | wx.TE_MULTILINE) 
pbox.Add(text1, 1, flag = wx.EXPAND) 
pnl.SetSizer(pbox)

设置AuiPanelInfo 的以下参数。

  • 方向:顶部、底部、左侧、右侧或中心

  • 位置:多个面板可以放置在一个可停靠区域内。每个都给出一个位置编号。

  • :多个面板显示在一行中。就像多条工具栏出现在同一行中一样。

  • :面板可以分层放置。

使用此PanelInfo,将设计的面板添加到管理器对象中。

info1 = wx.aui.AuiPaneInfo().Bottom() 
self.mgr.AddPane(pnl,info1)

其余的顶级窗口可以像往常一样拥有其他控件。

完整的代码如下:

import wx 
import wx.aui
  
class Mywin(wx.Frame):
  
   def __init__(self, parent, title): 
      super(Mywin, self).__init__(parent, title = title, size = (300,300)) 
		
      self.mgr = wx.aui.AuiManager(self)
		
      pnl = wx.Panel(self) 
      pbox = wx.BoxSizer(wx.HORIZONTAL)
      text1 = wx.TextCtrl(pnl, -1, "Dockable", style = wx.NO_BORDER | wx.TE_MULTILINE) 
      pbox.Add(text1, 1, flag = wx.EXPAND) 
      pnl.SetSizer(pbox) 
         
      info1 = wx.aui.AuiPaneInfo().Bottom() 
      self.mgr.AddPane(pnl, info1) 
      panel = wx.Panel(self) 
      text2 = wx.TextCtrl(panel, size = (300,200), style =  wx.NO_BORDER | wx.TE_MULTILINE) 
      box = wx.BoxSizer(wx.HORIZONTAL) 
      box.Add(text2, 1, flag = wx.EXPAND) 
         
      panel.SetSizerAndFit(box) 
      self.mgr.Update() 
		
      self.Bind(wx.EVT_CLOSE, self.OnClose) 
      self.Centre() 
      self.Show(True) 
		
   def OnClose(self, event): 
      self.mgr.UnInit() 
      self.Destroy() 
		
app = wx.App()
Mywin(None,"Dock Demo")  
app.MainLoop()

上述代码产生以下输出:

Dock Demo

wxPython - 多文档界面

典型的GUI 应用程序可能有多个窗口。选项卡式和堆叠式窗口小部件允许一次激活一个这样的窗口。但是,很多时候这种方法可能不起作用,因为其他窗口的视图被隐藏了。

同时显示多个窗口的一种方法是将它们创建为独立窗口。这称为SDI(单文档界面)。这需要更多内存资源,因为每个窗口可能都有自己的菜单系统、工具栏等。

wxPython 中的MDI 框架提供了一个wx.MDIParentFrame 类。其对象充当多个子窗口的容器,每个子窗口都是wx.MDIChildFrame 类的对象。

子窗口位于父框架的MDIClientWindow 区域中。添加子框架后,父框架的菜单栏会显示一个“窗口”菜单,其中包含以级联或平铺方式排列子窗口的按钮。

示例

以下示例说明了使用MDIParentFrame 作为顶级窗口。名为NewWindow 的菜单按钮在客户端区域中添加一个子窗口。可以添加多个窗口,然后以级联或平铺顺序排列。

完整的代码如下:

import wx 
 
class MDIFrame(wx.MDIParentFrame): 
   def __init__(self): 
      wx.MDIParentFrame.__init__(self, None, -1, "MDI Parent", size = (600,400)) 
      menu = wx.Menu() 
      menu.Append(5000, "&New Window") 
      menu.Append(5001, "&Exit") 
      menubar = wx.MenuBar() 
      menubar.Append(menu, "&File") 
		
      self.SetMenuBar(menubar) 
      self.Bind(wx.EVT_MENU, self.OnNewWindow, id = 5000) 
      self.Bind(wx.EVT_MENU, self.OnExit, id = 5001) 
		
   def OnExit(self, evt): 
      self.Close(True)  
		
   def OnNewWindow(self, evt): 
      win = wx.MDIChildFrame(self, -1, "Child Window")
      win.Show(True) 
		
app = wx.App() 
frame = MDIFrame() 
frame.Show() 
app.MainLoop()

上述代码产生以下输出:

MDI output

wxPython - 绘图API

GDI+(图形绘制接口)、CoreGraphicsCairo 库构成了wxPython 中绘图API 的框架。wx.GraphicsContext 是主要的绘图对象,使用它可以创建各种设备上下文对象。

wx.DC 是一个抽象类。它的派生类用于在不同设备上呈现图形和文本。设备上下文类是:

  • wx.ScreenDC:使用它在屏幕上绘图,而不是单个窗口。

  • wx.ClientDC:使用它在窗口的客户端区域(没有边框和其他装饰的部分)上绘图,但在wxPaintEvent 中不要使用它。

  • wx.PaintDC:使用它在窗口的客户端区域上绘图,但在wxPaintEvent 中使用。

  • wx.WindowDC:使用它在窗口的整个区域(包括装饰)上绘图。这在非Windows 平台上可能不可用。

wxPython 的绘图 API 提供了绘制形状、文本和图像的不同函数。绘图所需的 Colour、Pen、Brush 和 Font 等对象也可以使用 GDI 类构造。

wx.Colour 类

Colour 对象表示 RGB(红、绿、蓝)强度值的组合,每个值的范围都是 0-255。有一些预定义的颜色对象,例如:

  • wxBLACK
  • wxBLUE
  • wxCYAN
  • wxGREEN
  • wxYELLOW
  • wxLIGHT_GREY
  • wxRED
  • wxWHITE

可以使用自定义的 RGB 值组合来创建wx.Colour 对象

wx.Colour(r,g,b)

wx.Pen 类

Pen 对象确定图形(如线、矩形、圆形等)的形状的颜色、宽度和样式。

预定义的 Pen 对象有:

wxBLACK_DASHED_PEN
wxBLACK_PEN
wxBLUE_PEN
wxCYAN_PEN
wxGREEN_PEN
wxYELLOW_PEN
wxGREY_PEN
wxLIGHT_GREY_PEN
wxMEDIUM_GREY_PEN
wxRED_PEN
wxTRANSPARENT_PEN
wxWHITE_PEN

预定义的 Pen 样式有:

wx.SOLID
wx.DOT
wx.LONG_DASH
wx.SHORT_DASH
wx.DOT_DASH
wx.TRANSPARENT

wx.Brush 类

Brush 是另一个基本的图形对象,用于填充矩形、椭圆形、圆形等形状的背景。

自定义 Brush 对象需要 wx.Colour 和 Brush 样式参数。以下是预定义的笔刷样式列表:

wx.SOLID
wx.STIPPLE
wx.BDIAGONAL_HATCH
wx.CROSSDIAG_HATCH
wx.FDIAGONAL_HATCH
wx.CROSS_HATCH
wx.HORIZONTAL_HATCH
wx.VERTICAL_HATCH
wx.TRANSPARENT

wxPython 有许多函数可以方便地绘制不同的形状、文本和图像。

序号 函数和描述
1

DrawRectangle()

绘制给定尺寸的矩形

2

DrawCircle()

在给定中心点和半径处绘制一个圆形

3

DrawEllipse()

绘制给定 x 和 y 半径的椭圆形

4

DrawLine()

绘制两个 wx.Point 对象之间的直线

5

DrawBitmap()

在给定位置绘制图像

6

DrawText()

在指定位置显示给定的文本

示例

以下示例中实现了上述函数,并使用了 Pen、Brush、Colour 和 Font 对象。

完整的代码如下:

import wx 
 
class Mywin(wx.Frame): 
            
   def __init__(self, parent, title): 
      super(Mywin, self).__init__(parent, title = title,size = (500,300))  
      self.InitUI() 
         
   def InitUI(self): 
      self.Bind(wx.EVT_PAINT, self.OnPaint) 
      self.Centre() 
      self.Show(True)
		
   def OnPaint(self, e): 
      dc = wx.PaintDC(self) 
      brush = wx.Brush("white")  
      dc.SetBackground(brush)  
      dc.Clear() 
        
      dc.DrawBitmap(wx.Bitmap("python.jpg"),10,10,True) 
      color = wx.Colour(255,0,0)
      b = wx.Brush(color) 
		
      dc.SetBrush(b) 
      dc.DrawCircle(300,125,50) 
      dc.SetBrush(wx.Brush(wx.Colour(255,255,255))) 
      dc.DrawCircle(300,125,30) 
		
      font = wx.Font(18, wx.ROMAN, wx.ITALIC, wx.NORMAL) 
      dc.SetFont(font) 
      dc.DrawText("Hello wxPython",200,10) 
		
      pen = wx.Pen(wx.Colour(0,0,255)) 
      dc.SetPen(pen) 
      dc.DrawLine(200,50,350,50) 
      dc.SetBrush(wx.Brush(wx.Colour(0,255,0), wx.CROSS_HATCH)) 
      dc.DrawRectangle(380, 15, 90, 60) 
		
ex = wx.App() 
Mywin(None,'Drawing demo') 
ex.MainLoop()

上述代码产生以下输出:

Drawing Demo

wxPython - 拖放

拖放功能对于用户来说非常直观。在许多桌面应用程序中都可以找到它,用户只需用鼠标拖动对象并将其放在另一个窗口上,即可将对象从一个窗口复制或移动到另一个窗口。

拖放操作包括以下步骤:

  • 声明一个放置目标
  • 创建数据对象
  • 创建 wx.DropSource
  • 执行拖动操作
  • 取消或接受放置

在 wxPython 中,有两个预定义的放置目标:

  • wx.TextDropTarget
  • wx.FileDropTarget

许多 wxPython 小部件支持拖放活动。源控件必须启用拖动,而目标控件必须能够接受(或拒绝)拖动。

用户正在拖动的源数据被放置在目标对象上。目标对象的 OnDropText() 消耗数据。如果需要,可以删除源对象中的数据。

示例

在以下示例中,两个 ListCtrl 对象水平放置在一个 Box Sizer 中。左侧列表填充了 languages[] 数据。它被指定为拖动的源。右侧列表是目标。

languages = ['C', 'C++', 'Java', 'Python', 'Perl', 'JavaScript', 'PHP', 'VB.NET','C#'] 
self.lst1 = wx.ListCtrl(panel, -1, style = wx.LC_LIST) 
self.lst2 = wx.ListCtrl(panel, -1, style = wx.LC_LIST) 

   for lang in languages: 
      self.lst1.InsertStringItem(0,lang)

第二个列表控件为空,是 TextDropTarget 类对象的参数。

class MyTextDropTarget(wx.TextDropTarget):
   def __init__(self, object): 
      wx.TextDropTarget.__init__(self) 
      self.object = object
		
   def OnDropText(self, x, y, data): 
      self.object.InsertStringItem(0, data)

OnDropText() 方法将源数据添加到目标列表控件中。

拖动操作由事件绑定器初始化。

wx.EVT_LIST_BEGIN_DRAG(self, self.lst1.GetId(), self.OnDragInit)

OnDragInit() 函数将拖动数据放在目标上并从源中删除。

def OnDragInit(self, event): 
   text = self.lst1.GetItemText(event.GetIndex()) 
   tobj = wx.PyTextDataObject(text) 
   src = wx.DropSource(self.lst1) 
   src.SetData(tobj) 
   src.DoDragDrop(True) 
   self.lst1.DeleteItem(event.GetIndex())

完整的代码如下:

import wx
  
class MyTarget(wx.TextDropTarget): 
   def __init__(self, object): 
      wx.TextDropTarget.__init__(self) 
      self.object = object  
		
   def OnDropText(self, x, y, data): 
      self.object.InsertStringItem(0, data)  
		
class Mywin(wx.Frame): 
            
   def __init__(self, parent, title): 
      super(Mywin, self).__init__(parent, title = title,size = (-1,300))   
      panel = wx.Panel(self) 
      box = wx.BoxSizer(wx.HORIZONTAL)  
      languages = ['C', 'C++', 'Java', 'Python', 'Perl', 'JavaScript',
         'PHP', 'VB.NET','C#']
			
      self.lst1 = wx.ListCtrl(panel, -1, style = wx.LC_LIST) 
      self.lst2 = wx.ListCtrl(panel, -1, style = wx.LC_LIST) 
      for lang in languages: 
      self.lst1.InsertStringItem(0,lang) 
             
      dt = MyTarget(self.lst2) 
      self.lst2.SetDropTarget(dt) 
      wx.EVT_LIST_BEGIN_DRAG(self, self.lst1.GetId(), self.OnDragInit)
		
      box.Add(self.lst1,0,wx.EXPAND) 
      box.Add(self.lst2, 1, wx.EXPAND) 
		
      panel.SetSizer(box) 
      panel.Fit() 
      self.Centre() 
      self.Show(True)  
     
   def OnDragInit(self, event): 
      text = self.lst1.GetItemText(event.GetIndex()) 
      tobj = wx.PyTextDataObject(text) 
      src = wx.DropSource(self.lst1) 
      src.SetData(tobj) 
      src.DoDragDrop(True) 
      self.lst1.DeleteItem(event.GetIndex()) 
		
ex = wx.App() 
Mywin(None,'Drag&Drop Demo') 
ex.MainLoop()

上述代码产生以下输出:

Drag Drop Output
广告