Python实践之用PySimpleGUI库开发可视化界面

  • Post author:
  • Post category:python


作 者:高 亮

更新时间:2021年4月21日

更新说明:后续会陆续将一些实测例子更新到本文档,请大家注意文档更新时间的变化。



图形化界面开发中要解决的共同问题


  • 无论用什么编程语言来开发图形化界面,都要解决一些极为关键的问题

  • 问题1:如何创建一个窗口?如何关闭窗口?

  • 问题2:如何在窗口中放其他组件?比如文本框、按钮等

  • 问题3:如何得到窗口内组件与用户交互的数据?

  • 问题4:如何将处理过程中、过程后的数据更新到窗口内的组件上?

注:带着上述的问题,我们将结合具体的组件来学习PySimpleGUI库,这样会让我们知道自己在干什么,有一个清晰的思路



安装库

本人在windows系统下的CMD中进行安装,其他系统请参考其他教程。

pip install pysimplegui



官方说明书

最好的教程是官方的说明书,这里给出官方说明文档的地址


单击进入官方文档网址



在实践中学习

本文的所有示例代码皆为作者个人编辑和整理,欢迎大家转发分享但请注明出处,对于较大的例子我会将其单独整理为代码文件上传到资源区,文中也将只贴出部分重要的代码,但会在对应位置贴出下载链接。



1. 窗口类型

  1. 短暂性窗口:弹出一个窗口,收集到用户的指令信息后就关掉了
  2. 持续性窗口:窗口一直存在,用户点击关闭才关掉。可以循环读取和处理用户的交互事件

注:这部分的示例代码暂时无需弄懂语法,看到结果的不同就可以了,具体的组件使用后续会详细说明



短暂性窗口

  • 功能:短暂性窗口的使用,点击提交按钮后,用户在输入框中输入的内容被弹出
# 导入库
import PySimpleGUI as sg      

# 用列表设置窗口布局
layout = [[sg.Text('短暂性窗口.')],      
                 [sg.InputText()],      
                 [sg.Submit(), sg.Cancel()]]      
                 
# 创建主窗口
window = sg.Window('Window Title', layout)    

# 读取主窗口的事件和返回值
event, values = window.read()    
# 关闭主窗口
window.close()

text_input = values[0]    # 获取输入框的值
# 弹出输入的内容
sg.popup('你输入的内容是:', text_input)

在这里插入图片描述

在这里插入图片描述



持续性窗口

  • 功能:持续显示一个窗口,用户点击关闭才退出
import PySimpleGUI as sg      

sg.theme('DarkAmber')    # Keep things interesting for your users

layout = [[sg.Text('持续性窗口')],
          [sg.Input(key='-IN-')],
          [sg.Button('提交'), sg.Exit('退出')]]

window = sg.Window('持续性窗口示例', layout)

# 循环刷新窗口并处理事件
while True:
	# 读取事件和输入型组件的返回值
	event, values = window.read()
	print(event, values)
	# 点击关闭窗口,退出循环
	if event == '提交':
		text = values['-IN-']
		sg.popup(text)
	if event == sg.WIN_CLOSED or event == '退出':
		break

# 关闭窗口
window.close()

在这里插入图片描述



2. 简单的聊天窗口

  • 在这部分内容中,我们将致力于实现一个持续性窗口。窗口中有按钮和文本框两个组件。
  • 功能:用按钮来控制文本框内容,点击按钮,将输入框的内容添加到文本框。
# 导入库
import PySimpleGUI as sg

# 添加窗口内的组件,以列表形式封装
# 将窗口分成不同行不同列,一个列表是一行,行内的列表是列
layout = [
		# 第1行,里面有2列,分别是文本框和按钮组件
		[sg.Text('聊天文本:'), sg.Button('清空聊天记录')],
		# 第2行,里面有1列,文本框组件,设置了大小、背景色、文本色
		[sg.Text('', key='-TEXT-', size=(50, 5), background_color='white', text_color='red')],
		# 第3行,行内有2列,文本框、输入框和按钮,设置了输入框的关键字、大小
		[sg.T('输入框:'), sg.Input(key='-IN-', size=(40, 2)), sg.Button('发送')]
	]
