TKinter GUI,如何让Frames的大小正确?

时间:2017-06-29 16:52:00

标签: python user-interface tkinter

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

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

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

所以这是我的问题。我目前正在处理Button Frame,我遇到的问题是Frame的大小不正确。由于我还没有为Visual Frame完成编程,我只是创建了两个Button 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个小盒子和一个大的灰色区域。

随机颜色用于测试目的btw:P

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

1 个答案:

答案 0 :(得分:4)

您正试图一次解决太多问题。当第一次使用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属性(minsize,weight,pad)的不同值的好时机,或者切换到使用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步:LabelFrame

这只是一个带有几个标签的框架。同样,由于它只有几个小部件,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步 - ButtonFrame

最后,按钮框架。将有一个按钮网格。到目前为止,该过程应该很熟悉 - 创建小部件,然后使用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。

我知道你需要一个非常特定的大小,但是养成编写符合字体,分辨率和窗口大小变化的guis的习惯是很好的。