Tkinter pack() 几何管理器混乱

Tkinter pack() geometry manager confusion

就在我以为我理解了pack()经理的时候,我遇到了以下问题:

我创建了两个框架(每个框架都有一个 Button)并想将它们水平打包到另一个框架(即 'main' 框架)中。由于某种原因,它们垂直出现。如果我用一个简单的按钮替换第一帧,按钮 + 第二帧 水平打包,使用相同的 pack() 指令。

这是该程序的提炼(但有效)版本:

from Tkinter import *

class QuitBtn1(Button):
    def __init__(self):
        Button.__init__(self)
        self["text"] = "Quit"
        self["fg"] = "red"
        self["command"] = self.quit

class QuitBtn(Frame):
    def __init__(self):
        Frame.__init__(self)

        b = Button(text = "Quit", fg = "red", command = self.quit)
        b.pack()

class HiBtn(Frame):
    def __init__(self):
        Frame.__init__(self)

        b = Button(text = "Hi there", fg = "blue", command = self.quit)
        b.pack()

class App(Frame):
    def __init__(self, master = None):
        Frame.__init__(self, master)
        self.pack()
        self.createWidgets()

    def say_hi(self):
        print "hi there, everyone!"

    def createWidgets(self):
        self.QUIT = QuitBtn().pack(side = LEFT)
        self.hi_there = HiBtn().pack(side = LEFT)


root = Tk()
app = App(master = root)
app.mainloop()
root.destroy()

与运行一样,它生成两个垂直打包的帧。只需切换 QuitBtn1QuitBtn 的名称(将框架更改为一个简单的按钮),将包装更改为水平。

我看过几十个例子,它们似乎以某种方式避免了这种确切的结构。我是不是做错了什么?

一种方法是使用 in_= 参数告诉 pack 您想要将每个小部件打包到什么中。所以:

from Tkinter import *

class QuitBtn(Frame):
    def __init__(self):
        Frame.__init__(self)

        b = Button(text = "Quit", fg = "red", command = self.quit)
        b.pack(in_=self)                                                   # Here

class HiBtn(Frame):
    def __init__(self):
        Frame.__init__(self)

        b = Button(text = "Hi there", fg = "blue", command = self.quit)
        b.pack(in_=self)                                                   # Here

class App(Frame):
    def __init__(self, master = None):
        Frame.__init__(self, master)
        self.pack()
        self.createWidgets()

    def say_hi(self):
        print "hi there, everyone!"

    def createWidgets(self):
        self.QUIT = QuitBtn().pack(side = LEFT)       
        self.hi_there = HiBtn().pack(side = LEFT)      


root = Tk()
app = App(master = root)
app.mainloop()
root.destroy()

在框架内生成水平排列的按钮(每个按钮都在 App 框架内)。

我认为我自己从来不需要这个,但我也不记得曾经使用顶级 类 声明小部件。

附带说明一下,非常感谢您提供演示相同问题的精简版代码!我希望这更常见。

问题是您没有为任何小部件提供父级,因此它们都默认为根 window。即使您认为按钮在框架内,但它们不是。

因为 pack 的默认设置是将东西放在顶部,所以当您在按钮上调用 pack() 时,它们会堆叠在根 window 中。您的两个框架,因为其中没有任何内容,所以大小为 1x1,因此您看不到它们。 在左边打包,就是看不到而已。

解决方案是正确嵌套您的小部件。例如:

class QuitBtn(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)

        b = Button(self, text = "Quit", fg = "red", command = self.quit)
        b.pack()

def createWidgets(self):
    self.QUIT = QuitBtn(self)
    ...
    self.QUIT.pack(side = LEFT)
    ...

上面在 QuitBtn 框架内创建了一个按钮小部件,并将其打包到该框架的顶部。稍后,该框架(及其内容)将被打包到主框架的左侧。

将小部件的创建与小部件的布局分开也很重要。当您执行类似 self.QUIT = QuitBtn(...).pack(...) 的操作时,self.QUIT 将被设置为 None,因为这就是 pack(...) returns。另外,根据我的经验,将给定包含框架的所有布局移动到单独的块中可以更轻松地管理布局。