目錄 主要使用wxPython(最成熟的跨平台python GUI工具包) 前戲:基礎了解 WxPython的程式結構 視窗組成: 事件驅動: 常用元件(簡單了解,後面還有): 基本元件 1.靜态文本框 2.文本輸入框 3.按鈕控件 4.單選框 5.多選框 6.清單控件 7.使用sizer布局元件 菜單,視窗,對話框元件 菜單 視窗 對話框 視窗和對話框的互動 進階控件 表格控件 進階清單控件 樹形控件 樹表控件 定時器控件 WxPython庫中的進階功能
主要使用wxPython(最成熟的跨平台python GUI工具包)
前戲:基礎了解

View Code
補充:id是什麼:wxpython對每個控件都會配置設定一個唯一的整數型ID,友善調用,類十餘c中的Handle。ID在時間響應中必不可少。
建立控件時如果ID為-1時,會自動配置設定一個ID。這樣就不能對ID進行引用。其實可以使用控件對象的GetId方法進行擷取
前提: 唯一ID的生成:wx提供了NewId(),可以生成唯一的id。(若擔心重複,可以使用RegisterID檢測)
我們想要使用ID,但是程式中控件太多,如何處理
方法一:前置每個控件的ID(自己設定的名稱),使用清單生成器生成
[Btn_1_ID,Btn_2_ID,Btn_3_ID] = [wx.NewId() for _init_cj in range(3)]有幾個控件就設定循環幾次
然後在生成控件時進行調用
方法二:使用類的屬性來預先配置設定,然後控件類對他進行繼承,每個控件類句讀一個屬于他的id屬性
一個WxPython程式一般包含兩個對象:應用程式對象和根視窗(可多個)。其中,應用程式對象可以使用wx.App(或子類)實作(用于處理視窗中的事件響應),根視窗可以使用wx.Frame實作。

App子類的使用
其中OnInit方法中是必須的,其将會在事件循環處理之前被系統調用。同樣的在事件結束之後調用的方法也存在(OnExit)
兩個方法是相對的。例如:開啟資料庫和斷開資料庫
前面的代碼中視窗和應用程式似乎沒有關聯,為什麼?
在應用程式對象中,可以通過SetTopWindow方法來設定根視窗。若是沒有設定,是因為應用程式會選擇視窗清單中的第一個作為根視窗。上面的程式也隻有一個視窗,是以沒有必要去顯示設定。同樣使用SetTopWindow也可以改變根視窗
控件的部分構造參數:
<col>
參數
說明
parent
父視窗(為None代表為頂級視窗),注意設定父視窗後,在父視窗關閉時,子視窗也會消失
id
上面說過了
title
标題
pos
相對于螢幕的位置預設(-1,-1),自行選擇。我們在上面使用center也可以改變視窗在螢幕中的位置
size
大小預設(-1,-1)視窗系統自行選擇
style
視窗類型...
name
視窗的内在名字
style風格:

所有支援的事件類型(上百個)
一個事件是wx.Event類或其子類的一個執行個體。
事件的綁定和處理:通過使用wx.EvtHandler類中的Bind方法可以将綁定事件的類型,事件對象和事件處理函數關聯起來

def Bind(self, event<事件類型>, handler<處理函數>, source=None<事件的發生者:不寫預設目前控件>, id=-1, id2=-1)

事件綁定和處理的示範

為一個控件綁定多個事件
補充:
方式一:是是由父控件為子控件綁定的事件
方式二:是使用控件自己綁定事件
那麼兩者有何不同,可以混用嗎
答案是:父類去綁定其他事件是不允許的,錯誤的,會導緻父控件為其綁定的所有事件失效。而子類是可以綁定所有的相關事件的。
檢視事件對象:
這一類事件都是對應控件去響應的,也就是說父類中包含這些控件的話,可以對其直接綁定這些基礎事件響應。
是以說:要想使用父控件對子控件綁定事件:事件必須滿足 EVT_控件名 相對應
為同一個控件的同一個事件,綁定兩個(多個)處理函數。
其執行結果是隻執行了事件處理函數2:原因是因為:一般情況下,視窗部件對象在執行完該事件的一個處理函數,就預設完結了。不會再去處理其他相關的函數。而,事件綁定是從上到下,下面的會覆寫上面的,是以,值執行了處理函數了。
我們要想去執行其他函數,那麼就要在正在執行的處理函數後面加上event.Skip(),他會在目前函數傳回一個值後去調用下一個處理函數,改變原來的預設行為。

