Tkinter网格系统:元素排列

时间:2018-07-25 22:32:47

标签: python user-interface tkinter discord

我目前正在编码一个程序,该程序将与Discord的丰富功能配合使用,我需要在Tkinter中为其创建GUI。问题是,我不明白如何正确放置元素。真是痛苦。这是我计划使应用看起来像的样子:https://i.stack.imgur.com/K9Wox.jpg

但是,在我当前的代码中,这就是GUI的外观... https://i.stack.imgur.com/wGA9A.jpg

这是我的代码:

root = tkinter.Tk()
root.title("Matter: A Discord Rich Presence Tool")
root.config(bg='#2C2F33')
root.geometry("560x300")
#root.overrideredirect(1)

# Load images 
loadProfileImage = tkinter.PhotoImage(file="resources/loadprofile.png")
saveProfileImage = tkinter.PhotoImage(file="resources/saveprofile.png")
newProfileImage = tkinter.PhotoImage(file="resources/newprofile.png")


# GUI Hell starts here
topCanvas = tkinter.Canvas(root, width=600, height=150)
topCanvas.config(bd=0, highlightthickness=0, relief='ridge', background="#7289DA")

topTextFieldText = tkinter.StringVar(value='Sample top text')
topTextField = tkinter.Entry(root, textvariable=topTextFieldText)
topTextField.config(borderwidth=0, background="#7289DA")


bottomTextFieldText = tkinter.StringVar(value='Sample bottom text')
bottomTextField = tkinter.Entry(root, textvariable=bottomTextFieldText)
bottomTextField.config(borderwidth=0, background="#7289DA")


largeIconName = tkinter.StringVar()
largeIconNameField = tkinter.Entry(root, textvariable=largeIconName)

smallIconName = tkinter.StringVar()
smallIconNameField = tkinter.Entry(root, textvariable=smallIconName)


applicationIDFieldText = tkinter.StringVar()
applicationIDField = tkinter.Entry(root, textvariable=applicationIDFieldText)
applicationIDField.config(borderwidth=0, background="#23272A")

largeIconHoverText = tkinter.StringVar()
largeIconHoverTextField = tkinter.Entry(root, textvariable=largeIconHoverText)
largeIconHoverTextField.config(borderwidth=0, background="#23272A")

smallIconHoverText = tkinter.StringVar()
smallIconHoverTextField = tkinter.Entry(root, textvariable=smallIconHoverText)
smallIconHoverTextField.config(borderwidth=0, background="#23272A")


#greet_button = tkinter.Button(root, text="Run", command=run)

buttonFrame = tkinter.Frame(height=2, bd=0, relief=tkinter.SUNKEN)

newProfileButton = tkinter.Button(root, text="Save to profile", command=save)
newProfileButton.config(image=newProfileImage, borderwidth=0, background="#23272A")


saveButton = tkinter.Button(root, text="Save to profile", command=save)
saveButton.config(image=saveProfileImage, borderwidth=0, background="#23272A")


loadButton = tkinter.Button(root, command=load)
loadButton.config(image=loadProfileImage, borderwidth=0, background="#23272A")


# Grid stuff
topCanvas.grid(row=0, column=1)

applicationIDField.grid(row=3, column=1)
largeIconHoverTextField.grid(row=3, column=2)
smallIconHoverTextField.grid(row=3, column=3)

newProfileButton.grid(row=5, column=1, padx=(20, 5))
saveButton.grid(row=5, column=2, padx=(5, 5))
loadButton.grid(row=5, column=3, padx=(5, 20))

root.mainloop()

任何指导将不胜感激,因为我似乎无法弄清楚如何使用Tkinter的网格进行与上图类似的布局。

2 个答案:

答案 0 :(得分:0)

首先,您必须向网格几何管理器说明您希望画布跨越所有三列:

topCanvas.grid(row=0, column=1, columnspan=3)

如果您未指定窗口小部件,则窗口小部件不会自动展开以填充整个列(或行);如果您未使用sticky指定窗口小部件,则窗口小部件将自动居中显示在单元格中:

newProfileButton.grid(row=5, column=1, padx=(20, 5), sticky='w')
saveButton.grid(row=5, column=2, padx=(5, 5), sticky='w')
loadButton.grid(row=5, column=3, padx=(5, 20), sticky='w')

尽管这不是一个完整的答案,但它有望给您带来一些乐趣。

这是一个很好的教程:Getting Tkinter Grid Sizing Right the first time

答案 1 :(得分:0)

请勿尝试将所有内容放入单个网格中。将您的UI分成多个部分,然后为每个部分使用正确的工具。

从根窗口开始

