wxPython - 快速指南


wxPython - 简介

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

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

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

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

wxPython 的官方网站还托管了 Project Phoenix——wxPython for Python 3.* 的新实现。它专注于提高速度、可维护性和可扩展性。该项目于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 应用程序 -

  • 导入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()

上面的代码产生以下输出 -

你好世界

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

wxPython - GUI 构建工具

通过手动编码创建漂亮的 GUI 可能很乏味。可视化 GUI 设计器工具总是很方便。许多针对 wxPython 的 GUI 开发 IDE 都可用。以下是其中一些 -

  • wxFormBuilder
  • 设计器
  • wx格莱德
  • Boa构造函数
  • gui2py

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

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

给项目起一个合适的名称,并选择Python作为代码生成语言。这是在对象属性窗口中完成的,如下图所示 -

对象属性

然后从组件选项板的“表单”选项卡中选择“框架”。

选择镜框

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

添加wxBoxSizer

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

添加控件

在这三个控件上启用“扩展”和“拉伸”。在 wxButton 对象的对象属性中,将函数 findsquare() 分配给 OnButtonClick 事件。

三控

保存项目并按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 生成器输出

wxPython - 主要类

原来的wxWidgets(用C++编写)是一个巨大的类库。该库中的 GUI 类通过 wxPython 模块移植到 Python,该模块尝试尽可能接近地镜像原始 wxWidgets 库。因此,wxPython 中的 wx.Frame 类与 C++ 版本中的 wxFrame 类的Behave方式非常相似。

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

wxWindow层次结构 wxGDI对象层次结构 wxSizer层次结构 wxButton层次结构
序列号 类别和描述
1 wx.Frame

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

2 wx.面板

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

3 wx.静态文本

wx.StaticText 类对象提供了一个保存此类只读文本的控件。它可以被称为被动控制,因为它不产生任何事件。

4 文本控制

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

5 单选按钮和单选框

每个按钮(wx.RadioButton 类的对象)在圆形按钮旁边带有一个文本标签。wxPython API也由wx.RadioBox类组成。它的对象为组提供了边框和标签。

6 wx.CheckBox

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

7 组合框和选择类

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

8 Wx 规格

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

9 wx.滑块

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

10 wx.MenuBar

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

11 wx.工具栏

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

12 Wx.Dialog

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

13 wx.笔记本

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

14 wx.SplitterWindow

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

15 HTML窗口

wxHTML 库包含用于解析和显示 HTML 内容的类。尽管这并不是一个全功能的浏览器,但 wx.HtmlWindow 对象是一个通用的 HTML 查看器。

16 列表框和列表控件

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

wxPython - 事件处理

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

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

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

self.b1.Bind(EVT_BUTTON, OnClick)

所有显示对象都从 wx.EvtHandler 类继承Bind() 方法。这里的 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()   

上面的代码产生以下输出 -

移动事件

当前窗口位置 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

wxKey事件

按下或释放按键时发生

2

wxPaintEvent

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

3

wxMouseEvent

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

4

wxScrollEvent

与 wxScrollbar 和 wxSlider 等可滚动控件关联

5

wxCommandEvent

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

6

wx菜单事件

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

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 类。上面的代码产生以下输出 -

事件处理输出

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 子类的基类。让我们讨论一些重要的大小调整器,例如wx.BoxSizer、wx.StaticBoxSizer、wx.GridSizer、wx.FlexGridSizer 和wx.GridBagSizer。

序列号 尺寸测定器和描述
1 盒子大小调整器

该大小调整器允许控件以行或列的方式排列。BoxSizer 的布局由其方向参数(wxVERTICAL 或wxHORIZONTAL)决定。

2 网格大小调整器

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

3 灵活网格尺寸调整器

该尺寸测定器还具有二维网格。然而,它在单元格中布局控件方面提供了更多的灵活性。

4 网格包尺寸确定器

GridBagSizer 是一款多功能尺寸确定器。它提供了比 FlexiGridSizer 更多的增强功能。子部件可以添加到网格内的特定单元格。

5 静态框大小调整器

StaticBoxSizer 将盒子大小调整器放入静态盒子中。它在盒子周围提供了边框,并在顶部提供了标签。

wxPython - 按钮

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

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

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

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

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

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

序列号 方法与说明
1

设置标签()

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

2

获取标签()

返回按钮的标题

3

默认设置()

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

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

序列号 方法与说明
1

获取值()

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

2

设定值()

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

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

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 绑定器进行事件处理。

在以下示例中,所有三种类型的按钮都放置在面板的垂直框大小调整器中。

简单的按钮对象是使用语句创建的 -

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

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

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

使用以下语句将这些按钮添加到垂直大小调整器中 -

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)

三个位图按钮被添加到水平框大小调整器中。这些按钮将图像显示为图标作为其标题。

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()

上面的代码产生以下输出 -

按钮输出

按下按钮的标签 = 单击我

切换按钮状态关闭

切换按钮状态

按下按钮的标签 = NEW

按下按钮的标签 = OPEN

按下按钮的标签 = 保存

wxPython - 可停靠的 Windows

wxAui是一个集成在 wxWidgets API 中的高级用户界面库。Wx.aui.AuiManager是AUI框架中的中心类。

AuiManager使用 wx.aui.AuiPanelInfo 对象中每个面板的信息来管理与特定框架关联的窗格。让我们了解一下PanelInfo对象控制停靠和浮动Behave的各种属性。

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

首先,创建一个 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()

上面的代码产生以下输出 -

码头演示

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()

上面的代码产生以下输出 -

录入输出

wxPython - 绘图 API

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

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

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

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

  • wx.PaintDC - 使用它在窗口的客户区域上绘制,但只能在 wxPaintEvent 内进行。

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

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

wx.颜色类别

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

  • 黑色
  • 青色
  • wx绿色
  • wx黄色
  • wxLIGHT_GREY
  • 红红
  • 白色

具有自定义 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

预定义的笔样式是 -

wx.SOLID
wx.DOT
wx.LONG_DASH
wx.SHORT_DASH
wx.DOT_DASH
wx.透明

wx.画笔类

画笔是填充矩形、椭圆形、圆形等形状背景所需的另一种基本图形对象。

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

wx.SOLID
wx.点画
wx.BDIAGONAL_HATCH
wx.CROSSDIAG_HATCH
wx.FDIAGONAL_HATCH
wx.CROSS_HATCH
wx.HORIZONTAL_HATCH
wx.VERTICAL_HATCH
wx.透明

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

序列号 功能及说明
1

绘制矩形()

绘制给定尺寸的矩形

2

画圆()

以给定点为圆心和半径绘制圆

3

绘制椭圆()

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

4

画线()

在两个 wx.Point 对象之间绘制一条线

5

绘制位图()

在给定位置绘制图像

6

绘制文本()

在指定位置显示给定文本

例子

上述功能在下面的示例中使用 Pen、Brush、Color 和 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()

上面的代码产生以下输出 -

绘图演示

wxPython - 拖放

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

拖放操作涉及以下步骤 -

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

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

  • wx.TextDropTarget
  • wx.FileDropTarget

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

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

例子

在以下示例中,两个 ListCrl 对象水平放置在 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()

上面的代码产生以下输出 -

拖放输出