【问题标题】:tkinter grid: distribute rows and columns over frame height and widthtkinter 网格:在框架高度和宽度上分布行和列
【发布时间】:2015-01-20 23:05:54
【问题描述】:

在 Mac OS 上使用 python 3.4.1 我试图在名为“lowerframe”的子框架中使用网格几何管理器平等地分配标签和条目小部件。

我目前的 MWE 如下所示:

#!/usr/bin/env python3

from tkinter import *
from tkinter import ttk

class Window(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)
        # create master window
        self.master = master

        # create root window on initialization
        self.create_rootwindow()

    def create_rootwindow(self):
        self.master.title("GUI")
        self.master.geometry("1024x748")
        self.master.resizable(width=FALSE, height=FALSE)

        self.create_upperframe()
        self.create_lowerframe()
        self.create_inputentries()
        self.create_btnframe()
        self.create_inputbtn()

    def create_upperframe(self):
        self.upperframe = Frame(self.master, width=980, height=490)
        self.upperframe.config(background="#339900")
        self.upperframe.place(x=20, y=10)

    def create_lowerframe(self):
        self.lowerframe = Frame(self.master, width=830, height=200)
        self.lowerframe.config(background="#336699")
        self.lowerframe.place(x=20, y=530)

    def create_inputentries(self):
        self.create_lowerframe()

        parameternames = [
            ('a', 'U'), ('b', 'U'), ('c', 'U'), ('d', 'U'), ('e', 'U'),
            ('f', 'U'), ('g', 'U'), ('h', 'U'), ('i', 'U'), ('j', 'U'),
            ('k', 'U'), ('l', 'U'), ('m', 'U'), ('n', 'U'), ('o', 'U'),
            ('p', 'U'), ('q', 'U'), ('r', 'U'), ('s', 'U'), ('t', 'U')]

        for i, data in enumerate(parameternames):
            r = i % 5
            c = (i // 5) * 3
            Label(self.lowerframe, text=data[0]).grid(row=r, column=c, pady=4, padx=0)
            Entry(self.lowerframe, width=10).grid(row=r, column=c+1, pady=4, padx=0)
            Label(self.lowerframe, text=data[1]).grid(row=r, column=c+2, pady=4, padx=0)

    def create_btnframe(self):
        self.btnframe = Frame(self.master, width=130, height=200)
        self.btnframe.place(x=870, y=530)

    def create_inputbtn(self):
        self.create_btnframe()

        startanalysis_btn = Button(self.btnframe, text="Start Analysis", width=12, command=self.do_nothing)
        startanalysis_btn.place(x=0, y=0)

        abortanalysis_btn = Button(self.btnframe, text="Abort Analysis", width=12, command=self.do_nothing)
        abortanalysis_btn.place(x=0, y=50)

        resetanalysis_btn = Button(self.btnframe, text="Reset Analysis", width=12, command=self.do_nothing)
        resetanalysis_btn.place(x=0, y=100)

        showresults_btn = Button(self.btnframe, text="Show Results", width=12, command=self.do_nothing)
        showresults_btn.place(x=0, y=200, anchor=SW)

    def do_nothing(self):
        pass

root = Tk()

app = Window(root)

root.mainloop()

如您所见,下方蓝色框架(称为“lowerframe”)中的每个“集合”小部件由一个带有描述的标签(此处为“a”到“t”)、一个条目小部件和另一个标签组成具有相应输入值单位的小部件(此处为所有标签的“U”)。

使用这些“集合”,我需要创建 5 行和 4 个“集合列”(目前使用网格几何管理器的 12 列)。我的目标是将这些行和“设置列”分配到下框的指定高度和宽度。

-- 编辑:我将sketch 上传到我的 Dropbox 文件夹,显示结果应该是什么样子。

【问题讨论】:

    标签: python python-3.x tkinter grid


    【解决方案1】:

    您编写代码的方式使其很难修改。首先,根据经验,您永远不应该使用place。根本没有必要,因为packgrid 提供了更多功能。

    其次,作为另一个经验法则,父母应该负责布置其孩子——没有创建框架的函数也调用gridpackplace来放置自己在其父级中。如果你决定改变你的布局,你最终不得不改变一堆函数而不是一个。

    最后,在使用网格时,如果您希望行和列增长以填充其包含的窗口,则需要为行和列赋予“权重”。

    以下是我将如何重写您的代码:

    from tkinter import *
    
    class Window(Frame):
        def __init__(self, master=None):
            Frame.__init__(self, master)
            # create master window
            self.master = master
    
            # create root window on initialization
            self.create_rootwindow()
    
        def create_rootwindow(self):
            self.master.title("GUI")
            self.master.geometry("1024x748")
    
            self.create_upperframe()
            self.create_lowerframe()
            self.create_inputentries()
            self.create_btnframe()
            self.create_inputbtn()
    
            self.upperframe.pack(side="top", fill="both", expand=True, padx=4)
            self.lowerframe.pack(side="left", fill="both", expand=True, padx=4, pady=4)
            self.btnframe.pack(side="right", fill="both", padx=4, pady=4)
    
        def create_upperframe(self):
            self.upperframe = Frame(self.master, width=980, height=490)
            self.upperframe.config(background="#339900")
    
        def create_lowerframe(self):
            self.lowerframe = Frame(self.master, width=830, height=200)
            self.lowerframe.config(background="#336699")
    
        def create_inputentries(self):
            self.create_lowerframe()
    
            parameternames = [
                ('a', 'U'), ('b', 'U'), ('c', 'U'), ('d', 'U'), ('e', 'U'),
                ('f', 'U'), ('g', 'U'), ('h', 'U'), ('i', 'U'), ('j', 'U'),
                ('k', 'U'), ('l', 'U'), ('m', 'U'), ('n', 'U'), ('o', 'U'),
                ('p', 'U'), ('q', 'U'), ('r', 'U'), ('s', 'U'), ('t', 'U')]
    
            for i, data in enumerate(parameternames):
                r = i % 5
                c = (i // 5) * 3
                Label(self.lowerframe, text=data[0]).grid(row=r, column=c, pady=4, padx=0, sticky="nsew")
                Entry(self.lowerframe, width=10).grid(row=r, column=c+1, pady=4, padx=0, sticky="ew")
                Label(self.lowerframe, text=data[1]).grid(row=r, column=c+2, pady=4, padx=0, sticky="nswe")
    
                self.lowerframe.grid_columnconfigure(c+1, weight=1)
    
    
        def create_btnframe(self):
            self.btnframe = Frame(self.master, width=130, height=200)
    
        def create_inputbtn(self):
            self.create_btnframe()
    
            startanalysis_btn = Button(self.btnframe, text="Start Analysis", width=12, command=self.do_nothing)
            abortanalysis_btn = Button(self.btnframe, text="Abort Analysis", width=12, command=self.do_nothing)
            resetanalysis_btn = Button(self.btnframe, text="Reset Analysis", width=12, command=self.do_nothing)
            showresults_btn = Button(self.btnframe, text="Show Results", width=12, command=self.do_nothing)
    
            startanalysis_btn.pack(side="top", fill="x")
            abortanalysis_btn.pack(side="top", fill="x")
            resetanalysis_btn.pack(side="top", fill="x")
            showresults_btn.pack(side="top", fill="x")
    
        def do_nothing(self):
            pass
    
    root = Tk()
    app = Window(root)
    root.mainloop()
    

    注意事项:

    • 我已将 place 的所有用法替换为 pack(尽管 grid 也可以使用)
    • 创建后,我已将主要区域的packing 组合在一起
    • 我已将按钮的 packing 分组在一起,使其更易于可视化和修改
    • 我已为底部框架中具有条目小部件的列添加了权重。这会导致这些列增长或缩小以填充任何额外的空间
    • 我已将 resizable 设置为 false。一般来说,我认为应该允许用户选择 GUI 的大小。另外,它说明通过使用pack 和/或grid 而不是place,您无需任何额外努力即可获得正确的调整大小行为。如果你真的认为你比你的用户更了解,你可以把它放回去。

    代码现在具有良好的调整大小行为,条目小部件的网格扩展以填充其容器,并且函数的耦合不那么紧密,因为创建框架的函数不必知道该框架将如何显示。

    【讨论】:

    • 这解决了我的一半任务。小部件现在分布在框架的高度和宽度上。但是,我想指定条目小部件的宽度,并在每组“label-entry-label”之间获得一些自动分配的空间。目前,我无法为条目小部件指定宽度,或者至少不会影响当前设置中的任何内容。我将sketch 上传到我的 Dropbox 文件夹,显示我想要实现的目标
    • @albert:给那些你想有明确宽度的人一个明确的宽度,并为你想扩大或缩小的列使用非零权重。这里没有魔法,一切都是确定性的。如果您希望 个小部件之间具有可变宽度,请创建一个没有任何小部件的列,并为该列赋予一个权重。
    猜你喜欢
    • 2017-09-25
    • 1970-01-01
    • 1970-01-01
    • 2021-06-07
    • 2020-08-30
    • 1970-01-01
    • 2018-10-08
    • 2013-11-29
    • 2018-02-23
    相关资源
    最近更新 更多