工具欄
Realize() 方法需要被調用,以最終确定工具欄建立

StaticText和字型的設定Font

文本輸入框TextCtrl的設定size()設定-1代表預設
相關參數:
常用方法:

TextCtrl根據參數設定多行文本框,使用方法設定背景色

普通按鈕Button

位圖按鈕,以及圖檔的轉換
補充:圖檔轉換

RadioButton的使用,以及事件對象擷取GetEventObject,擷取對象标簽GetLabel

RadioBox單選框組的使用,可以為框組設定事件處理,使用self.框組.GetStringSelection擷取label值

CheckBox的使用(全選和反選資料處理)

同樣也有多選清單框CheckListBox

ListBox和CheckListBox控件的使用和事件處理
listbox樣式:

Choice下拉框

可編輯下拉框ComboBox(是Choice的子類,可以使用它的方法)
combobox的樣式:
前面的程式都是通過設定構造函數的pos,size屬性調整控件之間的位置。不太容易掌控位置。wxpython提供了Sizer布局管理器自動設定控件之間的位置。
使用步驟:
建立Sizers布局管理器。布局管理器分為grid sizer, flex grid sizer, grid bag sizer, box sizer,(都是繼承父類Sizer)
調整SetSizer()将布局管理器添加到容器中,這裡的容器一般指視窗,panel面闆等元件。這樣就建立了布局管理器和視窗之間的聯系。
def SetSizer(self, sizer, deleteOld=True)
調用容器的Add()方法将各個元件添加到布局管理器中.
Add(self,item, proportion=0, flag=0, border=0, userData=None)
其中item是添加到布局管理器中的元件,
proportion是表示目前視窗大小發生改變時,控件之間的比例
flag表示視窗風格,對齊方式,邊框等資訊
border邊框大小(前提是flag設定了邊框)
userdata用于傳遞額外的資料
調用容器的Fit()方法計算布局管理器和容器視窗的大小,來自動調整視窗大小,使其适合目前視窗。
Fit(self)
grid sizer布局是采用表格的形式配置設定各種控件,不需要設定控件在容器中的位置,直接添加到grid sizer布局管理器中即可

GridSizer簡單使用
是對grid sizer的改進。可以用于存放大小可以改變的元件。
相對于Grid Sizer而言,他們的差別主要在于:
FlexGridSizer可以設定某一列或行的可變大小。主要在于下面的幾個方法:
其中FlexGridSizer的本身是固定不變的而Grid Sizer是随着視窗的變化,也會改變

FlexGridSizer的使用(不使用專有方法:是不可變的)

GridSizer和上面比較
使用特殊方法,來實作FlexGridSizer的專有屬性

FlexGridSizer中的AddGrowableRow和AddGrowableCol
最後:符合我們所希望的:
這就是FlexGridSizer的特征

全部代碼
比FlexGridSize更加強大,可以是某個空間添加到特定的單元格,可以實作跨行,跨列顯示

GridBagSizer的使用
box sizer是布局管理器中最簡單,最靈活的一種布局,可以水準或垂直排列,是各個元件從左到右或從上到下排列在同一條線上。也可以嵌套使用。水準排列的布局可以嵌套水準或垂直排列的布局。這樣是應用程式的布局更加靈活
補充:對于上面的布局也可以使用
對齊标志
邊界标志:
行為标志:

BoxSizer布局的使用
補充:上面說的proportion比例問題

BoxSizer中;了解proportion
比例隻在box中有效,在其他布局中無效(有表格進行限制,不需要控件比例,但是可以用設定最小大小SetMinSize()來設定大小)
(1)建立菜單欄:調用wx.MenuBar建立菜單欄。
(2)建立父菜單。調用wx.Menu類建立父菜單。
(3)将父菜單添加到菜單欄中。調用菜單欄MenuBar類中的Append方法。
(4)添加子菜單,調用Menu類的Append方法直接添加子菜單
(5)添加菜單事件:wx,EVT_MENU
(6)在視窗中添加上菜單欄:

