2.1 设计GUI之PySimpleGUI的基础教程

学习资源Trinket: PySimpleGUI Program

PySimpleGUI 是一个十分 Pythonic 的 GUI 框架。为了叙述方便将 PySimpleGUI 简记为 sg,窗口(Window)主题有超过 100 个可供选择,您可以使用函数 sg.preview_all_look_and_feel_themes() 查看所有主题。切换主题需要使用回调函数 sg.change_look_and_feel("主题名称")

import PySimpleGUI as sg

# 变换主题
sg.change_look_and_feel('Material1')

下面将讨论 PySimpleGUI 的几个核心组件,虽然每个组件的参数可能很多,但是我们只需要了解其核心参数即可,所以,下面的介绍仅仅列出函数的核心参数,比如像 sg.Window(title, layout, size=(5, 1)) 这种形式。

1 sg.Popup 设计 I/O

sg.Popupprint 相当(用于输出(Output)),它创建了一个支持任意数量的任意 Python 支持的数据类型作为参数输入的 Window。变体有:sg.PopupOKsg.PopupOKCancelsg.PopupCancelsg.PopupErrorsg.PopupAutoClosesg.PopupYesNosg.PopupTimed

关于输入(Input)可以使用 sg.PopupGetTextsg.PopupGetFilesg.PopupGetFolder 获取用户的文本,文件,文件夹输入。

2 sg.Window 创建窗口

GUI 的设计目标一般都需要有一个用于和用户进行交互的窗口(Window)界面,为此 PySimpleGUI 提供 sg.Window 类创建窗口。使用方法:sg.Window(title, layout) ,其中 title 表示窗口的标题,layout 指定窗口的布局。

图1 一个简单的 Window 布局

图1 提供了一个自定义 Window 布局以及如何使用其与用户交互的例子。下面对图1 的代码进行拆解。第 7~9 行定义了 Window 的布局,第 12 行定义了一个 Window,第 14~23 行定义了 Window 的交互方法,第 24 行将 Window 关闭以释放资源。其中 sg.Textsg.T == sg.Text == sg.Txt)会将字符串打印到 Window,sg.Inputsg.I == sg.InputText == sg.Input == sg.In)用于获取用户的输入,sg.Button(sg.B == sg.Button)表示 Window 的按钮。下面看看 Window.Read 的输出:

图2 测试 Window.Read 的输出

从图2 可以看出 values 是关键字为数字序号的 dict,而 event 一般代表 Window 的按钮。然而,若 Window 中的 sg.Input 很多,我们仅仅依靠数字序号将十分不方便,为此我们需要传入 key 修改 dict 的关键字。具体实现见图3。

图3 修改 sg.In 的关键字

接下来您便可以使用关键字获取对应的表单数据。

3 在窗口显示用户输入

窗口 sg.Window 的元素可以通过类似于 dict 的方式进行更新及获取:

图4 在窗口显示用户输入

图4 显示了 sg.Window元素(也可称为“小部件”,“组件”)可以通过关键字(即 -OUTPUT-)获取,使用 update 方法更新。

这里的sg.Window元素,即:

IN = window['-IN-']
IN

显示为:

<PySimpleGUI.PySimpleGUI.InputText at 0x20d358068c8>

获取该元素的值:

IN.get()

显示结果为:

'平安是福'

4 创建 To Do List

下面我们创建 To Do 表单:

图5 创建 To Do List

图5 中 出现了复选项 sg.CBox,它的返回值是 True 或者 False,而 window.save_to_disk('ToDoList.out') 将 Window 的配置保存在磁盘,window.load_from_disk('ToDoList.out') 载入磁盘保存的 Window 配置。

5 创建菜单栏

先上代码:

import PySimpleGUI as sg

# ------ Menu Definition ------ #
menu_def = [['&File', ['&Open', '&Save', 'E&xit', 'Properties']],
            ['&Edit', ['Paste', ['Special', 'Normal', ], 'Undo'], ],
            ['&Help', '&About...']]

relief_list = [sg.RELIEF_RAISED, sg.RELIEF_SUNKEN, sg.RELIEF_FLAT, 
               sg.RELIEF_RIDGE, sg.RELIEF_GROOVE, sg.RELIEF_SOLID]

def layout_relief(element):
    return sg.Text(element,
                   size=(30, 1), justification='center', 
                   font=("Helvetica", 25), relief=element)
    

layout = [[sg.Menu(menu_def, tearoff=True)]]
layout += [[layout_relief(element)] for element in relief_list]

window = sg.Window('Everything bagel', layout, default_element_size=(40, 1), grab_anywhere=False)
event, values = window.read()
window.close()

menu_def 定义了多级菜单栏,relief_list 展示了文本显示的样式,sg.Text 的参数 size=(30, 1) 表示文本框是宽30个字符,高1个字符。具体效果见图6:

图6 创建多级菜单栏

6 方法名称简写

  1. 下拉列表:Combo == InputCombo == DropDown == Drop
  2. 文本输入:InputText == Input == In
  3. 复选框:CBox == CB == Check
  4. 按钮:Button== ReadButton == RButton == ReadFormButton
  5. 多行文本框:Multiline == MLine

