python简单进阶之GUI:PySimpleGUI使用教程

快速开始

import PySimpleGUI as sg

sg.theme('DarkAmber')   # 设置当前主题
# 界面布局,将会按照列表顺序从上往下依次排列,二级列表中,从左往右依此排列
layout = [  [sg.Text('Some text on Row 1')],
            [sg.Text('Enter something on Row 2'), sg.InputText()],
            [sg.Button('Ok'), sg.Button('Cancel')] ]

# 创造窗口
window = sg.Window('Window Title', layout)
# 事件循环并获取输入值
while True:
    event, values = window.read()
    if event in (None, 'Cancel'):   # 如果用户关闭窗口或点击`Cancel`
        break
    print('You entered ', values[0])

window.close()

效果:

event和Values详解

当执行window.read()函数时,将会返回一个(event,values)元组。event是事件,它可能是一个按钮的按下、列表项的选择等,比如我设置了一个sg.Submit('提交')按钮,那么event返回的是'提交'。如果我什么也不填,sg.Submit(),那么返回默认值'Submit',当然界面上显示的也是Submit。如果用户点击右上角X关闭窗口,则是None

注意,默认情况下只有Button才能触发事件,然后执行window.read(),也就是说返回的event始终是button名。但是如果你给控件加上一个
enable_events=True参数,那么点击任何控件都可以触发事件了,比如说
sg.Text('My one-shot window.',enable_events=True),那么点击文本也可以触发事件。

values是一个包含所有输入元素的值的字典。字典使用键来定义词条。如果你的元素没有特定的键,系统为你提供一个键。这些自动编号的键是以0开始的。

比如说我有两个输入框,则第一个输入框的值是values[0],第二个输入框的值是values[1]

下面的例子:

import PySimpleGUI as sg    

layout = [[sg.Text('My one-shot window.')],    
                 [sg.InputText()],    
                 [sg.Submit(), sg.Cancel()]]    

window = sg.Window('Window Title', layout)  

event, values = window.read()  

window.close()
text_input = values[0]  
sg.popup('You entered', text_input) # 弹出窗口

如果你想使用自定义key?很简单,相应位置修改为以下代码:

sg.InputText(key='-IN-')
text_input = values['-IN-']
print(text_input)

如何更新数据?

下面是一个例子,使用window[index].update(指定值)的方法,可以更新key为index控件的值,当然,指定值可以是另外一个控件的值,一个例子如下:

layout = [[sg.Text('Your typed chars appear here:'), sg.Text(size=(15,1), key='-OUTPUT-')],
          [sg.Input(key='-IN-')],
          [sg.Button('Show'), sg.Button('Exit')]]

window = sg.Window('Pattern 2B', layout)

while True:  # Event Loop
    event, values = window.read()
    print(event, values)
    if event in  (None, 'Exit'):
        break
    if event == 'Show':
        # Update the "output" text element to be the value of "input" element
        window['-OUTPUT-'].update(values['-IN-'])

window.close()

PS:下文中我会介绍一个target参数,我觉得也挺好用的

手册

window

window = sg.Window("Windows-like program",layout)
window.disappear() # 窗口隐藏
window.reappear() # 窗口展示
window = sg.Window('My window with tabs', layout, font=("宋体", 15),default_element_size=(50,1))  
# 字体为宋体,大小5默认窗口大小为50宽1高

可用控件列表

