【问题标题】:TKinter GUI, how do I get Frames to correct size?TKinter GUI,我如何让帧正确大小?
【发布时间】:2017-06-29 16:51:59
【问题描述】:

这就是问题所在。我正在使用 Python 的 TKinter 对 GUI 进行编程,并且我需要将窗口设置为特定大小。该程序的发布版本将屏幕设置为root.attributes("-fullscreen", True),因此它是全屏的,用户将无法访问任何菜单。所述屏幕将是 800x480 平板电脑屏幕。

显然我是在比 800x480 大得多的屏幕上编程,所以当我创建我的 tkinter 窗口时,我设置 root.minsize("800x480") 来模拟程序所处的环境。

至于 GUI 上的内容,我将提供一系列按钮和其他内容。窗口本身将被分成两个框架:一个按钮框架和一个可视框架。顾名思义,Button Frame 是一个完全由 Buttons 组成的 Frame,用于用户输入,而 Visual Frame 显然只包含用户的视觉输出。

所以这是我的问题。我目前正在研究 Button Frame,但我遇到了 Frame 尺寸不正确的问题。由于我还没有为可视框架完成编程,所以我刚刚创建了两个按钮框架并将它们放入根窗口。两个框架都应该占据整个屏幕,但它们不是。这是我的代码:

import tkinter as tk
from tkinter import ttk

class ButtonManager(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)

        self.config(background = 'green')
        self.columnconfigure(0, weight = 1)
        self.rowconfigure(0, weight = 1)

        lblFrame = LabelFrame(self, controller)
        lblFrame.grid(column = 0, row = 0, sticky = "nsew")
        lblFrame.tkraise()

        btnFrame = ButtonFrame(self, controller)
        btnFrame.grid(column = 0, row = 1, sticky = "nsew")
        btnFrame.tkraise()

        for child in self.winfo_children():
            child.grid_configure(padx = 5, pady = 5)

class LabelFrame(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)

        self.config(background = 'blue')

        lblTitleBar = ttk.Label(self, text = 'TITLE BAR', background = 'grey', font = ("Arial", 20, "bold"))
        lblTitleBar.grid(column = 1, row = 1, columnspan = 4, sticky = "nsew")

        lblTextBar = ttk.Label(self, text = 'test text', background = 'grey', font = ("Arial", 16, "bold"))
        lblTextBar.grid(column = 1, row = 2, columnspan = 4, sticky = "nsew")

class ButtonFrame(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)

        self.config(background = 'red')

        btn1 = ttk.Button(self, text = '1', command = lambda : print("1"))
        btn1.grid(column = 1, row = 1, columnspan = 2, rowspan = 2, sticky = "nsew")

        #Not gonna type out the code for all the buttons, but I have 2 columns, and 6 rows.  
        #The buttons on the 4th and 6th row span the columns of both rows.
        #In total there are 10 buttons

        for child in self.winfo_children():
            child.grid_configure(padx = 5, pady = 5)