我在您的UI中看到两个主要部分:蓝色的顶部具有一些信息,而底部的黑色背景具有一些按钮。

因此,我将从在根窗口中创建这两部分开始,然后使用pack将其中一个放在另一个之上:

topFrame = tk.Frame(root, background="#7289DA")
bottomFrame = tk.Frame(root, background="#2C2F33")

topFrame.pack(side="top", fill="both", expand=True)
bottomFrame.pack(side="bottom", fill="both", expand=True)

这样,您现在将始终将根分为两个彩色区域。上面的代码为它们提供了相等的大小。您可以将一个用户的expand值更改为False,具体取决于用户调整窗口大小时要发生的情况。

不过,不必太担心大小。一旦您开始向每个部分添加小部件,它将改变。

enter image description here

下一步,执行底部

底部似乎也分为两个部分:一个用于输入,另一个用于按钮。您可以在整个部分中使用单个网格布局,但是为了说明将UI划分为多个部分的概念,我们将底部分为两部分。另外,由于并非所有内容都整齐地排列在行和列中,所以这会使事情变得容易一些。

正如我之前提到的,您可能想使用expand选项,这取决于您是希望这些框架在用户调整窗口大小时重新调整大小还是保持相同大小。

inputFrame = tk.Frame(bottomFrame, background="#2C2F33")
buttonFrame = tk.Frame(bottomFrame, background="#2C2F33")

inputFrame.pack(side="top", fill="both", expand=True)
buttonFrame.pack(side="top", fill="both", expand=True)

注意:如果您就在这里停止并尝试运行程序,则可能看不到这些框架。在开发过程中,有时可以为它们提供独特的颜色以帮助您可视化。一旦一切正常,就可以将颜色调整为最终值。

添加条目小部件

现在,我们可以将条目小部件添加到底部的上半部分。我们可以在这里使用grid,因为所有内容都排列整齐。重要的步骤是使行具有相等的权重,以便它们一起增长和收缩,尽管您可以这样做,以便根据需要仅调整一列的大小。

我还将指出,无需使用StringVar实例。您可以,但是它添加了额外的对象以进行跟踪,在大多数情况下,这是没有必要的。

    label1 = tk.Label(inputFrame, text="APPLICATION ID",
                      foreground="lightgray",
                      background="#2C2F33")
    label2 = tk.Label(inputFrame, text="LARGE IMAGE HOVER",
                      foreground="lightgray",
                      background="#2C2F33")
    label3 = tk.Label(inputFrame, text="SMALL IMAGE HOVER",
                      foreground="lightgray",
                      background="#2C2F33")

    # columns should get extra space equally. Give any extra vertical space
    # to an empty column below the entry widgets
    inputFrame.grid_columnconfigure((0,1,2), weight=1)
    inputFrame.grid_rowconfigure(2, weight=1)

    appIdEntry = tk.Entry(inputFrame, borderwidth=0,
                          highlightthickness=0,
                          background="#23272A", bd=0)
    largeImageEntry = tk.Entry(inputFrame, 
                               highlightthickness=0,
                               background="#23272A", bd=0)
    smallImageEntry = tk.Entry(inputFrame, borderwidth=0,
                               highlightthickness=0,
                               background="#23272A", bd=0)

    label1.grid(row=0, column=0, sticky="w")
    label2.grid(row=0, column=1, sticky="w", padx=10)
    label3.grid(row=0, column=2, sticky="w")
    appIdEntry.grid(row=1, column=0, sticky="ew")
    largeImageEntry.grid(row=1, column=1, sticky="ew", padx=10)
    smallImageEntry.grid(row=1, column=2, sticky="ew")

这给我们以下内容: enter image description here

请注意,顶部似乎已经缩小。那只是因为它是空的。 Tkinter非常擅长于扩展和缩小内容以适合内部内容。不用太担心。一旦一切正常,就可以进行调整。

以此类推...

我不想在此答案中重写整个程序。这里的要点是,您应该将您的UI分成逻辑块,并使每个块成为一个框架。然后,您可以自由使用该框架中最有意义的任何几何图形管理器。有时grid最好,有时pack。无论哪种情况,管理几个高级框架都比将数十个小部件塞入单个网格要容易得多,尤其是在没有明确的行和/或列的情况下。

此解决方案还使为每个部分创建函数或类变得非常容易。例如,您的主程序可能如下所示:

root = tkinter.Tk()
top = topSection(root)
bottom = bottomSection(root)

这样做,如果您决定完全重新设计UI的一部分,则可以这样做,而不必担心会弄乱其他部分的布局,因为每个框架都基本上独立于任何其他框架。