使用方法:直接sg.Text()即可

  • Text # 文本
  • InputText # 单行输入框
  • Button # 按钮
  • FileBrowse # 文件选择,选择多个文件FilesBrowse,保存文件FileSaveAs
  • FolderBrowse # 文件夹选择
  • CalendarButton # 日历选择,必须输入按钮名如'choose date',返回字符串
  • ColorChooser # 颜色选择,如sg.ColorChooserButton('颜色选择'),返回RGB元组
  • Combo # 下拉选择菜单,如sg.Combo(['choice 1', 'choice 2'])
  • Checkbox # 复选框。如sg.Checkbox('My first Checkbox!', default=True), sg.Checkbox('My second Checkbox!'),返回布尔值
  • Radio # 单选按钮,如sg.Radio('My first Radio!', "RADIO1", default=True),sg.Radio('My second radio!', "RADIO1"),第一个是显示的字符,第二个是单选按钮所在组,只有在同一组的单选按钮才有排他性,第三个是默认选中,返回布尔值True or False
  • Listbox # 列表框,如sg.Listbox(values=['Listbox 1', 'Listbox 2', 'Listbox 3']
  • Slider # 滚动条,如sg.Slider(range=(1,500),default_value=222,orientation='horizontal'),垂直是vertical
  • Multiline # 多行输入框
  • Multi-line Text Output (not on tkinter version)
  • Spin # 一个可以上下调节的控件,像一个简化版的滚动条?如sg.Spin([i for i in range(1,11)], initial_value=1)
  • ProgressBar # 进度条,下面是一个使用案例:
  • layout = [[sg.Text('A custom progress meter')],
              [sg.ProgressBar(1000, orientation='h', size=(20, 20), key='progressbar')],
              [sg.Cancel()]]
    
    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 == 'Cancel'  or event is 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()
    
  • Menu # 菜单
  • ButtonMenu # 菜单按钮
  • menu_def = [['File', ['Open', 'Save', 'Exit' ]],
                ['Edit', ['Paste', ['Special', 'Normal',], 'Undo'],]]
    
    # 定义布局
    layout = [[sg.Menu(menu_def, tearoff=False, pad=(20,1))],
              [sg.ButtonMenu('ButtonMenu',key='-BMENU-', menu_def=menu_def[0])],]
    
    window = sg.Window('My window with tabs', layout)
    
  • Frame # 框,如下面的代码:
  • sg.Frame(layout=[    
        [sg.Checkbox('Checkbox', size=(10,1)),  sg.Checkbox('My second checkbox!', default=True)],    
        [sg.Radio('My first Radio!', "RADIO1", default=True, size=(10,1)), sg.Radio('My second Radio!', "RADIO1")]], 
        title='Options',title_color='red', relief=sg.RELIEF_SUNKEN, tooltip='Use these to set flags')]
    

  • Image # 图片查看,只支持png,gif格式,如sg.Image(r'C:\PySimpleGUI\Logos\PySimpleGUI_Logo_320.png'),不知道为什么我运行这个函数总会有各种问题……
  • TabGroup # 选项卡
  • tab1_layout =  [[sg.T('This is inside tab 1')]]  
    tab2_layout = [[sg.T('This is inside tab 2')],  
                   [sg.In(key='in')]]  
    layout = [[sg.TabGroup([[sg.Tab('Tab 1', tab1_layout), sg.Tab('Tab 2', tab2_layout)]])],  
              [sg.Button('Read')]]  
    window = sg.Window('My window with tabs', layout)  
    
  • Output # 输出框,可以使用print()直接打印,下面是一个例子:
  • def ChatBot():
        layout = [[(sg.Text('This is where standard out is being routed', size=[40, 1]))],
                  [sg.Output(size=(80, 20))],
                  [sg.Multiline(size=(70, 5), enter_submits=True),
                   sg.Button('SEND', button_color=(sg.YELLOWS[0], sg.BLUES[0])),
                   sg.Button('EXIT', button_color=(sg.YELLOWS[0], sg.GREENS[0]))]]
    
        window = sg.Window('Chat Window', layout, default_element_size=(30, 2))
    
        # ---===--- Loop taking in user input and using it to query HowDoI web oracle --- #
        while True:
            event, value = window.read()
            if event == 'SEND':
                print(value)
            else:
                break
        window.close()
    ChatBot()
    

    基本可用参数:

  • key,指定键名
  • size=(8,6),控件大小
  • font = ('宋体',15),字体,前者是字体类型,后者是字体大小
  • enable_events,是否触发事件
  • justification='center',居中
  • 内置Button

    虽然官方列了很多内置Button,但是测试下来似乎并没有什么特殊效果,只是多了可以直接使用的Button罢了

  • OK
  • Ok
  • Submit
  • Cancel
  • Yes
  • No
  • Exit
  • Quit
  • Help
  • Save
  • SaveAs
  • Open
  • 比如说,你可以直接sg.OK(),也可以sg.Button('OK')

    target参数

    选择器型控件,如FileBrowse,FilesBrowse,FolderBrowse,FileSaveAs,CalendarButton,ColorChooserButton,会传递选择值给窗口上的另外一个控件,可以是TextInputText或它本身。比如它与输入框在同一行时会传地址给输入框,如[sg.InputText(),sg.FolderBrowse()],可以为输入框加一个visible=False参数隐藏(是隐藏整个输入框)。

    那么我想让值传递给指定控件,可以加一个target参数,如:

    layout = [[sg.T('Source Folder')],
                  [sg.In(key='input')],
                  [sg.FolderBrowse(key='_BUTTON_KEY_',target='input'), sg.OK()]]
    

    这样选择的值就会传递给相同key的控件

    注意,使用此参数时,就无法获取选择器控件的值了,比如说上面的例子,你就无法
    print(values['_BUTTON_KEY_'])

    popup

    popup

    简单来说,popup就是一个弹出窗口,执行该函数时,会停止执行当前窗口,直到用户关闭弹出窗口时才会重新执行。

    可以输入任意数量的参数,都会转化为字符串并输出。

    拥有以下类型的popup:

    sg.popup('Popup')  # Shows OK button
    sg.popup_ok('PopupOk')  # Shows OK button
    sg.popup_yes_no('PopupYesNo')  # Shows Yes and No buttons
    sg.popup_cancel('PopupCancel')  # Shows Cancelled button
    sg.popup_ok_cancel('PopupOKCancel')  # Shows OK and Cancel buttons
    sg.popup_error('PopupError')  # Shows red error button
    sg.popup_timed('PopupTimed')  # Automatically closes
    sg.popup_auto_close('PopupAutoClose')  # Same as PopupTimed
    

    比如popup_ok是一个带有ok按钮的弹出窗口,popup_timed是一个过一段时间自动关掉的弹出窗口。

    popup中可以输入的参数,自行help(sg.popup),需要注意的一点是因为popup会把所有输入的参数都当做字符串输出,所以特殊的参数需要标识出来,比如sg.popup('values[0],values[1],title="test"')

    popup_scrolled

    还有一类特殊的popup,即Scrolled Output,它展示的是带有滚动条的弹出窗口,适用于展示大量信息时,函数名为sg.popup_scrolled()

    popup_scrolled会自动调整大小,如果想自定义的话,可以sg.popup_scrolled(my_text, size=(80, None))

    上述代码会展示一个宽度为80字符,高度随输出字符串变化的弹出窗口。

    效果

    popup_get_file

    获取一个或多个文件地址

    # 例子:
    text = sg.popup_get_file('Please enter a file name')

    效果:

    特殊参数:

    save_as=False,是否显示保存按钮,multiple_files=False是否允许选择多个文件,no_window=False是否跳过弹出窗口直接显示系统打开文件界面?

    popup_get_folder

    即获取文件夹路径

    注意,该函数没有save_as=Falsemultiple_files=False参数,但是有no_window=False

    主题theme

    theme_name_list = sg.theme_list() # 获取所有可用主题,返回一个列表
    sg.theme_previewer() # 在layout中添加此函数,运行时会展示所有主题的预览
    

    下面代码创造了一个主题浏览器,可以用下拉餐单切换预览所有主题

    sg.theme('Dark Brown')
    layout = [[sg.Text('Theme Browser')],
              [sg.Text('Click a Theme color to see demo window')],
              [sg.Listbox(values=sg.theme_list(), size=(20, 12), key='-LIST-', enable_events=True)],
              [sg.Button('Exit')]]
    window = sg.Window('Theme Browser', layout)
    
    while True:  # Event Loop
        event, values = window.read()
        if event in (None, 'Exit'):
            break
        sg.theme(values['-LIST-'][0])
        sg.popup_get_text('This is {}'.format(values['-LIST-'][0]))
    
    window.close()
    

    实战:写一个简单的批量重命名工具

    直接上代码吧,功能挺简单的,就是把某一个文件夹下所有文件全部重命名为hash值+后缀的形式,如果有两个文件hash值一样,则把其中一个移到重复文件夹下。

    import PySimpleGUI as sg    
    from hashlib import sha1
    import os,shutil
    
    def gui():
        layout = [
                [sg.Text('你选择的文件夹是:',font=("宋体", 10)),sg.Text('',key='text1',size=(50,1),font=("宋体", 10))],
                [sg.Text('程序运行记录',justification='center')],
                [sg.Output(size=(70, 20),font=("宋体", 10))],              
                [sg.FolderBrowse('打开文件夹',key='folder',target='text1'),sg.Button('重命名'),sg.Button('关闭程序')]
                ]    
      
        window = sg.Window('雁陎的工具箱', layout,font=("宋体", 15),default_element_size=(50,1))  
      
        while True:
            event, values = window.read()
            if event in (None, '关闭'):   # 如果用户关闭窗口或点击`关闭`
                break
            if event == '重命名':
                if values['folder']:
                    print('{0}正在重命名原文件为hash值{0}'.format('*'*10))
                    mult_rename(values['folder'])
                    print('{0}重命名完毕{0}'.format('*'*10))
                else:
                    print('请先选择文件夹')
      
        window.close()
    
    
    def calchash(file_path):  # 计算图片hash值
        with open(file_path,'rb') as f:
            sha1obj = sha1()
            sha1obj.update(f.read())
            hash = sha1obj.hexdigest()
            return hash
     
      
    def mult_rename(dir_path): # 批量重命名
        for file in os.listdir(dir_path):
            file_path = os.path.join(dir_path,file)
            if not os.path.isdir(file_path): # 判断是否为文件夹         
                pic_hash = calchash(file_path)      # 计算hash值           
                last = file[file.rindex(r'.'):]  # 后缀
                new_name = pic_hash+last
                if file == new_name:
                    print(file,'无需修改')
                else:
                    try:
                        new_path = os.path.join(dir_path,new_name)
                        os.rename(file_path,new_path)
                        print('{0}已重命名为{1}'.format(file,new_name))
                    except FileExistsError:
                        repeat_path = dir_path+r'\重复文件夹'
                        if os.path.exists(repeat_path) == False:
                            os.makedirs(repeat_path)
                        new_path = os.path.join(repeat_path,new_name)
                        shutil.move(file_path,new_path)
                        print(r'{0}文件重复,已移至重复文件夹下'.format(file))
    
    def main():  
        gui()
    
    if __name__ == '__main__':
        main()          
    

    效果图:

    感觉可以把我所有写的代码都搞一个GUI,(好像也没啥实际用处)

    来源:懵懵懂懂一场️

    物联沃分享整理
    物联沃-IOTWORD物联网 » python简单进阶之GUI:PySimpleGUI使用教程

    发表评论