菜單建立代碼
MenuBar常用方法:
菜單的響應事件(除了上面的wx.EVT_MENU外):

菜單事件響應以及self.GetMenuBar()擷取菜單欄等相關操作

多級菜單設定(一級一級向上添加)
Menu類的常用方法:
使用&來形成快捷鍵
對于父類菜單,一般快捷鍵是展開子菜單,Alt + m展開子菜單,再按下q快捷鍵退出

快捷鍵的定義
助記符在同一個菜單中是唯一的,在整個菜單欄中可以重複

MenuItem建立子菜單,再使用SetBitmap設定圖檔,追加到菜單中即可
也是由Menu類建立的,隻需要在上下文顯示的容器中綁定wx.EVT_CONTEXT_MENU事件,然後又容器元件(如Panel)調用PopupMenu()方法彈出上下文菜單即可

PopupMenu彈出菜單和EVT_CONTEXT_MENU事件
使用者的所有操作都是在視窗中完成的,wxPython使用wx.Frame類建立視窗。Frame類的構造函數:

簡單的Frame視窗

含有工具欄的菜單欄的Frame視窗:CreateToolBar建立工具欄,Realize來顯示。CreateStatusBar建立狀态欄
多文檔程式視窗可以建立子視窗,子視窗有MDI多文檔視窗管理和控制。使用MDIParentFrame建立

MDIParentFrame的使用

多文檔界面建立子視窗MDIChildFrame

MiniFrame預設不帶視窗操作按鈕關閉等)可以設定,而且不會顯示在工作列

Dialog的使用(控件類之間的調用)

MessageDialog提示對話框,注意記得對生成的其他對話框或視窗進行釋放,使用Destroy

TextEntryDialog文本輸入對話框

FileDialog檔案對話框的使用

FontDialog的使用(注意擷取字型時需要先擷取所有字型的資料,再從中擷取選中的字型對象,在進行設定)

視窗互動(Validator資料驗證的使用)
注意:
對話框的元件支援驗證能力,而視窗不支援元件的驗證(不會去自動調用,我們可以自己去調用,但是何必呢)
其中似乎都沒有用到驗證類中的Validate方法(這個才是我們的驗證函數吧),也沒有去自動調用TraFromWindow(不是說在對話框關閉時調用嗎)。都沒有為我們進行調用。那我們是不是可以自己來調用。
在對話框關閉前我們自行調用TraFromWindow方法....(太扯了點....應該如何去正确的使用??)
上面的方法純屬參考。畢竟文檔中說了這些預留方法會自動調用,而我們對validate和transferfromwindow都是自行調用的,不太妥當...
表格控件Grid是wxPython中最複雜的控件之一,表格控件通常用于浏覽資料。這裡介紹表格控件的建立,單元格的設定,表格對象的使用

grid.Grid表格控件的使用
建立步驟:
(1)需要先導入wx.grid包,其中wx.grid包中提供了建立和控制表格的類和方法。
(2)執行個體化表格類
(3)建立表格控件,numRows是行數,numCols是列數
(4)設定行标題和列标題
(5)設定單元格的值
可以定制更加複雜的表格。通過繼承PyGridTableBase類可以實作對表格控件更加複雜的設定。其中繼承PyGridTableBase類必須實作GetNumberRows(),GetNumberCols(),GetValue()和SetValue()這些方法。表格會根據這些方法中(Get開頭的方法中設定的傳回值)的傳回值來預設設定值

GetNumberCols

GetNumberRows

GetValue

SetValue(是用來當使用者設定值時會調用)
都有說:Must be overridden
注意要想設定屬性,先要加上GetAttr()

GridTableBase的使用(設定奇數行顔色為黃色)
注意:table表格是基于表格控件的
注意:設定屬性的時候需要對屬性加一個引用計數
在我們加上引用計數時,每一次擷取都是4(self.evenAttr或self.oddAttr是一次,attr是一個,IncRef增加一次,作為參數傳入sys.getrefcount中産生一次,一個四次)
但是我們每次産生一個表格都會對self.evenAttr或者self.oddAttr進行一次計數增加,那麼為何依舊是4。
因為在對一個單元格設定屬性後,會認為這個值不會再拿去給其他表格使用。是以會在設定屬性後減少一個引用計數,而且GetAttr執行完後attr銷毀,sys,getrefcount結束都會減少一個計數,是以若是我們不進行引用計數增加的話,會在執行一個GetAtrr(){注:這裡有兩個屬性,會執行兩次},該調用的屬性會由于引用計數為0,被銷毀。導緻表格無法生成。
表格控件的單元格可以根據不同的資料需求進行設定。例如:可以把 某個單元格設定為下拉框,複選框,數字選擇等控件。wx.grid包提供了一系列的Editor編輯器,這些編輯器都可以在單元格中實作上面需要的控件。除外單元格還可以對資料的字型,顔色,格式進行設定。

