大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是wxPython GUI構建工具wxFormBuilder。
一、手工代碼布局GUI界面的煩惱
如果你曾經設計過上位機軟件GUI界面,初始階段一定是純手工代碼布局GUI界面上的各個控件,相信你肯定遇到過如下煩惱:
- 控件類型較難找:UI界面里有很多控件類型,純手工寫代碼需要翻看文檔一個個去查找這些控件的名字與用法。
- 尺寸位置難調整:如果界面上已經布了多個控件,想要整體去調整這些控件的尺寸與位置是一件頭疼的事。
- 效果查看不實時:每新添加一個控件都需要運行才能查看整體效果,如果代碼添加不完善,可能無法運行看不到效果。
二、wxFormBuilder工具背景
在講本文主角wxFormBuilder之前有必要提一下這個軟件的來歷,首先要追述到大名鼎鼎的跨平台GUI庫wxWidgets,這個庫主要是用C++語言實現的;鑒於wxWidgets的流行,Robin Dunn用Python語言對wxWidgets做了一層封裝,封裝后便成了Python版GUI庫wxPython;下面是這兩個GUI庫的官方主頁:
- wxWidgets項目官方主頁: https://www.wxwidgets.org/
- wxPython項目官方主頁: https://www.wxpython.org/
wxWidgets的各種UI控件功能均是通過class來實現的,這個鏈接 http://docs.wxwidgets.org/3.0/page_class_cat.html 列出了wxWidgets里的所有class,wxPython並沒有實現wxWidgets里全部class,但基本實現了大部分常用class,這個鏈接 https://docs.wxpython.org/wx.1moduleindex.html 列出了wxPython里所有的class。
知道了wxPython的class便可以開始設計GUI界面,但手工寫代碼設計界面太繁瑣,因此wxFormBuilder應運而生,這是一款能夠可視化設計界面的工具(並不是唯一工具,還有wxGlade、Boa Constructor等),通過該工具設計GUI界面后可自動生成wxPython代碼,下面是wxFormBuilder的官方主頁:
- wxFormBuilder項目Github: https://github.com/wxFormBuilder/wxFormBuilder
三、wxFormBuilder快速上手
使用wxFormBuilder去設計GUI界面可以不用掌握wxPython里的各個控件class的具體用法,你只需要在wxFormBuilder軟件里添加這些控件即可,下面痞子衡將簡介wxFormBuilder的用法:
3.1軟件界面
安裝好wxFormBuilder軟件之后打開這個軟件,可見到如下界面,界面主要分為四大區:項目區、控件區、編輯區、屬性區。軟件使用起來非常簡單,就是在【控件區】里點擊添加需要的控件,這些控件的效果會在【編輯區】里實時顯示,並在【屬性區】這些控件的屬性,【項目區】用於顯示控件間的層級關系。
3.2基礎布局
讓我們開始創建一個GUI的基礎框架,基礎框架包括:Frame(外圍輪廓)、Sizer(內部控件區)、menubar(頂部菜單欄)、statusBar(底部狀態欄)。
第一步是添加一個Frame,這是GUI的輪廓基礎,其size(default為500; 300)決定了GUI整體界面的大小。

第二步是在Frame下添加一個Sizer,后續所有控件均是放在Sizer里的。關於Sizer部分需要特別說明一下,wxPython提供的Sizer類型有如下七種:wxBoxSizer、wxWrapSizer、wxStaticBoxSizer、wxGridSizer、wxFlexGridSizer、wxGridBagSizer、wxStdDialogButtonSizer,Sizer的樣式決定了后續控件的整體相對位置關系,選定了Sizer即選定了GUI界面樣式。關於這七種Sizer的具體樣式請見 https://docs.wxpython.org/sizers_overview.html#sizers-overview。如果你覺得單個Sizer里的控件布局太單調,你可以嵌套使用Sizer,這是實現GUI界面控件布局多樣化的關鍵。

第三步是在Frame頂部添加一個menubar:

第四步是在Frame底部添加一個statusBar:

3.3多種控件
基礎布局搞定之后,接下來便是在Sizer里添加控件,wxPython支持的控件非常豐富,其中比較常用的是如下幾個:button(按鈕)、staticText(靜態顯示文本框)、textCtrl(輸入輸出文本框)、Choice(復選框)、checkBox(選中框)、slider(滑動條)。前面痞子衡選擇的Sizer是wxBoxSizer,即自上而下布局,因此這些控件在Sizer是自上而下排列的,各個控件的位置后續在屬性里還可以微調,但改變不了自上而下的格局。

3.4控件屬性
添加了所有控件之后,下一步便是分別設置控件的屬性,進一步調整控件。痞子衡以Button屬性為例,痞子衡勾選了如下4項比較重要的屬性設置,分別是name(button在后續python代碼的對象名,一般需要按其功能修改,修改后使得代碼閱讀/修改起來更直觀)、label(button在GUI里顯示的標簽名,此處是MyButton,也需要按其功能修改,方便用戶使用軟件)、size(設置button的尺寸,這個尺寸最大不應超過Sizer尺寸)、flag(調整對齊方式從而調整Button在Sizer里的位置)。另外有一個屬性不得不說,即控件位置pos,在wxFormBuilder里設置這個屬性並不生效,痞子衡猜想可能跟Sizer樣式有關,因為Sizer決定了控件間相對位置關系,因此控件的pos不能隨意設置。