# 创建主窗口,设置窗口名,给窗口传入layout指明的组件
window = sg.Window('模拟聊天窗口', layout)
text = ''
# 循环刷新窗口并处理事件
while True:
	# 读取事件和输入型组件的返回值
	event, values = window.read()
	# 控制台输出,便于调试
	print(event, values)

	# 发送按钮事件响应逻辑
	if event == '发送':
		# 处理输入框的数据,添加多行文本控制符\n
		text = text + '我:'+values['-IN-']+'\n'
		print(text)
		# 更新文本框数据,实现发送功能
		window['-TEXT-'].update(value=text)
		window['-IN-'].update('')

	# 清空聊天记录按钮事件响应逻辑
	if event == '清空聊天记录':
		# 更新窗口中的文本框数据
		window['-TEXT-'].update('')

	# 点击X,关闭窗口
	if event == sg.WIN_CLOSED:
		break

# 关闭窗口
window.close()

在这里插入图片描述

  • 重点回顾

上面的一段代码实现了一个简易的图形化窗口,窗口中有文本框、输入框和按钮三种组件。点击发送按钮后,输入框中的内容会被发送到聊天文本框中;点击清空聊天记录会清空聊天文本框。分析源码可以得到得出以下几点结论:

  1. 组件中的key参数是主窗口识别组件的依据,按钮的字符串参数为按钮的名字,如果按钮被点击了,主窗口的事件会检测到以按钮名字为依据的事件名
  2. 输入型组件的数据会被主窗口事件轮询的values接收到,values是一个字典,键为组件的key,值为数据
  3. 主窗口根据组件key开更新组件的数据



3. 文件选择器

  • 功能:点击按钮开始选择文件,将选择的文件或文件夹的绝对路径显示出来
# 文件选择器
# 导入库
import PySimpleGUI as sg

layout = [
	[sg.FileBrowse('单文件选择', target='-GETFILE-',
	               key='-GETFILE-', enable_events=True, file_types=(("ALL Files", "*.*"),))],
	[sg.Text('选择的单文件是:'), sg.Text('', key='-TEXT-', size=(60, 1),
	                             background_color='white', text_color='red')],
	[sg.FilesBrowse('多文件选择', target='-GETFILES-',
	               key='-GETFILES-', enable_events=True, file_types=(("ALL Files", "*.*"),))],
	[sg.Text('选择的多文件分别是:')],
	[sg.Text('', key='-TEXT1-', size=(80, 6),
	                             background_color='white', text_color='red')],
	[sg.FolderBrowse('文件夹选择', target='-GFOLDER-',
	               key='-GFOLDER-', enable_events=True)],
	[sg.Text('选择的文件夹是:'), sg.Text('', key='-TEXT2-', size=(60, 1),
	                              background_color='white', text_color='red')],
	[sg.FileSaveAs('另存为', target='-SAVEAS-',
	               key='-SAVEAS-', enable_events=True)],
	[sg.Text('保存的文件是:'), sg.Text('', key='-TEXT3-', size=(60, 1),
	                              background_color='white', text_color='red')],
]

# 创建主窗口,设置窗口名,给窗口传入layout指明的组件
window = sg.Window('文件选择器', layout, size=(600, 500))