單元格的屬性設定以及插入控件

事件處理
注意事件是綁定在整個表格,而不是某個單元格
ListCtrl是出具顯示的另一種方式。可以提供詳細清單,圖示清單等顯示方式。ListCtrl控件的列對齊,排序等富足功能可以通過繼承wx.lib.mixins.listctrl包的mixin類實作
ListCtrl控件常用清單方式顯示資訊,可以進行排序,位址清單的顯示樣式。建立方式
1直接執行個體化wx.ListCtrl類,然後關聯清單資料。
2自定義清單控件類,繼承wx.ListCtrl或wx.lib.mixins.listctrl包中的mixin類。這些mixin類實作了一些輔助性的功能。例如對齊,排序

清單控件的建立
InseItem是插入一行,預設自己包含一列
參數1:是插入的行的索引,這裡我們設定了為0,那麼意味着每次插入一條資料,都會插入在第一條,形成了倒序排列(一般我們會将這個參數設定為一個大數,因為顯示的時候會去找到第一條資料然後向下顯示《會将空白行跳過》)
參數2:就是我們的為預設的那一列設定的預設值(可以不用設定,因為在後面,我們進行了替換)
清單控件的排序
其中對ListCtrl清單排序的總結不錯。但是使用的是python2版本。我這裡使用python3

清單排序全部代碼
注意點:
1.資料的索引必須以0開始:
因為他會調用函數去操作資料。且從0開始去索引,你的資料中沒有索引0,那麼會報錯
2.需要實作幾個特定方法,當我們使用ColumnSorterMixin時,必須去實作
(1)必須實作GetListCtrl用于傳回建立的清單,因為在進行排序的時候沒需要用到清單,而清單的擷取是調用GetListCtrl擷取
因為MyFrame類繼承了ColumnSorterMixin類,是以必須由他來實作這個方法。此外也是需要他去實作(3)
(2)這個讓我找了半天...先說3
(3)itemDataMap,對其指派(賦予我們添加在清單中的值,帶上是以,友善映射).注意itemDataMap和ListCtrl控件的建立都要在ColunSorterMixin構造函數執行之前完成,不然會報錯
補充(2):他說我們需要去在清單控件類中使用SetItemData去設定一個唯一的值為每一行
那麼檢視定義:
代碼:
SetItemData中的第二個參數data不是我們所定義的資料,而是與資料(itemDataMap)之間的映射。
而這裡itemDataMap我們設定的是data全局變量。他和我們這裡設定給每行的資料是對應的。而我們這裡的index也是從0開始遞增的(預設跳過空行,雖然我們在插入的時候随便設定了一個大數,但是由于前面為空,是以還是從0開始)。是以和資料的索引對上号了。我們就可以将兩個映射都寫為index即可。
注意一點:我們設定的初始排序方法,不能為倒序。若是我們設定的初始排序方式為倒序,那麼在插入每一行時。都會出現:插入的資料傳回的索引都是0(因為插入資料行都會向前出入,我們無法擷取真正的索引,無法與資料建立映射)

AssignImageList和InsertImageStringItem去建立位圖清單
1.使用ImageList對象存儲圖示資源wx.Bitmap對象
2.建立ListCtrl控件,并始終style為wx.LC_ICON
3.調用AssignImageList()方法關聯ImageList對象
4.調用InsertImageStringItem()方法出入清單項,并未圖示設定說明字元串
樹形控件采用分層的方式顯示複雜資料,資料呈現父子結構的關系。(分級)

