首页 > 技术文章 > pysimplegui之列表布局

catfeel 2022-01-15 18:05 原文

重点

1通过循环生成一行

2通过循环生成一列

3【】这个代表一行

4需要大量重复布局的时候可以使用

生成的布局(如果你有> 5个重复元素/行,一定要阅读)

本节讨论了 5 种生成布局的特定技术。它们可以单独使用,也可以相互结合使用。

  1. 布局 + 布局串联 [[A]] + [[B]] = [[A], [B]]
  2. 同一行上的元素添加 [[A] + [B]] = [[A, B]]
  3. 列表理解生成一行 [A for x in range(10)] = [A,A,A,A,A...]
  4. 列表理解生成多行 [[A] for x in range(10)] = [[A],[A],...]
  5. 用户定义元素/复合元素

示例 - 连接多行的列表理解 - “待办事项”列表示例

让我们创建一个小布局,用于使用 PySimpleGUI 制作待办事项列表。

蛮力

import PySimpleGUI as sg

layout = [
            [sg.Text('1. '), sg.In(key=1)],
            [sg.Text('2. '), sg.In(key=2)],
            [sg.Text('3. '), sg.In(key=3)],
            [sg.Text('4. '), sg.In(key=4)],
            [sg.Text('5. '), sg.In(key=5)],
            [sg.Button('Save'), sg.Button('Exit')]
         ]

window = sg.Window('To Do List Example', layout)
event, values = window.read()

这个脚本的输出是这个窗口:

SNAG-0451

花点时间看看代码和生成的窗口。您是否能够查看布局并设想屏幕上的窗口?

通过连接行构建

蛮力方法适用于 5 项长的列表,但如果您的待办事项列表上有 40 项怎么办。然后呢?好吧,这就是我们转向“生成”布局的时候,它是由您的代码生成的布局。用这个布局定义替换上一个示例中的 layout= 内容。

import PySimpleGUI as sg

layout = []
for i in range(1,6):
    layout += [sg.Text(f'{i}. '), sg.In(key=i)],
layout += [[sg.Button('Save'), sg.Button('Exit')]]

window = sg.Window('To Do List Example', layout)
event, values = window.read()

它当然会产生完全相同的窗口。这就是进步.... 从写出 GUI 的每一行到生成每一行。如果我们想要建议的 48 个项目,请将 range(1,6) 更改为 range(1,48)。每次通过列表时,都会将另一行添加到布局中。

使用列表理解创建多行

但是,我们还没有完成!

这是Python,我们使用列表来构建一些东西,所以我们应该看看*list comprehensions *. 让我们将for循环更改为列表推导。回想一下,我们的for循环用于将 6 行连接到一个布局中。

layout =  [[sg.Text(f'{i}. '), sg.In(key=i)] for i in range(1,6)]

在这里,我们将for循环移动到列表定义内部(列表理解)

连接多行

我们已经使用列表推导构建了行,现在我们只需要按钮。通过简单的添加,它们可以很容易地“固定到最后”。

layout =  [[sg.Text(f'{i}. '), sg.In(key=i)] for i in range(1,6)]
layout += [[sg.Button('Save'), sg.Button('Exit')]]

任何时候您有 2 个布局,您都可以通过简单的相加将它们连接起来。确保您的布局是“列表列表”布局。在上面的例子中,我们知道第一行是输入行的生成布局。最后一行在布局上添加了另一个布局...注意格式为 [ [ ] ]。

这个按钮定义是一个完整的布局,可以添加到我们的列表理解中

[[sg.Button('Save'), sg.Button('Exit')]]

这是相当可读的代码。两种布局在视觉上排列得很好。

但是,我们不要停止压缩代码。如何删除那个 += 而是将布局更改为单行,+在两组行之间只有 a 。

在一行上进行这种连接,我们最终得到了这个为 GUI创建整个布局的语句:

layout =  [[sg.Text(f'{i}. '), sg.In(key=i)] for i in range(1,6)] + [[sg.Button('Save'), sg.Button('Exit')]]

最终“待办事项”计划

这里我们有我们的最终程序......所有4行。

import PySimpleGUI as sg

layout  = [[sg.Text(f'{i}. '), sg.In(key=i)] for i in range(1,6)] + [[sg.Button('Save'), sg.Button('Exit')]]

window = sg.Window('To Do List Example', layout)

event, values = window.read()

如果你真的想把事情搞定,你可以通过将布局移动到对 Window

import PySimpleGUI as sg

event, values = sg.Window('To Do List Example', layout=[[sg.Text(f'{i}. '), sg.In(key=i)] for i in range(1,6)] + [[sg.Button('Save'), sg.Button('Exit')]]).read()

示例 - 构建行的列表理解 - 表模拟 - 输入网格

在这个例子中,我们正在使用Input元素构建一个 4 宽 x 10 高的“桌子”

我们正在寻求的最终结果是这样的:

HEADER 1    HEADER 2    HEADER 3    HEADER 4
INPUT       INPUT       INPUT       INPUT
INPUT       INPUT       INPUT       INPUT
INPUT       INPUT       INPUT       INPUT
INPUT       INPUT       INPUT       INPUT
INPUT       INPUT       INPUT       INPUT
INPUT       INPUT       INPUT       INPUT
INPUT       INPUT       INPUT       INPUT
INPUT       INPUT       INPUT       INPUT
INPUT       INPUT       INPUT       INPUT
INPUT       INPUT       INPUT       INPUT

代码完成后,结果将如下所示:

图片

我们将使用列表推导构建每一行,我们将通过使用另一个列表推导连接行来构建表格。这是一个跨越的列表理解和另一个沿着布局向下的列表理解,一行接一行地添加。

构建标题

首先让我们构建标题。这里有两个概念需要注意:

import PySimpleGUI as sg

headings = ['HEADER 1', 'HEADER 2', 'HEADER 3','HEADER 4']  # the text of the headings
header =  [[sg.Text('  ')] + [sg.Text(h, size=(14,1)) for h in headings]]  # build header layout

这段代码中有两点需要注意 1. 构成标题元素的列表理解 2. 添加到前面的空格

让我们从标题本身开始。

这是生成一行包含标题文本的文本元素的代码。结果是一个文本元素列表,一行。

[sg.Text(h, size=(14,1)) for h in headings]

然后我们添加一些空格来移动标题,使它们在它们的列上居中。为此,我们只需Text在该标题列表的前面添加一个元素即可。

header =  [[sg.Text('  ')] + [sg.Text(h, size=(14,1)) for h in headings]]

这个header变量是一个有 1 行的布局,其中有一堆Text带有标题的元素。

构建输入元素

元素以Input网格形式排列。为此,我们将使用双重列表推导。一个将构建行,另一个将行添加在一起以形成网格。这是执行此操作的代码行:

input_rows = [[sg.Input(size=(15,1), pad=(0,0)) for col in range(4)] for row in range(10)]

语句的这一部分构成单行 4 个Input元素

[sg.Input(size=(15,1), pad=(0,0)) for col in range(4)]

接下来,我们获取Input元素列表,并根据行数制作尽可能多的元素,在本例中为 10。我们再次使用 Python 令人敬畏的列表推导将这些行添加到一起。

input_rows = [[sg.Input(size=(15,1), pad=(0,0)) for col in range(4)] for row in range(10)]

第一部分应该看起来很熟悉,因为它只是作为构建单行的内容进行了讨论。要制作矩阵,我们只需取那一行并创建 10 个,每个都是一个列表。

把它们放在一起

这是我们的最终程序,它使用简单的加法将标题添加到输入矩阵的顶部。为了使其更具吸引力,颜色主题设置为“深棕色 1”。

import PySimpleGUI as sg