3.5觸發事件
有些控件是需要有響應的,比如Button,在GUI軟件實際使用中,用戶如果按下了Button,應該需要觸發某個任務,任務需要有響應函數,這個響應函數需要在【Events】里設置,Button的響應函數在OnButtonClick里設置,痞子衡在這里指定了響應函數名為showMessage。在wxFormBuilder里我們只需要指定控件響應函數名即可,響應函數的具體功能實現,不屬於wxFormBuilder設計范疇。

3.6生成代碼
當GUI界面布局全部完成之后,需選擇File->Generate Code或F8生成python代碼,需要復制所有的python代碼並保存在單獨的文件里,痞子衡保存在了my_win.py文件里。

可以簡單看一下這個my_win.py里的內容,代碼里首先import了wx庫(即wxPython庫),並定義了名為MyFrame1的class,這個class主要包含兩個函數__init__()和showMessage():__init__()里初始化了各個控件成員self.m_xx,這與我們在wxFormBuilder里添加控件是對應的;showMessage()是Button控件的響應函數,但這個響應函數並沒有任何實質代碼,當然我們可以在這個函數里面實現Button響應功能,但一般不建議直接在wxFormBuilder生成的代碼里添加代碼,因為你可能隨時調整GUI頁面布局,那么main_win.py里的代碼會重新生成,這樣會覆蓋我們自己添加的代碼,導致維護起來比較麻煩。
# -*- coding: utf-8 -*-
###########################################################################
## Python code generated with wxFormBuilder (version Jul 11 2018)
## http://www.wxformbuilder.org/
##
## PLEASE DO *NOT* EDIT THIS FILE!
###########################################################################
import wx
import wx.xrc
###########################################################################
## Class MyFrame1
###########################################################################
class MyFrame1 ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 500,300 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
bSizer1 = wx.BoxSizer( wx.VERTICAL )
self.m_button1 = wx.Button( self, wx.ID_ANY, u"MyButton", wx.Point( -1,-1 ), wx.DefaultSize, 0 )
bSizer1.Add( self.m_button1, 0, wx.ALL, 5 )
self.m_staticText1 = wx.StaticText( self, wx.ID_ANY, u"MyLabel", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText1.Wrap( -1 )
bSizer1.Add( self.m_staticText1, 0, wx.ALL, 5 )
self.m_textCtrl1 = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.Point( -1,-1 ), wx.DefaultSize, 0 )
bSizer1.Add( self.m_textCtrl1, 0, wx.ALL, 5 )
m_choice1Choices = []
self.m_choice1 = wx.Choice( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, m_choice1Choices, 0 )
self.m_choice1.SetSelection( 0 )
bSizer1.Add( self.m_choice1, 0, wx.ALL, 5 )
self.m_checkBox1 = wx.CheckBox( self, wx.ID_ANY, u"Check Me!", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer1.Add( self.m_checkBox1, 0, wx.ALL, 5 )
self.m_slider1 = wx.Slider( self, wx.ID_ANY, 50, 0, 100, wx.DefaultPosition, wx.DefaultSize, wx.SL_HORIZONTAL )
bSizer1.Add( self.m_slider1, 0, wx.ALL, 5 )
self.SetSizer( bSizer1 )
self.Layout()
self.m_menubar1 = wx.MenuBar( 0 )
self.m_menu1 = wx.Menu()
self.m_menuItem1 = wx.MenuItem( self.m_menu1, wx.ID_ANY, u"MyMenuItem", wx.EmptyString, wx.ITEM_NORMAL )
self.m_menu1.Append( self.m_menuItem1 )
self.m_menubar1.Append( self.m_menu1, u"MyMenu" )
self.SetMenuBar( self.m_menubar1 )
self.m_statusBar1 = self.CreateStatusBar( 1, wx.STB_SIZEGRIP, wx.ID_ANY )
self.Centre( wx.BOTH )
# Connect Events
self.m_button1.Bind( wx.EVT_BUTTON, self.showMessage )
def __del__( self ):
pass
# Virtual event handlers, overide them in your derived class
def showMessage( self, event ):
event.Skip()
四、使用wxFormBuilder生成的代碼
前面已經使用wxFormBuilder生成GUI界面類MyFrame1並保存在my_win.py文件中,此時需要創建一個主函數文件去調用MyFrame1,下面是痞子衡創建的main_win.py中的代碼:
import wx
# 導入my_win.py中內容
import my_win
# 創建mainWin類並傳入my_win.MyFrame1
class mainWin(my_win.MyFrame1):
# 實現Button控件的響應函數showMessage
def showMessage(self, event):
self.m_textCtrl1.Clear()
self.m_textCtrl1.SetValue('hello world')
if __name__ == '__main__':
# 下面是使用wxPython的固定用法
app = wx.App()
main_win = mainWin(None)
main_win.Show()
app.MainLoop()
最后讓我們測試一下這個GUI軟件,在命令行下運行main_win.py
PS D:\my_git_repo\> python .\main_win.py
至此,wxPython GUI構建工具wxFormBuilder痞子衡便介紹完畢了,掌聲在哪里~~~
參考資料
歡迎訂閱
文章會同時發布到我的 博客園主頁、CSDN主頁、微信公眾號 平台上。
微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦。