class Interface(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        container = tk.Frame(self)
        container.grid(column = 0, row = 0, sticky = "nsew")
        container.grid_rowconfigure(0, weight = 1)
        container.grid_columnconfigure(0, weight = 1)

        bMan1 = ButtonManager(container, self)
        bMan1.grid(column = 0, row = 0, sticky = "nsew")
        bMan2 = ButtonManager(container, self)
        bMan2.grid(column = 1, row = 0, sticky = "nsew")

interface = Interface()
interface.minsize(800, 480)
interface.mainloop()

正如我上面所说,我的问题是我需要每个 ButtonManager 对象在每个宽度上占据屏幕的一半。然而,我得到了 2 个小盒子和一个大的灰色区域。

随机颜色用于测试目的顺便说一句:P

编辑:我的代码中有一些复制/粘贴错误,现在它应该作为一个文件工作。道歉。

【问题讨论】:

  • 如果您创建了一个不需要两个单独文件的 minimal reproducible example,这将非常有帮助。
  • 您的 ButtonFrame 似乎坏了,还有其他错误。您的代码需要可运行。
  • @BryanOakley 我会设置它以便它可以是一个文件,编辑公司。我确实复制/粘贴了错误的 ButtonFrame 函数,我忘记了 def __init__ >__

标签: python user-interface tkinter


【解决方案1】:

您试图一次解决太多问题。当第一次开始使用 tkinter 时,或者第一次布置新的 GUI 时,有条不紊并且一次只解决一个布局问题确实很有帮助。

第 1 步 - 主窗口

您已选择为 GUI 中的所有内容创建一个“容器”。因此,第一步是在尝试让其他任何东西发挥作用之前让它发挥作用。如果它太小,那么它会导致其中的所有内容都太小,这是您原始代码问题的一部分。

因为它是唯一直接在根目录中的小部件,我建议使用pack。您可以使用grid,但这需要三行代码而不是一行,因为使用grid,您必须记住配置至少一行和一列的权重。

从以下开始(以下):

class Interface(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        container = tk.Frame(self, background="bisque")
        container.pack(fill="both", expand=True)

interface = Interface()
interface.minsize(800, 480)
interface.mainloop()

它看起来怎么样?它看起来不错——蓝色完全填满了 800x480 的窗口。我们现在不再需要担心容器。

如果你想使用grid,把调用pack的那一行去掉,换成这三行:

self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
container.grid(row=0, column=0, sticky="nsew")

第 2 步 - 容器的子项

看起来容器将包含两个孩子,对吧?左侧是按钮框架,右侧是主要区域。现在让我们使用几个空帧,在继续之前让它们工作。

您没有指定这些区域的大小,因此在此示例中,左侧的列将是屏幕大小的 1/3,而右侧的列将是 2/3。如果您愿意,您可以为左侧使用固定的像素宽度,并让右侧占据其余部分。

如果您需要一个非常具体的宽度,您可以在这里使用place,但现在我们将坚持使用grid

Interface.__init__的底部添加以下内容:

    bman = ButtonManager(container, controller=self)
    main = Main(container, controller=self)

    container.grid_columnconfigure(0, weight=1)
    container.grid_columnconfigure(1, weight=2)
    container.grid_rowconfigure(0, weight=1)

    bman.grid(row=0, column=0, sticky="nsew")
    main.grid(row=0, column=1, sticky="nsew")

我们还需要为ButtonManagerMain 定义存根:

class ButtonManager(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        self.configure(background="green")

class Main(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        self.configure(background="yellow")

这已经足够编码了。停止并运行代码,确保粉色窗口占据蓝色区域的 1/3,黄色窗口占据另外 2/3。

这可能是玩转columnconfigure 属性(最小尺寸、重量、填充)的不同值的好时机,或者改用place 来看看它是如何工作的。

第 3 步 - 按钮管理器

我们只需要继续这个过程,更深一层。好消息是,我们只需要关注按钮管理器内部发生的事情。除非我们添加一个太大而无法容纳的小部件,否则我们无法更改整个窗口的整体布局。

看起来ButtonManager 由标题和按钮区域组成。所以,让我们补充一下。由于此框架中只有两个小部件,我们可以再次使用 pack 节省几行代码和一些令人头疼的问题,因为 pack 擅长从上到下堆叠。

在下面的代码中,我将标签贴在顶部,并让按钮框架填充窗口的其余部分。

ButtonManager 更改为如下所示:

class ButtonManager(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        self.config(background = 'green')

        lblFrame = LabelFrame(self, controller)
        btnFrame = ButtonFrame(self, controller)

        lblFrame.pack(side="top", fill="x", expand=False)
        btnFrame.pack(side="top", fill="both", expand=True)

第 4 步:标签框

这只是一个带有几个标签的框架。同样,由于它只有几个小部件,pack 将节省一些编码。如果你愿意,你可以使用grid,只要记住你必须配置行和列的权重。

class LabelFrame(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        self.configure(background="blue")

        lblTitleBar = ttk.Label(self, text = 'TITLE BAR', background = 'grey', font = ("Arial", 20, "bold"))
        lblTextBar = ttk.Label(self, text = 'test text', background = 'grey', font = ("Arial", 16, "bold"))

        lblTitleBar.pack(side="top", fill="x")
        lblTextBar.pack(side="top", fill="x")

第 5 步 - 按钮框架

最后是按钮框架。会有一个按钮网格。现在这个过程应该很熟悉了——创建小部件,并使用gridpack 来布置它们。在这种情况下,grid 最有意义。

class ButtonFrame(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        self.configure(background="red")

        for row in range(7):
            self.grid_rowconfigure(row, weight=1)
        self.grid_columnconfigure(0, weight=1)
        self.grid_columnconfigure(1, weight=1)

        b1 = tk.Button(self, text="Button 1")
        b2 = tk.Button(self, text="Button 2")
        b3 = tk.Button(self, text="Button 3")
        b4 = tk.Button(self, text="Button 4")
        b5 = tk.Button(self, text="Button 5")
        b6 = tk.Button(self, text="Button 6")
        b7 = tk.Button(self, text="Button 7")
        b8 = tk.Button(self, text="Button 8")
        b9 = tk.Button(self, text="Button 9")
        b10 = tk.Button(self, text="Button 10")

        b1.grid(row=0, column=0, sticky="nsew")
        b2.grid(row=0, column=1, sticky="nsew")
        b3.grid(row=1, column=0, sticky="nsew")
        b4.grid(row=1, column=1, sticky="nsew")
        b5.grid(row=2, column=0, sticky="nsew")
        b6.grid(row=2, column=1, sticky="nsew")
        b7.grid(row=3, column=0, columnspan=2, sticky="nsew")
        b8.grid(row=4, column=0, sticky="nsew")
        b9.grid(row=4, column=1, sticky="nsew")
        b10.grid(row=5, column=0, columnspan=2, sticky="nsew")

总结

如果您对 GUI 布局采取有条不紊的方法,问题会变得更容易解决,因为您一次只解决一个区域。如果您密切关注上述所有内容,您最终会得到一个运行良好的 GUI,即使您扩大或缩小窗口也是如此。

我知道您对非常具体的尺寸有要求,但最好养成编写 gui 以响应字体、分辨率和窗口尺寸变化的习惯。

【讨论】:

    猜你喜欢
    • 2012-10-23
    • 2022-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-29
    • 1970-01-01
    • 1970-01-01
    • 2012-11-07
    相关资源
    最近更新 更多