PySimpleGUI:快速开始

好,我们的第一个 GUI 程序用大家一般在 Python 学习阶段都用过的一个简单的模拟登录。

  • 预设账号和密码
  • 输入账号
  • 输入密码
  • 点击提交
  • 判断账号和密码是否匹配,都匹配则返回登录成功,否则登录失败。

基本逻辑如下:

user = input('请输入账号:')
password = input('请输入密码:')
if user == 'admin' and password == '123':
	print('登录成功!')
else:
	print('登录失败!')

相信很多同学都在控制台上做过这个练习。接下来呢,我们用 GUI 实现。

写一个 GUI 程序有以下步骤:

  1. 理清楚需求
  2. 画出原型图
  3. 分解原型图中的元素,构造布局生成窗口
  4. 获取窗口事件和数据
  5. 运行事件和数据处理逻辑
  6. 反馈结果
  7. 重复 4~6 直到点击退出
  8. 退出并销毁窗口

定义需求

定义需求:
用户在界面上输入账号和密码,当点击提交时判断账号和密码是否匹配,匹配则弹出登录成功,失败则弹出红字标识的登录失败。

画原型图

好,接下来我们画一个原型图,画原型图大家可以使用一些需求工具:

  • Axure:很强大的原型图工具,但是用起来学习成本也比较高
  • Balsamiq Mockups:草图工具,需要购买才能使用
  • MockPlus:国产的原型图工具,画原型图免费,但是要导出需要收费

还有其他很多相关的原型图工具,请大家自行下载,当然你也可以直接在纸上画:

丑是丑了点,意思到了就行。简单的我们就直接画了,如果复杂的界面还是需要借助工具。

分解原型图并构建布局

我们来看一下原型图中可能会用到的界面元素(也有地方叫做控件、部件、组件等,我们这里统一叫做元素好了)。

  1. 窗口标题,还有窗口上的 -缩小、适应屏幕、x关闭。除了标题,其他自动构建;
  2. 账号输入框,这里有两个元素:一个文本,显示字符串“账号”,一个输入框
  3. 密码输入框,这里也有两个元素:一个文本,显示字符串“密码”,一个密码输入框
  4. 一个提交按钮
  5. 两个弹出窗口,一个弹出“登录成功”,另一个弹出红色文字的“登录失败”。

在PySimpleGUI 中布局是按行来处理的。每个元素都处于布局中的某一行。其中第 1 点中的标题栏不属于布局中的内容,第 5 点的弹出窗口属于特殊元素,不用加入布局。

我们来看看在 PySimpleGUI 中如何通过行来管理的:

  • 整个布局是一个大的列表list
  • 每一行是这个大列表中的子列表;
  • 每一行中的元素是这个列表的元素。

比如第 2 点的账号输入框,有两个元素,我们需要构建一个列表:

[文本, 输入框]

整个布局应该是这样:

[
	[文本, 输入框],
	[文本, 输入框],
	[按钮]
]

如果更复杂的布局,就在这个列表中添加,比如你想在账号输入框后面添加一个复选框 checkbox 用来勾选是否保存账号,那么布局会变成这样:

[
	[文本, 输入框, 复选框],
	[文本, 输入框],
	[按钮]
]

是不是很简单?

好了,我们还是回到我们这个小程序。

这里我们用到了三个元素,文本、输入框和按钮:

  • 文本: Text 或者 T,它接收的第一个参数是要显示的文本;
  • 输入框:InputText 或 Input 或 In,可以不用输入参数,是用来接收输入的单行文本。如果要用作密码输入框,那么用password_char参数来指定替换的字符串,比如你要用*作为屏蔽字符,就写为password_char='*'
  • 按钮: Button 或 Btn 或 B,接收的第一个参数是按钮显示的文本。

这里我们可以看到作者给出了很多简写,方便你使用但其实也增加了一些记忆负担,你可以在可读性的基础上记住其中一个就行。

好,那么接下来,我们就把这些元素替换到我们布局的列表中去:

import PySimpleGUI as sg # 引入PySimpleGUI,注意大小写

# 创建布局
layout = [
    [sg.Text('账号'), sg.Input(key='_USER_')],
    [sg.Text('密码'), sg.Input(password_char='*', key='_PWD_')],
    [sg.Btn('提交', key='_LOGIN_')]
]

这里的一些元素加上了 key 参数,这有什么用?是不是都要加?

key有什么用? key 参数主要用于后面接收事件和获取用户输入。
是不是都要加? 像文本元素这种后续基本不会再处理的,可以不加。但是后续你如果要接收它的事件(比如按钮被点击),获取用户输入(输入框中录入的数据),改变元素(比如某种情况触发需要改变字体颜色等),那么这些被操作的元素一定要用 key 参数指定一个唯一的标识。
如何加? 作者建议,使用大写字母,前后加下划线的方式增加标识的可读性和可识别性。