sg.theme('Dark Brown 1')

headings = ['HEADER 1', 'HEADER 2', 'HEADER 3','HEADER 4']
header =  [[sg.Text('  ')] + [sg.Text(h, size=(14,1)) for h in headings]]

input_rows = [[sg.Input(size=(15,1), pad=(0,0)) for col in range(4)] for row in range(10)]

layout = header + input_rows

window = sg.Window('Table Simulation', layout, font='Courier 12')
event, values = window.read()

图片

用户定义元素/复合元素

“用户定义元素”和“复合元素”是包装在函数定义中的一个或多个 PySimpleGUI 元素。在布局中,它们看起来像是某种类型的自定义元素。

当您在布局中反复使用的元素上设置大量参数时,用户定义的元素特别有用。

示例 - 计算器应用程序的按钮网格

假设您正在使用具有以下设置的按钮制作计算器应用程序:

  • 字体 = Helvetica 20
  • 大小 = 5,1
  • 按钮颜色=蓝底白字

这些按钮之一的代码是:

sg.Button('1', button_color=('white', 'blue'), size=(5, 1), font=("Helvetica", 20))

如果您有 6 个按钮和 5 个按钮,那么您的布局将有 30 行这样的文本。

这些按钮的一行可以写成:

    [sg.Button('1', button_color=('white', 'blue'), size=(5, 1), font=("Helvetica", 20)),
     sg.Button('2', button_color=('white', 'blue'), size=(5, 1), font=("Helvetica", 20)),
     sg.Button('3', button_color=('white', 'blue'), size=(5, 1), font=("Helvetica", 20)),
     sg.Button('log', button_color=('white', 'blue'), size=(5, 1), font=("Helvetica", 20)),
     sg.Button('ln', button_color=('white', 'blue'), size=(5, 1), font=("Helvetica", 20)),
     sg.Button('-', button_color=('white', 'blue'), size=(5, 1), font=("Helvetica", 20))],

通过使用用户定义元素,您可以显着缩短布局。让我们调用我们的元素CBtn它会这样写:

def CBtn(button_text):
    return sg.Button(button_text, button_color=('white', 'blue'), size=(5, 1), font=("Helvetica", 20))

使用您的新CBtn元素,您可以将上面的按钮行重写为:

[CBtn('1'), CBtn('2'), CBtn('3'), CBtn('log'), CBtn('ln'), CBtn('-')],

查看您不必编写的大量代码!每当您发现自己多次复制一个元素时,请使用此构造。

但我们不要止步于此。

由于我们一直在讨论列表推导,让我们使用它们来创建这一行。做到这一点的方法是制作一个跨越行的符号列表,形成一个遍历该列表的循环。结果是一个如下所示的列表:

[CBtn(t) for t in ('1','2','3', 'log', 'ln', '-')],

该代码生成的列表与我们手动创建的列表相同:

[CBtn('1'), CBtn('2'), CBtn('3'), CBtn('log'), CBtn('ln'), CBtn('-')],

复合元素

就像一个Button可以从用户定义的元素中返回一样,多个元素也可以。

回到我们之前做的待办事项列表示例,我们可以定义一个用户定义的元素来表示一个待办事项,这次我们要添加一个复选框。此列表中的一行将是:

  • 项目#(一个Text元素)
  • Checkbox指示已完成的元素
  • Input输入要做什么的元素

我们的 User Element 的定义就是这个ToDoItem函数。它是由 3 个 PySimpleGUI 元素组合而成的单个用户元素。

def ToDoItem(num):
    return [sg.Text(f'{num}. '), sg.CBox(''), sg.In()]

当与我们之前学习的列表理解技术相结合时,这使得创建一个包含 5 个待办事项的列表变得非常简单。这是在我们的待办事项列表中创建 5 个条目所需的代码。

layout = [ToDoItem(x) for x in range(1,6)]

然后我们可以从字面上添加按钮

