Wxpython 简明教程

wxPython - Quick Guide

wxPython - Introduction

wxPython 是用于 wxWidgets (用 C++ 编写)的 Python 封装程序,而 wxWidgets 是一个流行的跨平台 GUI 工具包。由 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 - Environment

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 文档还可以从同一页面下载。

Linux

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

sudo apt-get install python-wxgtk3.0

MacOS

适用于 MacOS 的磁盘映像格式的预编译二进制文件可在官方网站的下载页面上获得。

wxPython - Hello World

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

  1. Import wx module.

  2. 定义 Application 类的对象。

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

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

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

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

  7. 进入 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 object 是最常用的顶级窗口。它派生自 wxWindow class 。框架是一个窗口,其大小和位置可以由用户更改。它具有标题栏和控制按钮。如果需要,还可以启用其他组件(如菜单栏、工具栏和状态栏)。wxFrame 窗口可以包含除对话框或其他框架外的任何框架。

wxPython - GUI Builder Tools

通过手动编码创建出色的 GUI 可能很繁琐。一个可视化 GUI 设计器工具总是很方便的。针对 wxPython 的许多 GUI 开发 IDE 都可用。下面是其中一些 −

  1. wxFormBuilder

  2. wxDesigner

  3. wxGlade

  4. BoaConstructor

  5. gui2py

wxFormBuilder 是一个开源、跨平台的所见即所得 (WYSIWYG) GUI 构建器,可以将 wxWidget GUI 设计转换为 C++、Python、PHP 或 XML 格式。此处给出了有关 wxFormBuilder 用法的简要介绍。

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

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

object properties

然后,从组件选板的“Forms”选项卡,选择 Frame。

frame

从“Layouts”选项卡添加垂直的 wxBoxSizer。

wxboxsizer

在 Box 中添加带有合适标题的必要控件。在此,添加了一个 StaticText(标签)、两个 TextCtrl 对象(文本框)和一个 wxButton 对象。框架类似于以下图片:

add controls

对这三个控件启用“Expand and Stretch”。在 wxButton 对象的对象属性中,为 OnButtonClick 事件指定一个函数 findsquare()。

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

上述代码生成以下输出 -

tools output

wxPython - Major Classes

原始的 wxWidgets(用 C 语言编写)是一个庞大的类库。此库中的 GUI 类已通过 wxPython 模块移植到 Python,该模块尝试尽可能镜像原始 wxWidgets 库。因此,wxPython 中的 wx.Frame 类的作用与 C 版本中的 wxFrame 类非常相似。

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

wxwindow class hierarchy
wxgdiobject class hierarchy
wxsizer class hierarchy
wxbutton class hierarchy

S.N.

Classes & Description

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 Class 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 - Event Handling

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

在应用程序运行时发生的事件相关的数据存储为从 wx.Event 派生的子类的对象。显示控件(例如按钮)是特定类型事件的源并生成与之关联的Event类对象。例如,单击按钮会发出wx.CommandEvent。此事件数据将调度给程序中的事件处理程序方法。wxPython具有许多预定义的事件绑定程序。一个 Event binder 将特定小部件(控件)、其关联的事件类型以及事件处理程序方法之间的关系封装起来。

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

self.b1.Bind(EVT_BUTTON, OnClick)

Bind() method 由 wx.EvtHandler 类中的所有显示对象继承。此处 EVT_.BUTTON 是关联按钮点击事件至 OnClick() 方法的绑定器。

Example

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

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 继承的一些子类在下表中列出 −

S.N.

Events & Description

1

wxKeyEvent 当按下或释放一个键时发生

2

wxPaintEvent 当需要重新绘制窗口内容时生成

3

wxMouseEvent 包含任何鼠标活动(如按住或拖动鼠标按钮)产生的事件数据

4

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

5

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

6

wxMenuEvent 不同菜单相关事件(排除菜单命令按钮点击)

7

wxColourPickerEvent wxColourPickerCtrl generated events

8

wxDirFilePickerEvent FileDialog 和 DirDialog 生成的事件

WxPython 中的事件有两种类型:基本事件和命令事件。基本事件只存在于其源头的窗口中。大多数 wxWidget 会生成命令事件。一个 command event 可以传播到位于类层次结构中源窗口之上的窗口。

Example

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

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 - Layout Management

可以通过指定 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()

然而,这个 Absolute Positioning 由于以下原因不可行 −

  1. 即使调整了窗口的大小,小组件的位置也不会改变。

  2. 在具有不同分辨率的不同显示设备上,外观可能不统一。

  3. 布局中的修改比较困难,因为它可能需要重新设计整个表单。

wxPython API 提供了 Layout 类来更优雅地管理容器中组件的位置。布局管理器在绝对定位方面有以下优点 −

  1. 窗口中的小组件自动调整大小。

  2. 确保在不同分辨率的显示设备上一致的外观。

  3. 动态地增加或删除组件而不必重新设计。

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