簡單建立樹形控件
(1)建立TreeCtrl類的執行個體。下面建立了樹形對象tree
(2)調用TreeCtrl類的AddRoot方法添加根節點。并擷取該節點
(3)調用自定義函數去遞歸添加子節點,調用AppendItem(parent,node)為父節點,添加上子節點。
樹形控件的事件主要有節點的選擇時間,展開時間,合并時間等。當樹形控件建立完成後,直接為他綁定相關的事件類型,然後實作相應的處理函數即可。

主要的三個事件觸發
樹表控件:結合了上面的樹形控件和清單控件的風格。既存在父子關系,有可以按照列來顯示資料。具備兩者的屬性和方法。
步驟:
(1)wx.gizmos包中的TreeListCtrl類可以建立樹表控件,是以需要先進行導入
(2)建立TreeListCtrl類的執行個體
(3)可以調用SetImageList()方法設定樹表控件中節點所會需要用到的圖示。
(4)調用AddColumn()方法可以添加列,并設定列名
(5)調用AddRoot()方法添加樹表的根節點。即在第一行第一列中添加根節點
(6)同樣可以為這第一行的其他列設定值(SetItemText中的第一個參數是該行标志)
(7)調用AppendItem()方法在父節點下面在添加子節點。下面在root根節點下面添加子節點
(8)調用SetItemText()方法可以對該子節點的列的内容進行設定
(9)可以調用SetItemImage()方法設定樹節點的展開,合并圖示
執行個體代碼:

樹表控件的簡單實作
定時器控件時非可視化的控件,用于定時器查詢的運作。使用wx.PyTimer,wx.Timer和wx.CallLater類建立定時器控件。定時器類提供了3個主要的方法。Start(mil)方法用于啟動定時器,參數mil表示毫秒。Stop()方法用于通知定時器。Restart()方法用于重新開機定時器,進行新一輪的處理。wx.CallLater類可以向處理程式傳遞參數,并傳回處理程式的計算結果。

定時器實作
1.使用wx.PyTimer定時器會一直進行循環使用start,當然也有其他方法StartOnce隻執行一次。Stop去停止定時器。
2.但是我們使用帶有參數的定時器時:
預設隻會執行一次該定時器,要想繼續執行,我們需要在設定的回調函數中在進行重新開機定時器
執行一次的原因(看源碼):
檢視執行函數:
這是就想到:在構造函數中就停止了定時器,那麼還執不執行定時器了呀?這不是扯淡嗎?
接着向下看:
再停止了自己後,就去調用PyTimer定時器了,我去:原來這個類的作用隻是對PyTimer的擴充,使得函數可以帶上參數了。那麼繼續向下看如何去執行這個帶參數的函數:
大緻思路是使用中間類CallLater去擷取我們的回調函數名和參數。将函數名和參數存放在自己的成員屬性中,然後調用PyTimer類去執行定時器,傳入的執行函數名是中間類CallLater定義的一個無參函數,但是在這個方法中執行了成員屬性中的回調函數,并向其中傳入了參數。
對于一些複雜多樣的格式,我們前面使用的樣式,有點.....。現在我們可以使用wx.html子產品來處理HTML格式的文檔。更加友善

HtmlWindow的簡單使用
需要引入wx.html子產品。使用HtmlWindow類生成一個HTML視窗。可以設定次視窗的内容。但是至少簡單内容。style等樣式css樣式無法使用。

HTML視窗和控件布局結合

LoadPage加載頁面
剪切闆是在各個應用程式中交換資料的一種方式。一個應用程式可以将資料儲存在剪切闆中,另一個應用程式可以從剪切闆中擷取資料、儲存的資料可以是文本,圖像,或者是其他檔案對象。
由于作業系統中的剪切闆是全局性的,即對不同的應用程式都是相同的,是以在wxpython程式中剪切闆對象是一個全局對象。在操作剪切闆之前,需要通過調用Open方法打開次對象,隻有此方法傳回了True之後,才能夠繼續使用剪切闆。這是因為剪切闆是一個全局對象。當其正在被另一個應用程式操作時,我們對剪切闆的使用可能會失效。傳回false。是以需要對傳回值進行檢測。也可以使用IsOpened方法來判斷。記得在操作結束後調用Close方法将其關閉。阻止占用

TheClipboard剪切闆的使用
全部到此結束,若有再會補充,如果想了解程序,線程以及網絡等程式設計在圖形界面的程式設計,可以去試試Qt