layout = [ToDoItem(x) for x in range(1,6)] + [[sg.Button('Save'), sg.Button('Exit')]]

这是我们的最终程序

import PySimpleGUI as sg

def ToDoItem(num):
    return [sg.Text(f'{num}. '), sg.CBox(''), sg.In()]

layout = [ToDoItem(x) for x in range(1,6)] + [[sg.Button('Save'), sg.Button('Exit')]]

window = sg.Window('To Do List Example', layout)
event, values = window.read()

它创建的窗口如下所示:

图片

2列元素和框架,选项卡“容器”元素

列和框架和选项卡都是“容器元素”并且行为相似。本节重点介绍列,但可以在其他地方应用。

从 2.9 版开始,您将能够使用 Column Element 进行更复杂的布局。将列视为窗口中的窗口。而且,是的,如果需要,您可以在 Column 中拥有 Column。

与所有“容器元素”一样,列以与窗口完全相同的方式指定为列表列表。

如果要在单行中指定多个元素,则需要列。

例如,此布局有一个滑块元素,该元素跨越多行,后跟 7TextInput同一行上的元素。

柱子

如果没有列元素,您将无法创建这样的布局。但是有了它,您应该能够紧密匹配仅使用 tkinter 创建的任何布局。


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)

列作为修改元素的一种方式

有时 Columns 用于包含单个 elemnet,但要做到这一点,即使不是不可能,也很难做到这些布局。

通过设置'参数来证明Column元素的行。Columnjustification

您还可以Column使用 Column 的element_justification参数来证明 a 中的全部内容。

使用这些参数,可以创建内容居中的窗口。以前这很难做到。

这目前仅在主要 PySimpleGUI 端口中可用。

它们还可以用于以特定方式证明一组元素的合理性。

将元素放置Column在元素内部Columns可以创建大量

3分级器元素Sizer

4.3 中的新功能是Sizer元素。此元素用于帮助创建特定大小的容器。它可以放在这些 PySimpleGUI 项中:

  • 柱子
  • 框架
  • 标签
  • 窗户

a 的实现Sizer非常简单。它返回一个空Column元素,该元素的填充值设置为传递给Sizer因此不是一个类,而是一个类似于预定义按钮的“快捷功能”。

此功能目前仅在 PySimpleGUI 的 tkinter 端口中可用。需要一个交叉口。


4框架元素(带标签的框架,带标题的框架)

框架与列的工作方式完全相同。您创建布局,然后用于初始化 Frame。与 Column 元素一样,它是一个“容器元素”,其中包含一个或多个元素。

框架元素

注意框架布局看起来与窗口布局相同。窗口的工作方式与列和框架完全相同。它们都是“容器元素”——包含其他元素的元素。

这些容器元素可以嵌套任意深度。这是一个非常漂亮的功能,对吧?做了很多工作,所以要感激。递归代码并非易事。

此代码创建一个带有 Frame 和 2 个按钮的窗口。

frame_layout = [
                  [sg.T('Text inside of a frame')],
                  [sg.CB('Check 1'), sg.CB('Check 2')],
               ]
layout = [
          [sg.Frame('My Frame Title', frame_layout, font='Any 12', title_color='blue')],
          [sg.Submit(), sg.Cancel()]
         ]

window = sg.Window('Frame with buttons', layout, font=("Helvetica", 12))

 

4选项卡和选项卡组元素

选项卡是 PySimpleGUI“容器元素”的另一个。它能够“包含”一个布局,就像一个窗口包含一个布局一样。其他容器元素包括ColumnandFrame元素。

就像窗口和其他容器元素一样,Tab元素的布局由任何所需布局中的任何所需元素组合组成。您可以在 Windows 内的 Columns 内的 Tabs 内拥有 Tabs 等。

Tab布局看起来与 Window 布局完全一样,即它们是Elements 列表的列表