while True:
	# 读取事件和输入型组件的返回值,values返回值是一个字典
	event, values = window.read()
	# 控制台输出,便于调试
	print(event, values)
	# 点击x退出
	if event == sg.WIN_CLOSED:
		break
	# 获取单文件选择框的输出并将文件的绝对路径更新到文本框显示
	if event == '-GETFILE-':
		window['-TEXT-'].update(values['-GETFILE-'])
	# 获取多文件选择框的输出并将多个文件的绝对路径更新到文本框显示
	# \n是多行文本框的换行符
	if event == '-GETFILES-':
		files_path = values['-GETFILES-']
		files_path = files_path.replace(';', '\n')
		# print(files_path)
		window['-TEXT1-'].update(files_path)
	# 获取文件夹选择框框的返回值,并将之显示在文本框
	if event == '-GFOLDER-':
		window['-TEXT2-'].update(values['-GFOLDER-'])
	# # 获取另存为选择框的输出并将文件的绝对路径更新到文本框显示
	if event == '-SAVEAS-':
		window['-TEXT3-'].update(values['-SAVEAS-'])
# 最后关闭窗口,防止循环中的退出事件失效
window.close()
  • 单文件选择器图形化展示

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述
  • 最终的界面,包括多文件选择结果,文件夹选择结果,另存为的文件名

    最终的展示结果

注:文件选择器的功能是返回用户在可视化界面中指定的文件或文件夹的绝对路径以配合其他处理函数对文件进行处理和保存。值得注意的是,将选择器的target和key参数设为一致,才会有事件返回值。



4. 调整列表框的行序

  • 功能:用按钮更改一段多行文本行内容的先后顺序
  • 组件:文本框、列表、按钮、主窗口、弹窗
# 列表框行序调整
# 导入库
import PySimpleGUI as sg
text = ['第一行', '第二行', '第三行', '第四行']

layout = [
    [sg.T('列表内容:')],
    [
     sg.Listbox(text, key='-TEXT-', select_mode='single', enable_events=True,
                background_color='white', text_color='red', size=(80, 6))
     ],
    [sg.B('刷新显示'), sg.B('上调'), sg.B('下调'), sg.B('置首'), sg.B('置尾')]

]

# 创建主窗口,设置窗口名,给窗口传入layout指明的组件
window = sg.Window('文本行序调整', layout, size=(600, 200))

while True:
    # 读取事件和输入型组件的返回值,values返回值是一个字典
    event, values = window.read()
    # 控制台输出,便于调试
    print(event, values)
    # 点击x退出
    if event == sg.WIN_CLOSED:
        break
    if event == '刷新显示':
        window['-TEXT-'].update(text)

    if event == '置首':
        sss = window['-TEXT-'].get_indexes()[0]
        if sss == 0:
            sg.popup('已到达最顶部')
        else:
            temp = text[sss]
            del text[sss]
            text.insert(0, temp)
            window['-TEXT-'].update(text, set_to_index=0)

    if event == '置尾':
        sss = window['-TEXT-'].get_indexes()[0]
        if sss == len(text)-1:
            sg.popup('已到达最底部')
        else:
            temp = text[sss]
            del text[sss]
            text.append(temp)
            window['-TEXT-'].update(text, set_to_index=len(text)-1)
    if event == '上调':
        sss = window['-TEXT-'].get_indexes()[0]
        if sss == 0:
            sg.popup('已经到达最顶部')
        else:
            temp = text[sss]
            del text[sss]
            text.insert(sss-1, temp)
            window['-TEXT-'].update(text, set_to_index=sss-1)
    if event == '下调':
        sss = window['-TEXT-'].get_indexes()[0]
        if sss == len(text)-1:
            sg.popup('已经到达最底部')
        else:
            temp = text[sss]
            del text[sss]
            text.insert(sss+1, temp)
            window['-TEXT-'].update(text, set_to_index=sss+1)

# 最后关闭窗口,防止循环中的退出事件失效
window.close()
  • 运行结果

    在这里插入图片描述

在这里插入图片描述

注:这个小例子的难点是如何获取到列表组件内容的索引值,反复摸索后才找到

get_indexes()函数,set_to_index=index参数可以指定着重标记的列表项。只要找到了要操作的列表项的索引值,再根据索引对列表的数据进行增删改查就容易了。

如果觉得作者的内容对您有帮助,可以给作者点赞或打赏,也欢迎大家在评论区留言与作者交流!



版权声明:本文为qq_31628691原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。