2021-05-12 14:32:11
使用 PySimpleGUI 輕鬆為程式和指令碼增加 GUI
五分鐘建立客製化 GUI。
對於 .exe
型別的程式檔案,我們可以通過雙擊滑鼠左鍵開啟;但對於 .py
型別的 Python 程式,幾乎不會有人嘗試同樣的操作。對於一個(非程式設計師型別的)典型使用者,他們雙擊開啟 .exe
檔案時預期彈出一個可以互動的表單。基於 Tkinter,可以通過標準 Python 安裝standard Python installations的方式提供 GUI,但很多程式都不太可能這樣做。
如果開啟 Python 程式並進入 GUI 介面變得如此容易,以至於真正的初學者也可以掌握,會怎樣呢?會有人感興趣並使用嗎?這個問題不好回答,因為直到今天建立自定義 GUI 布局仍不是件容易的事情。
在為程式或指令碼增加 GUI 這件事上,似乎存在能力的“錯配”。(缺乏這方面能力的)真正的初學者被迫只能使用命令列方式,而很多(具備這方面能力的)高階程式設計師卻不願意花時間建立一個 Tkinter GUI。
GUI 框架
Python 的 GUI 框架並不少,其中 Tkinter,wxPython,Qt 和 Kivy 是幾種比較主流的框架。此外,還有不少在上述框架基礎上封裝的簡化框架,例如 EasyGUI,PyGUI 和 Pyforms 等。
但問題在於,對於初學者(這裡是指程式設計經驗不超過 6 個月的使用者)而言,即使是最簡單的主流框架,他們也無從下手;他們也可以選擇封裝過的(簡化)框架,但仍難以甚至無法建立自定義 GUI 布局layout。即便學會了某種(簡化)框架,也需要編寫連篇累牘的程式碼。
PySimpleGUI 嘗試解決上述 GUI 難題,它提供了一種簡單明瞭、易於理解、方便自定義的 GUI 介面。如果使用 PySimpleGUI,很多複雜的 GUI 也僅需不到 20 行程式碼。
秘訣
PySimpleGUI 極為適合初學者的秘訣在於,它已經包含了絕大多數原本需要使用者編寫的程式碼。PySimpleGUI 會處理按鈕回撥callback,無需使用者編寫程式碼。對於初學者,在幾週內掌握函數的概念已經不容易了,要求其理解回撥函數似乎有些強人所難。
在大部分 GUI 框架中,布局 GUI 小部件widgets通常需要寫一些程式碼,每個小部件至少 1-2 行。PySimpleGUI 使用了 “auto-packer” 技術,可以自動建立佈局。因而,布局 GUI 視窗不再需要 pack 或 grid 系統。
(LCTT 譯註:這裡提到的 pack 和 grid 都是 Tkinter 的布局管理器,另外一種叫做 place 。)
最後,PySimpleGUI 框架編寫中有效地利用了 Python 語言特性,降低使用者程式碼量並簡化 GUI 資料返回的方式。在表單form布局中建立小部件時,小部件會被部署到對應的布局中,無需額外的程式碼。
GUI 是什麼?
絕大多數 GUI 只完成一件事情:收集使用者資料並返回。在程式設計師看來,可以歸納為如下的函數呼叫:
button, values = GUI_Display(gui_layout)
絕大多數 GUI 支援的使用者行為包括滑鼠點選(例如,“確認”,“取消”,“儲存”,“是”和“否”等)和內容輸入。GUI 本質上可以歸結為一行程式碼。
這也正是 PySimpleGUI (的簡單 GUI 模式)的工作原理。當執行命令顯示 GUI 後,除非點選滑鼠關閉表單,否則不會執行任何程式碼。
當然還有更複雜的 GUI,其中滑鼠點選後視窗並不關閉;例如,機器人的遠端控制介面,聊天視窗等。這類複雜的表單也可以用 PySimpleGUI 建立。
快速建立 GUI
PySimpleGUI 什麼時候有用呢?顯然,是你需要 GUI 的時候。僅需不超過 5 分鐘,就可以讓你建立並嘗試 GUI。最便捷的 GUI 建立方式就是從 PySimpleGUI 經典範例中拷貝一份程式碼。具體操作流程如下:
- 找到一個與你需求最接近的 GUI
- 從經典範例中拷貝程式碼
- 貼上到 IDE 中並執行
下面我們看一下書中的第一個經典範例recipe:
importPySimpleGUIas sg
#Very basic form. Return values as a list
form = sg.FlexForm('Simple data entry form') #beginwith a blank form
layout =[
[sg.Text('Please enter your Name, Address, Phone')],
[sg.Text('Name',size=(15,1)), sg.InputText('name')],
[sg.Text('Address',size=(15,1)), sg.InputText('address')],
[sg.Text('Phone',size=(15,1)), sg.InputText('phone')],
[sg.Submit(), sg.Cancel()]
]
button, values = form.LayoutAndRead(layout)
print(button, values[0], values[1], values[2])
執行後會開啟一個大小適中的表單。
如果你只是想收集一些字串型別的值,拷貝上述經典範例中的程式碼,稍作修改即可滿足你的需求。
你甚至可以只用 5 行程式碼建立一個自定義 GUI 布局。
importPySimpleGUIas sg
form = sg.FlexForm('My first GUI')
layout =[[sg.Text('Enter your name'), sg.InputText()],
[sg.OK()]]
button,(name,)= form.LayoutAndRead(layout)
5 分鐘內建立一個自定義 GUI
在簡單佈局的基礎上,通過修改經典範例中的程式碼,5 分鐘內即可使用 PySimpleGUI 建立自定義布局。
在 PySimpleGUI 中,小部件widgets被稱為元素elements。元素的名稱與編碼中使用的名稱保持一致。
(LCTT 譯註:Tkinter 中使用小部件這個詞)
核心元素
Text
InputText
Multiline
InputCombo
Listbox
Radio
Checkbox
Spin
Output
SimpleButton
RealtimeButton
ReadFormButton
ProgressBar
Image
Slider
Column
元素簡寫
PySimpleGUI 還包含兩種元素簡寫方式。一種是元素型別名稱簡寫,例如 T
用作 Text
的簡寫;另一種是元素引數被設定了預設值,你可以無需指定所有引數,例如 Submit
按鈕預設的文字就是 “Submit”。
T =Text
Txt=Text
In=InputText
Input=IntputText
Combo=InputCombo
DropDown=InputCombo
Drop=InputCombo
(LCTT 譯註:第一種簡寫就是 Python 類的別名,第二種簡寫是在返回元素物件的 Python 函數定義時指定了引數的預設值)
按鈕簡寫
一些通用按鈕具有簡寫實現,包括:
FolderBrowse
FileBrowse
FileSaveAs
Save
Submit
OK
Ok(LCTT 譯註:這裡`k`是小寫)
Cancel
Quit
Exit
Yes
No
此外,還有通用按鈕功能對應的簡寫:
SimpleButton
ReadFormButton
RealtimeButton
(LCTT 譯註:其實就是返回 Button
類範例的函數)
上面就是 PySimpleGUI 支援的全部元素。如果不在上述列表之中,就不會在你的視窗佈局中生效。
(LCTT 譯註:上述都是 PySimpleGUI 的類名、類別名或返回範例的函數,自然只能使用列表內的。)
GUI 設計模式
對於 GUI 程式,建立並展示視窗的呼叫大同小異,差異在於元素的布局。
設計模式程式碼與上面的例子基本一致,只是移除了布局:
importPySimpleGUIas sg
form = sg.FlexForm('Simple data entry form')
#Define your form here (it's a list of lists)
button, values = form.LayoutAndRead(layout)
(LCTT 譯註:這段程式碼無法執行,只是為了說明每個程式都會用到的設計模式。)
對於絕大多數 GUI,編碼流程如下:
- 建立表單物件
- 以“列表的列表”的形式定義 GUI
- 展示 GUI 並獲取元素的值
上述流程與 PySimpleGUI 設計模式部分的程式碼一一對應。
GUI 布局
要建立自定義 GUI,首先要將表單分割成多個行,因為表單是一行一行定義的。然後,在每一行中從左到右依次放置元素。
我們得到的就是一個“列表的列表”,類似如下:
layout =[ [Text('Row 1')],
[Text('Row 2'),Checkbox('Checkbox 1', OK()),Checkbox('Checkbox 2'), OK()]]
上述布局對應的效果如下:
展示 GUI
當你完成佈局、拷貝完用於建立和展示表單的程式碼後,下一步就是展示表單並收集使用者資料。
下面這行程式碼用於展示表單並返回收集的資料:
button, values = form.LayoutAndRead(layout)
表單返回的結果由兩部分組成:一部分是被點選按鈕的名稱,另一部分是一個列表,包含所有使用者輸入表單的值。
在這個例子中,表單顯示後使用者直接點選 “OK” 按鈕,返回的結果如下:
button =='OK'
values ==[False,False]
Checkbox 型別元素返回 True
或 False
型別的值。由於預設處於未選中狀態,兩個元素的值都是 False
。
顯示元素的值
一旦從 GUI 獲取返回值,檢查返回變數中的值是個不錯的想法。與其使用 print
語句進行列印,我們不妨堅持使用 GUI 並在一個視窗中輸出這些值。
(LCTT 譯註:考慮使用的是 Python 3 版本,print
應該是函數而不是語句。)
在 PySimpleGUI 中,有多種訊息方塊可供選取。傳遞給訊息方塊(函數)的資料會被顯示在訊息方塊中;函數可以接受任意數目的引數,你可以輕鬆的將所有要檢視的變數展示出來。
在 PySimpleGUI 中,最常用的訊息方塊是 MsgBox
。要展示上面例子中的資料,只需編寫一行程式碼:
MsgBox('The GUI returned:', button, values)
整合
好了,你已經了解了基礎知識,讓我們建立一個包含儘可能多 PySimpleGUI 元素的表單吧!此外,為了更好的感觀效果,我們將採用綠色/棕褐色的配色方案。
importPySimpleGUIas sg
sg.ChangeLookAndFeel('GreenTan')
form = sg.FlexForm('Everything bagel', default_element_size=(40,1))
column1 =[[sg.Text('Column 1', background_color='#d3dfda', justification='center',size=(10,1))],
[sg.Spin(values=('Spin Box 1','2','3'), initial_value='Spin Box 1')],
[sg.Spin(values=('Spin Box 1','2','3'), initial_value='Spin Box 2')],
[sg.Spin(values=('Spin Box 1','2','3'), initial_value='Spin Box 3')]]
layout =[
[sg.Text('All graphic widgets in one form!',size=(30,1), font=("Helvetica",25))],
[sg.Text('Here is some text.... and a place to enter text')],
[sg.InputText('This is my text')],
[sg.Checkbox('My first checkbox!'), sg.Checkbox('My second checkbox!',default=True)],
[sg.Radio('My first Radio! ',"RADIO1",default=True), sg.Radio('My second Radio!',"RADIO1")],
[sg.Multiline(default_text='This is the default Text should you decide not to type anything',size=(35,3)),
sg.Multiline(default_text='A second multi-line',size=(35,3))],
[sg.InputCombo(('Combobox 1','Combobox 2'),size=(20,3)),
sg.Slider(range=(1,100), orientation='h',size=(34,20), default_value=85)],
[sg.Listbox(values=('Listbox 1','Listbox 2','Listbox 3'),size=(30,3)),
sg.Slider(range=(1,100), orientation='v',size=(5,20), default_value=25),
sg.Slider(range=(1,100), orientation='v',size=(5,20), default_value=75),
sg.Slider(range=(1,100), orientation='v',size=(5,20), default_value=10),
sg.Column(column1, background_color='#d3dfda')],
[sg.Text('_' *80)],
[sg.Text('Choose A Folder',size=(35,1))],
[sg.Text('Your Folder',size=(15,1), auto_size_text=False, justification='right'),
sg.InputText('Default Folder'), sg.FolderBrowse()],
[sg.Submit(), sg.Cancel()]
]
button, values = form.LayoutAndRead(layout)
sg.MsgBox(button, values)
看上面要寫不少程式碼,但如果你試著直接使用 Tkinter 框架實現同樣的 GUI,你很快就會發現 PySimpleGUI 版本的程式碼是多麼的簡潔。
程式碼的最後一行開啟了一個訊息方塊,效果如下:
訊息方塊函數中的每一個引數的內容都會被列印到單獨的行中。本例的訊息方塊中包含兩行,其中第二行非常長而且包含列表巢狀。
建議花一點時間將上述結果與 GUI 中的元素一一比對,這樣可以更好的理解這些結果是如何產生的。
為你的程式或指令碼新增 GUI
如果你有一個命令列方式使用的指令碼,新增 GUI 不一定意味著完全放棄該指令碼。一種簡單的方案如下:如果指令碼不需要命令列引數,那麼可以直接使用 GUI 呼叫該指令碼;反之,就按原來的方式執行指令碼。
僅需類似如下的邏輯:
if len(sys.argv)==1:
# collect arguments from GUI
else:
# collect arguements from sys.argv
建立並執行 GUI 最便捷的方式就是從 PySimpleGUI 經典範例中拷貝一份程式碼並修改。
快來試試吧!給你一直疲於手動執行的指令碼增加一些趣味。只需 5-10 分鐘即可玩轉範例指令碼。你可能發現一個幾乎滿足你需求的經典範例;如果找不到,也很容易自己編寫一個。即使你真的玩不轉,也只是浪費了 5-10 分鐘而已。
資源
安裝方式
支援 Tkinter 的系統就支援 PySimpleGUI,甚至包括樹莓派Raspberry Pi,但你需要使用 Python 3。
pip install PySimpleGUI
文件
via: https://opensource.com/article/18/8/pysimplegui
作者:Mike Barnett 選題:lujun9972 譯者:pinewall 校對:wxy
Linux公社的RSS地址:https://www.linuxidc.com/rssFeed.aspx
本文永久更新連結地址:https://www.linuxidc.com/Linux/2018-09/154213.htm
相關文章