模組安裝
要使用wxPytho視窗介面, 就要先 import wx, 所以需先安裝wxPython模組, 如下指令
pip install wxPython
基礎架構
wxPython視窗由wx.App, wx.Frame, wx.Panel以及其他widget控制元件組成. 一支視窗程式只能有一個wx.App所產生的物件, 用於執行事件迴圈. 然後可以使用多個wx.Frame所產生的物件作為容器. 每一個frame也至少會有一個panel用來控制佈局的視窗. 其他的widget元件則都擺被在Panel上。
wxWidget使用了物件導向的方式開發了一些便利的方法. 這些方法名稱首字都是大寫, 比如初始化視窗的方法為OnInit(self). 這雖違反了變數命名規則, 不過這也是wxWidget的特性, 必需習慣.
最簡易的方法
首先一定要先建立一個wx.App的物件, 此物件是用來控制視窗內的行程.
接下來產生wx.Frame物件, 此物件是真正的視窗物件, 需傳入父視窗參數. 但wx.Frame已是最上層的視窗, 所以直接傳入None即可. 然後記得要將此物件Show()出來
最後, 進入wx.App的MainLoop()迴圈, 就會開始顯示視窗了. 如果沒有進入迴圈, 視窗就會一閃並立即結束離開, 所以看不到視窗.
import wx app=wx.App() frame=wx.Frame(None) frame.Show() app.MainLoop()
自訂類別寫法
我們通常會客制化視窗的初始狀態. 所以就可以自行定義一個MainFrame類別, 此類別繼承wx.Frame, 然後把要初始化的工作寫在建構子內.
不過記得, 建構子第一行一定要先執行wx.Frame父類別的建構子
此寫法的執行結果, 同上面的圖
import wx
class MainFrame(wx.Frame):
def __init__(self, parent=None):
wx.Frame.__init__(self, parent)
self.Show()
app=wx.App()
frame=MainFrame()
app.MainLoop()
加入Panel
Panel是存放控制元件的Container(容器), 然後再把Panel放入Frame裏頭. 但我們通常會在Panel放入Frame之前, 先設定Frame的Layout管理器(如BoxSizer), 然後再將Panel加入BoxSizer進行管理.
Frame設定Layout管理器
如下代碼, 先產生Layout管理器, 然後用Frame的SetSizer()進行委託管理
self.boxSizer=wx.BoxSizer(wx.VERTICAL)
self.SetSizer(self.boxSizer)
Layout管理器加入成員
先產生Panel物件, 此物件的Parent還是Frame喔. 然後BoxSizer使用Add加入要管理的物件
self.panel=wx.Panel(self) self.panel.SetBackgroundColour("#0000ff") self.boxSizer.Add(self.panel, 1, wx.EXPAND |wx.ALL, 5 )
父子關係
Layout管理器就好比公司的人事單位, 老闆委託人事部門來管理員工(Panel)的薪資. 但員工(Panel)的老闆, 還是Frame
如果還是聽不懂, 就把Layout當成是連長的傳令, 或者是宮廷裏的太監總管. 每個大臣都需聽從皇帝的指示. 但一些鎖碎的事情都是由太監總管來指揮, 所以大臣們也不敢不聽.
Frame裏的物件, 可以使用區域變數, 也可以使用物件變數(前面加self). 但為了日後在其他地方控制這些物件, 習慣中都是使用物件變數
import wx class MainFrame(wx.Frame): def __init__(self, parent=None): wx.Frame.__init__(self, parent) self.boxSizer=wx.BoxSizer(wx.VERTICAL) self.SetSizer(self.boxSizer) self.panel=wx.Panel(self) self.panel.SetBackgroundColour("#0000ff") self.boxSizer.Add(self.panel, 1, wx.EXPAND |wx.ALL, 5 ) self.Show() app=wx.App() frame=MainFrame() app.MainLoop()
通常都是把Panel及其他控制項加入後, 才啟動Frame的Show(). 但如果Frame Show()出來後, 要再度動態的加入其他控制項, 則這些後來加入的控制項並不會依BoxSizer的指示擴展開來, 只是在左上角顯示一下塊區塊而以. 這就好比新進的大臣又不認識太監總管, 所以根本就不鳥這些閹人. 此時Frame(皇帝)只好使用Layout()再度佈局一次, 才會擴展開來
import wx class MainFrame(wx.Frame): def __init__(self, parent=None): wx.Frame.__init__(self, parent) self.Show() #先 show出視窗 self.boxSizer=wx.BoxSizer(wx.VERTICAL) self.SetSizer(self.boxSizer) self.panel=wx.Panel(self) self.panel.SetBackgroundColour("#0000ff") self.boxSizer.Add(self.panel, 1, wx.EXPAND |wx.ALL, 5 ) self.Layout() #動態管理後面加入的控制項 app=wx.App() frame=MainFrame() app.MainLoop()
下圖是沒加入Frame Layout() 的下場
直接繼承App
如果直接繼承wx.App, 則需在OnInit()方法中, 初始化標頭等工作, 最後返回True.
當然, 在主程式裏, 先產生MainWindow物件, 並進入MainLoop迴路.
import wx class MainWindow(wx.App): def OnInit(self): frame=wx.Frame(parent=None, title="AIot Patrol System",style=wx.MAXIMIZE |wx.DEFAULT_FRAME_STYLE) frame.Show() return True MainWindow().MainLoop()