7 “选择器” 按钮

“选择器” 按钮("Chooser" Buttons)会弹出一个对话框用于选择 filename, date, color 等等。这些按钮直接可以通过名称便可以知道其代表的含义,即 FileBrowse, FolderBrowse, FileSaveAs , FilesSaveAs, CalendarButton, ColorChooserButton。比如使用 FolderBrowse 打开文件夹并将文件夹名称传递给 sg.In,效果图见图7:

图7 打开文件夹并将文件夹名称传递给 `sg.In`

也可以自定义按钮:layout = [[sg.Button('My Button', key='_BUTTON_KEY_')]]

8 其他方法简介

  1. Listbox 示例:layout = [[sg.Listbox(values=['Listbox 1', 'Listbox 2', 'Listbox 3'], size=(30, 6))]],效果见图8:
图8 Listbox + 带表头的表格
  1. 多行文本输入输出:sg.Multiline,效果见图9:
图9 多行输入输出
  1. Slider(滑动条)sg.Slider,效果见图10:
图10 滑块
  1. 单选 sg.Radio 与多选 sg.Checkbox,具体效果见图11:
图11 单选与复选项

需要注意的是 sg.Radio 的第2个参数是用来标识此选项是否归属于指定的 ID

  1. 上/下微调控件(An up/down spinner control)sg.Spin,效果图见图12:
图12 上/下微调控件
  1. Progress Meter
import PySimpleGUI as sg

# layout the window
layout = [[sg.Text('A custom progress meter')],
          [sg.ProgressBar(1000, orientation='h', size=(20, 20), key='progressbar')],
          [sg.Cancel()]]

# create the window`
window = sg.Window('Custom Progress Meter', layout)
progress_bar = window['progressbar']
# loop that would normally do something useful
for i in range(1000):
    # check to see if the cancel button was clicked and exit loop if clicked
    event, values = window.read(timeout=10)
    if event in ['Cancel', None]:
        break
  # update bar with loop value +1 so that bar eventually reaches the maximum
    progress_bar.UpdateBar(i + 1)
# done with loop... need to destroy the window as it's still open
window.close()

效果图见图13:

图13 进度条

7 Column

import PySimpleGUI as sg

# Demo of how columns work
# window has on row 1 a vertical slider followed by a COLUMN with 7 rows
# Prior to the Column element, this layout was not possible
# Columns layouts look identical to window layouts, they are a list of lists of elements.

window = sg.Window('Columns')                                   # blank window

# Column layout
col = [[sg.Text('col Row 1')],
       [sg.Text('col Row 2'), sg.Input('col input 1')],
       [sg.Text('col Row 3'), sg.Input('col input 2')],
       [sg.Text('col Row 4'), sg.Input('col input 3')],
       [sg.Text('col Row 5'), sg.Input('col input 4')],
       [sg.Text('col Row 6'), sg.Input('col input 5')],
       [sg.Text('col Row 7'), sg.Input('col input 6')]]

layout = [[sg.Slider(range=(1,100), default_value=10, 
             orientation='v', size=(8,20)), sg.Column(col)],
          [sg.In('Last input')],
          [sg.OK()]]

# Display the window and get values

window = sg.Window('Compact 1-line window with column', layout)
event, values = window.read()
window.Close()

sg.Popup(event, values, line_width=200)

显示效果见图14:

图14 数据列
  1. 运行 sg.main() 有惊喜,截图见图15:
图15 sg.main
  1. 创建一个控制面板(资料来源:)

代码(图片被转换为了Base64字符):

import PySimpleGUI as sg

"""
    Creates a grid of buttons include of a column for scrolling
    This window looks much like a control panel
    
    NOTE - The SCROLLING using the mousewheel is known to have a bug in the tkinter port.  You will need to have your mouse over the scrollbar to scroll with the mousewheel
"""

def GraphicButton(text:str, key:str, image_data):
    text = text.replace('_', ' ')
    button = sg.Button('', image_data=image_data, button_color=('white', '#9FB8AD'), font='Any 15', key=key, border_width=0)
    text = sg.Text(text, font='Any 10', size=(15,1), justification='center',)
    return sg.Column([[button],[text]], element_justification='c')

def main():
    sg.ChangeLookAndFeel('GreenTan')

    layout  = [ [sg.Text('Control Panel. Click Abort to exit.')]]
    layout += [[sg.Column([[GraphicButton(png_names[i+j*5], png_names[i+j*5] , png_images[i+j*5]) for i in range(2)] for j in range(7)], scrollable=True, size=(400,400))]]

    window = sg.Window('Control Panel', layout, font='any 15', finalize=True)
    while True:                               # ---===--- The event loop --- #
        event, values = window.read()
        print(event)
        if event in ('Exit','Abort', None):   # Exit button or X
            break
    window.close()


Abort = b"..."
...
vars = dir()
png_images = []
png_names = []
for var in vars:
    png_images.append(eval(var))
    png_names.append(var)

main()

显示效果图见图16:

图16 控制面板
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351