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
廣告