S.N.

Sizers & Description

1

BoxSizer 此 sizer 允许按行或按列排列控件。BoxSizer 的布局由其方向参数(wxVERTICAL 或 wxHORIZONTAL)决定。

2

GridSizer 如其名称所示,GridSizer 对象呈现一个二维网格。控件在网格槽中从左到右、从上到下添加。

3

FlexiGridSizer 此 sizer 也有一个二维网格。但是,它在单元格中布局控件时提供了一些灵活性。

4

GridBagSizer GridBagSizer 是一款通用 sizer。它提供了比 FlexiGridSizer 更丰富的功能。子组件可被添加到网格中的特定单元格。

5

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

wxPython - Buttons

按钮组件在任何 GUI 界面中都使用最广泛。它捕获用户生成的单击事件。它最明显的使用是触发绑定到它的一个处理程序函数。

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

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

wx.Button 类和 wx.ToggleButton 类的构造函数接收以下参数 −

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

以下是 wx.Button 类的一些重要方法 −

S.N.

Methods & Description

1

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

2

GetLabel() Returns the button’s caption

3

SetDefault() 为顶级窗口设置默认按钮。在按下 Enter 键时模拟单击事件

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

S.N.

Methods & Description

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

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

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

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)

Note ——由于 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()

上述代码生成以下输出 -

buttons output

按下按钮的标签 = 单击我

切换按钮状态关闭

切换按钮状态开启

按下按钮的标签 = 新建

按下按钮的标签 = 打开

按下按钮的标签 = 保存

wxPython - Dockable Windows

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 的以下参数:

  1. Direction − 顶部、底部、左侧、右侧或中心

  2. Position − 可以在一个可停靠区域内放置多个面板。每个面板均赋予一个位置号。

  3. Row − 多个面板显示在同一行中。就像在同一行中显示多个工具栏。

  4. Layer − 可以将面板放置在图层中。

使用此 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 - Multiple Document Interface

典型的 GUI 应用程序可能有多个窗口。标签式和小部件可随时激活一个这样的窗口。但是,很多时候此方法可能没有用,因为其他窗口的视图被隐藏了。

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

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

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

Example

以下示例说明了 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 - Drawing API

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

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

  1. wx.ScreenDC - 使用此类在屏幕上作画,而不是在单个窗口上作画。

  2. wx.ClientDC - 使用此类在窗口的客户端区域(没有边框和其他装饰的部分)作画,但不要在 wxPaintEvent 内使用它。

  3. wx.PaintDC - 使用此类在窗口的客户端区域作画,但只能在 wxPaintEvent 内使用。

  4. wx.WindowDC - 使用此类在窗口的整个区域作画,包括装饰。在非 Windows 平台上可能不可用。

wxPython 绘图 API 提供用于绘制形状、文本和图像的不同函数。用于绘制目的的对象(比如颜色、笔、画笔和字体)也可以使用 GDI 类进行构建。

wx.Colour Class

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

  1. wxBLACK

  2. wxBLUE

  3. wxCYAN

  4. wxGREEN

  5. wxYELLOW

  6. wxLIGHT_GREY

  7. wxRED

  8. wxWHITE

以 RGB 值自定义组合形成颜色 为 wx.Colour object

wx.Colour(r,g,b)

wx.Pen Class

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

Predefined Pen objects 为:

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

Predefined Pen styles 为:

wx.SOLID

wx.DOT

wx.LONG_DASH

wx.SHORT_DASH

wx.DOT_DASH

wx.TRANSPARENT

wx.Brush Class

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

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

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 具有很多便于绘制不同形状、文本和图像的函数。

S.N.

Functions & Description

1

DrawRectangle() 绘制给定尺寸的矩形

2

DrawCircle() 在给定点以中心和半径绘制圆形

3

DrawEllipse() 使用给定的 x 和 y 半径绘制椭圆

4

DrawLine() 在两个 wx.Point 对象之间绘制线

5

DrawBitmap() 在给定位置绘制图像

6

DrawText() 在指定位置显示给定文本

Example

上述函数在以下示例中实现,利用了 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 - Drag & Drop

提供 drag and drop 对于用户而言非常直观。它会在很多桌面应用程序中找到,用户只需使用鼠标拖放就能从一个窗口复制或移动对象到另一个窗口。

拖放操作涉及以下步骤:

  1. Declare a drop target

  2. Create data object

  3. Create wx.DropSource

  4. Execute drag operation

  5. Cancel or accept drop

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

  1. wx.TextDropTarget

  2. wx.FileDropTarget

许多 wxPython 小组件支持拖放活动。源控件必须启用拖放,而目标控件必须处于可接受(或拒绝)拖拽的位置。

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

Example

在下面的示例中,两个 ListCrl 对象被水平放置在一个框 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