如何将 tkinter 小部件打包到已打包到左侧的现有小部件下方?
我正在尝试编写一个基本的 Tkinter GUI,它的顶部有一个 Text
小部件,然后是一个在其下方左对齐的 Button
小部件,然后是另一个 Text 按钮下方的小部件。我遇到的问题是,将
Button
小部件打包到左侧后,当我打包第二个 Text
小部件时,它会将其放在按钮旁边右侧,而不是按钮下方。无论我为第二个 Text
小部件设置什么 side
参数,都会发生这种情况,这是演示此行为的一段简单代码:
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
小部件,以便它出现在按钮下方,而不是按钮右侧?
I'm attempting to write a basic Tkinter GUI that has a Text
widget at the top, then a Button
widget left aligned under it, then another Text
widget underneath the button. The problem I'm having is, after packing the Button
widget to the left, when I then go to pack the second Text
widget, it puts it next to the button on the right, rather than underneath the button. This happens regardless of what I set the side
argument to for the second Text
widget Here's a simple piece of code that demonstrates this behaviour:
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()
So how would I go about setting up the second Text
widget so that it appears below the button, rather than to the right of it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
布局问题通常有两种解决方案:
改用网格。完成您想要完成的布局变得非常容易。网格可以解决大约 95% 的布局问题(仔细想想,这真是太神奇了 —— Tk 只需要一个管理器就能完成大多数工具包需要六个管理器才能完成的工作!)
使用多个框架。如果某些小部件需要从上到下堆叠,而另一些小部件需要从左到右堆叠,那么您并不总能获得所需的内容,将所有内容打包在一个框架中。对布局的从上到下部分使用一个框架,对从左到右的内容使用附加框架。
还要意识到小部件不必是它们被打包/网格化的小部件的子代。您可以使用“in”参数将小部件放入其父容器之外的其他容器中。
例如,在您的具体示例中,您可以创建三个框架:顶部、中间、底部。将这些从上到下打包在您的顶层窗口中。然后,您可以将第一个文本小部件打包在顶部,将一个或多个按钮水平打包在中间,将另一个文本小部件打包在底部。
这种方法的优点是,它使将来更改布局变得更加容易(根据我的经验,这种情况总是在某个时刻发生)。您不必重新设置任何小部件的父级,只需将它们打包/放置/网格化到其他容器中即可。
在您的简短示例中,它没有太大区别,但对于复杂的应用程序,此策略可以成为救星。
我最好的建议是:布局不是事后的想法。做一些计划,甚至可能花五分钟在方格纸上画画。首先决定应用程序的主要区域,并为每个区域使用框架或其他容器(窗格窗口、笔记本等)。一旦掌握了这些,就对每个部分执行相同的分而治之的方法。这使您可以为应用程序的不同部分使用不同类型的布局。工具栏采用水平布局,表单可能采用垂直布局等。
There are generally two solutions to layout problems:
switch to using grid. It becomes real easy to do layouts like what you are trying to accomplish. Grid can solve probably 95% of all layout issues (it's amazing when you think about it -- Tk does with one manager what most toolkits need half a dozen to accomplish!)
use multiple frames. If some widgets need to be stacked top-to-bottom and some left-to-right you can't always get what you want packing everything in a single frame. Use one frame for the top-to-bottom parts of the layout and additional frames for the left-to-right content.
Also realize that widgets don't have to be children of the widget in which they are packed/gridded. You can use the "in" parameter to put widgets in some other container than their parent.
For example, in your specific example you can create three frames, top, middle, bottom. Pack these top-to-bottom in your toplevel window. Then you can pack the first text widget in the top, the button or buttons horizontally in the middle, and the other text widget in the bottom.
The advantage to such an approach is that it makes it much easier to change the layout in the future (which in my experience always happens at some point). You don't have to re-parent any of your widgets, just pack/place/grid them in some other container.
In your short example it doesn't make much difference, but for complex apps this strategy can be a life saver.
My best advice is this: layout isn't an afterthought. Do a little planning, maybe even spend five minutes drawing on some graph paper. First decide on the major regions of your app and use a frame or some other container for each (paned window, notebook, etc). Once you have those, do the same divide-and-conquer approach for each section. This lets you use different types of layout for different sections of your app. Toolbars get horizontal layout, forms might get vertical layout, etc.
我最初误解了打包的工作原理,并且没有意识到当我执行
x.pack(side=LEFT)
时,整个左侧都被“声明”。阅读 this 和 Alex 的答案后我发现我并不是真的在x
完全位于左侧,而是将其锚定到左侧,使用anchor=W
(W 代表西)而不是side=LEFT
。我修改后的代码片段看起来像这样:这样
x
不再“声明”左侧,它只是在其空间块内向左(或西)对齐。I was initially misunderstanding how packing worked and didn't realise that the entire left side was being "claimed" when i did
x.pack(side=LEFT)
. What I found after reading this and the answer by Alex here is that I was not really after havingx
packed to the left side at all, but rather having it anchored to the left, usinganchor=W
(W for West) instead ofside=LEFT
. My revised code snippet which does what I was after looks like this:This way
x
is not "claiming" the left side anymore, it's just aligned to the left (or West) within its block of space.打包按照调用 .pack 方法的顺序进行,因此一旦 x “声明”了左侧,就这样了——它将占据其父级的左侧部分,而其父级中的其他所有内容都将位于其右侧。您需要一个框架来“调解”,例如...:(
将文本更改为按钮只是为了更直接地查看布局 - 这台 Mac 上的 Tkinter 在文本获得焦点之前不会清楚地显示文本,但按钮非常清晰; -)。
Packing happens in the order the .pack methods are called, so once x has "claimed" the left side, that's it -- it will take up the left portion of its parent and everything else within its parent will be to its right. You need a Frame to "mediate", e.g....:
(changed Texts to Buttons for more immediate visibility of layout only -- the Tkinter on this Mac doesn't show Texts clearly until they have focus, but Buttons are quite clear;-).
使用与 WebView 相同的方式使用 Mosaic Canvas Widget Sets 内部结构(与 Tk 非常相似)。诀窍是,第二个相同的命名框架对象作为块级浮点(inline:block;),用于放置在其后面的所有内容,并且所有调用“fr”的内容都将自动在其内部开始。
您可以让许多 TOP 对齐的小部件执行此操作,只需在要在 side=LEFT 之间中断的位置添加另一个相同的命名框架即可。也可在 Bottom 之后工作。
Do it the same way that WebView does using the Mosaic Canvas Widget Sets internals(which are very similar to Tk). The trick is that the second identical named Frame Object works as a Block Level Float(inline:block;) for everything placed after it and everything that calls "fr" already will automatically begin over inside of it.
You can have many doing this of TOP aligned widgets and simply add another identical named Frame where you want to break between side=LEFT's. Works after Bottom also.