将 Tab 元素放入窗口的方式与所有其他元素不同。 您不能将 Tab 直接放入 Window 的布局中。

此外,此时不能使选项卡不可见。他们有一个可见性参数,但调用 update 不会改变它。

选项卡包含在选项卡组中。它们不会被放置到其他布局中。要将选项卡放入窗口,首先将Tab元素放入TabGroup元素,然后将TabGroup元素放入窗口布局。

让我们以这个 Window 为例:

标签 1

第二个选项卡的视图:

选项卡 2

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')]]

窗口布局具有 TabGroup,并且在选项卡组中有两个 Tab 元素。

关于所有这些容器元素和 Windows 布局,需要注意的一件重要事情是……它们都采用“列表列表”作为布局。他们都有一个看起来像这样的布局[[ ]]

当您正在调试选项卡式窗口时,您将希望将此[[ ]]构造保留在您的脑海中。很容易忽略一两个必要的 ['s

如前所述,旧式选项卡仅限于窗口级别。换句话说,选项卡的大小与整个窗口相同。“新型”选项卡不是这种情况。这就是为什么当您发现您的旧代码不再适用于新的 PySimpleGUI 版本时您不会感到不安的原因。花一点时间来转换你的代码是值得的。

看看新标签有什么可能!

标签 标签 标签

查看选项卡 7 和 8。我们有一个窗口,其中有一列包含选项卡 5 和 6。选项卡 6 上是...选项卡 7 和 8。

从 3.8.0 版开始,并非Tab 和 TabGroup 元素的 API 定义中显示的所有选项都有效。它们作为占位符存在。

首先我们有选项卡布局定义。它们反映了您在屏幕截图中看到的内容。选项卡 1 中有 1 个文本元素。选项卡 2 有一个文本和一个输入元素。

阅读标签组

现在,当读取返回时,选项卡组会返回一个值。它们返回当前选择的选项卡。如果选择/更改了该组中的选项卡,还有一个enable_events可以设置的参数会导致读取返回。属于切换到的 Tab 的键或标题将作为值返回

x## 窗格元素

3.20 版中的新功能是 Pane Element,这是一个超酷的 tkinter 功能。你不会在 PySimpleGUIQt 中找到这个,只有 PySimpleGUI。很难描述其中之一。将它们视为可以滑动的“没有标签的标签”。

窗格3

窗格元素的每个“窗格”都必须是列元素该参数pane_list是列元素的列表。

如果您尝试将所有内容声明为内联,如本示例中所示,调用可能会看起来有点毛茸茸。

sg.Pane([col5, sg.Column([[sg.Pane([col1, col2, col4], handle_size=15, orientation='v',  background_color=None, show_handle=True, visible=True, key='_PANE_', border_width=0,  relief=sg.RELIEF_GROOVE),]]),col3 ], orientation='h', background_color=None, size=(160,160), relief=sg.RELIEF_RAISED, border_width=0)

将这些与可见性相结合,形成了一个有趣的界面,整个窗格从视图中隐藏起来,直到用户需要。这是产生“动态”窗口的一种方式。

颜色

从 2.5 版开始,您可以更改窗口和元素的背景颜色。

你的窗户可以从这里开始:

快照0155

对此......通过一个函数调用......

快照0156

虽然您可以在逐个元素或窗口级别的基础上执行此操作,但更简单的方法是使用theme调用或set_options这些调用将为创建的所有窗口设置颜色。

请注意,一旦您更改了这些选项,它们就会在程序执行的其余部分中更改。您的所有窗口都将具有该主题,直到您将其更改为其他内容。

此调用设置了许多不同的颜色选项。

SetOptions(background_color='#9FB8AD',
       text_element_background_color='#9FB8AD',
       element_background_color='#9FB8AD',
       scrollbar_color=None,
       input_elements_background_color='#F7F3EC',
       progress_meter_color = ('green', 'blue')
       button_color=('white','#475841'))

推荐阅读