我正在尝试编写一个基本的Tkinter GUI,其顶部有一个Text
窗口小部件,然后一个Button
窗口小部件在其下面对齐,然后另一个Text
窗口小部件位于按钮下方。我遇到的问题是,在将Button
窗口小部件打包到左侧后,当我再打包第二个Text
窗口小部件时,它将它放在右边的按钮旁边,而不是在下面按钮。无论我为第二个side
小部件设置Text
参数,都会发生这种情况。这是一段演示此行为的简单代码:
from Tkinter import *
root = Tk()
w = Text(root)
w.pack()
x = Button(root, text="Hi there!")
x.pack(side=LEFT)
y = Text(root)
y.pack(side=BOTTOM)
root.mainloop()
那么我该如何设置第二个Text
窗口小部件,使其显示在按钮下方而不是右侧?
答案 0 :(得分:15)
布局问题通常有两种解决方案:
切换到使用网格。像你想要完成的那样做布局真的很容易。网格可以解决所有布局问题的95%(当你想到它时,这是惊人的 - Tk与一位经理一起做大多数工具包需要完成的工作量!)
使用多个框架。如果某些小部件需要从上到下堆叠,而某些小部件需要从左到右堆叠,您无法始终获得所需的内容,将所有内容打包在一个框架中。布局的从上到下部分使用一个框架,从左到右内容使用其他框架。
还要意识到窗口小部件不一定是打包/网格化的窗口小部件的子窗口。您可以使用“in”参数将窗口小部件放在除父窗口之外的其他容器中。
例如,在您的具体示例中,您可以创建三个框架,顶部,中部,底部。在顶层窗口中将这些从上到下打包。然后,您可以将顶部的第一个文本小部件,中间的水平按钮或按钮打包,并将底部的另一个文本小部件打包。
这种方法的优势在于,它可以使未来更改布局变得更加容易(根据我的经验,总是在某些时候发生)。您不必重新设置任何窗口小部件,只需在其他容器中打包/放置/网格化即可。
在您的简短示例中,它没有太大区别,但对于复杂的应用程序,这种策略可以节省生命。
我最好的建议是:布局不是事后的想法。做一点计划,甚至花五分钟画一些方格纸。首先确定应用程序的主要区域,并为每个区域使用框架或其他容器(paned窗口,笔记本等)。一旦你拥有了这些,就为每个部分做同样的分而治之的方法。这使您可以为应用的不同部分使用不同类型的布局。工具栏可以获得水平布局,表单可以获得垂直布局等。
答案 1 :(得分:7)
我最初误解了包装是如何工作的,并没有意识到当我做x.pack(side=LEFT)
时,整个左侧都被“声称”了。我在阅读this之后找到的内容以及Alex在这里的答案是,我根本没有将x
打包到左侧,而是将其锚定左侧,使用anchor=W
(西方为W)而不是side=LEFT
。我修改后的代码片段完成了我的工作,如下所示:
from Tkinter import *
root = Tk()
w = Text(root)
w.pack()
x = Button(root, text="Hi there!")
x.pack(anchor=W)
y = Text(root)
y.pack(side=BOTTOM)
root.mainloop()
这种方式x
不再“声称”左侧,它只是在其空间区域内与左侧(或西侧)对齐。
答案 2 :(得分:3)
打包按照调用.pack方法的顺序进行,所以一旦x“声明”了左侧,就是它 - 它将占据其父节点的左侧部分,而其父节点中的所有其他节点将是它的对。你需要一个框架来“调解”,例如....:
from Tkinter import *
root = Tk()
w = Button(root, text="Mysterious W")
w.pack()
f = Frame(root)
x = Button(f, text="Hi there!")
x.pack()
y = Button(f, text="I be Y")
y.pack(side=BOTTOM)
f.pack(side=LEFT)
root.mainloop()
(将文本更改为按钮以便更直接地查看布局 - 此Mac上的Tkinter在获得焦点之前不会清晰显示文本,但按钮非常清晰; - )。
答案 3 :(得分:0)
以与WebView使用Mosaic Canvas Widget Sets内部构件(与Tk非常相似)相同的方式进行操作。诀窍在于,第二个相同的名为Frame Object的块级浮动对象(inline:block;)对于放置在其后的所有内容以及调用“ fr”的所有内容都将自动从其内部开始。
您可以执行许多TOP对齐的小部件操作,而只需在希望在side = LEFT之间中断的地方添加另一个相同的命名Frame。在Bottom之后也可以使用。
fr=Frame(root)
fr.pack(fill=X, side=TOP)
block1=Label(fr)
block1.pack(side=LEFT)
block2=Label(fr)
block2.pack(side=LEFT)
block3=Button(fr)
block3.pack(side=LEFT)
# NAME IT THE SAME ID NAME AS THE FIRST MAIN FRAME...
fr=Frame(root)
fr.pack(fill=X, side=TOP)
# These NOW jump into the second Frame breaking the side=LEFT in new Frame
block4=Label(fr)
block4.pack(side=LEFT)
block5=Label(fr)
block5.pack(side=LEFT)
# AND THEY CONTINUE GOING side=LEFT AFTERWARDS.