好了,一个布局就生成了,是不是很简单。

接下来把布局列表作为参数传入窗口实例就可以了:

# 创建窗口,生成窗口实例
window = sg.Window('登录', layout=layout, finalize=True)

Window 第一个参数是窗口标题,第二个参数我们传入了前面定义的布局列表,第三个参数finalize不是必须的,用来定型窗口,这主要有一些操作必须在窗口定型后才能执行。

接下来你运行一下就可以看到一个窗口闪了一下。

《震惊!这样写代码居然会让窗口闪一下就没了!》

好吧,如果你不加 finalize 参数,甚至闪都不会闪。我们还是把过程写完吧,这本来就是半成品。

事件循环

事件循环包含三个我们需要处理的过程:

  • 获取窗口事件和数据
  • 运行事件和数据处理逻辑
  • 反馈结果

为什么要用循环?任何 GUI 窗口都是利用循环机制,不断循环接收用户输入和用户操作事件,然后处理,直到用户点击退出为止。如果不循环,窗口运行一次就会关闭。

在循环过程中,我们需要使用 WindowRead 方法来接收用户的事件和输入数据:

event, value =  window.Read()  
# event, value 的值分别是 _LOGIN_ {'_USER_': 'admin', '_PWD_': '123'}

返回的第一个值 event,其结果是接收界面的事件,这里是接收按钮点击事件。如果按钮被点击,event 的值将是被点击元素的 key 参数设置的标识符,比如我们这里的提交按钮的 key 设置为 _LOGIN_,那么当提交按钮被点击时,event 的值就是 _LOGIN_

如果没有设置 key,event 的值将会是按钮文本,那这里就会是中文的提交

第二个返回值是 value,这是一个以字典形式记录接收到界面上的用户输入。我们之前在元素中设置的 key 参数将作为字典的键,比如_USER__PWD_,可以通过这些 key 来取对应的输入值。

如果你没有为输入元素设置 key,那么字典的键为按照元素在 layout 中的顺序,用下标 0, 1, 2… 来记录用户输入的值。你就需要用下标按顺序去读取,如果元素很多的情况下,你很难保证正确性,因此我 建议一定要在元素定义的时候加上 key 参数,并且为元素设置一个唯一的标识。

好了,接下来我们就对事件进行处理。

if event == '_LOGIN_':  # 当获取到事件是提交按钮被点击时,处理账号密码判断
    user = value['_USER_']   # 从返回值字典中提取账号输入框的值
    password = value['_PWD_'] # 从返回值字典中提取密码输入框的值
    if user == 'admin' and password == '123':
        sg.popup('登录成功!')  # 弹出框
    else:
        sg.popup('登录失败!', text_color='red')  # 弹出框的字体设置为红色

popup() 是 PySimpleGUI 中提供的弹出框,用text_color参数设置字体颜色。

如果你用的是 Pycharm,直接 Ctrl+鼠标悬停 在类名、函数名上都会看到其参数及返回值。你在调用时,也可以看到有哪些参数,大部分参数命名都能见名知义,用的时候多留心。大致你想要的绝大部分功能都能实现。

代码敲完,运行一下,是不是就可以进行输入了。但是输入一次窗口就关闭了,因为上面说过,窗口值运行一次就结束。要想持续保持窗口运行状态就需要加入循环,在特定情况(比如右上角的x和定义的元素事件)下退出循环,关闭窗口。

while True:  # 设置一个循环
	# 在特定条件下
	break

那么什么特定条件下退出呢?比如某个按钮被点击或者右上角的x被点击。特定按钮(比如界面上定义了一个按钮,其 key 为 _EXIT_)的话,你直接写为:

while True:
	if event == '_EXIT_':
		break

对于右上角的x被点击,window.Read() 会接收到一个事件None。对,没错就是你熟悉的那个 None。那我们要响应右上角的x退出怎么写呢?

while True:
	if event is None:
		break

或者你想两个地方(退出按钮被点击,右上角x被点击)接收到事件都退出,那么写为:

while True:
	if event in ['_EXIT_', None]:
		break

然后在循环退出后,销毁窗口。

其实你也发现了,就算我们不做任何处理,窗口也会自动关闭。为什么还要多写一句呢?这是因为在某些系统中会出现异常,因此保持良好的习惯,在循环后加上退出代码。

window.close()

是不是比你用 input 写命令行复杂不了多少呢?

这里获取本节完整代码。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值