简体   繁体   English

如何在已打包到左侧的现有小部件下方打包 tkinter 小部件?

[英]How to pack a tkinter widget underneath an existing widget that has been packed to the left side?

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.我正在尝试编写一个基本的 Tkinter GUI,它的顶部有一个Text小部件,然后一个Button小部件在其下方左对齐,然后是Button下方的另一个Text小部件。 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.我遇到的问题是,在将Button小部件打包到左侧之后,当我再打包第二个Text小部件时,它会将其放在右侧的按钮旁边,而不是按钮下方。 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:无论我为第二个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()

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?那么我将如何设置第二个Text小部件,使其出现在按钮下方,而不是它的右侧?

There are generally two solutions to layout problems:布局问题一般有两种解决方案:

  1. 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!) Grid 可以解决大约 95% 的所有布局问题(当您想到它时,这真是太神奇了——Tk 只需一个经理就可以完成大多数工具包需要六个才能完成的工作!)

  2. 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.您可以使用“in”参数将小部件放入其父容器之外的其他容器中。

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.工具栏采用水平布局,表单可能采用垂直布局等。

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) .我最初误解了包装是如何工作的,并且没有意识到当我执行x.pack(side=LEFT)时整个左侧都被“声明”。 What I found after reading this and the answer by Alex here is that I was not really after having x packed to the left side at all, but rather having it anchored to the left, using anchor=W (W for West) instead of side=LEFT .我在阅读这篇文章和 Alex 在这里的回答后发现的是,我并不是真的在将x打包到左侧之后,而是将它锚定到左侧,使用anchor=W (W 代表西方)而不是side=LEFT My revised code snippet which does what I was after looks like this:我修改后的代码片段看起来像这样:

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()

This way x is not "claiming" the left side anymore, it's just aligned to the left (or West) within its block of space.这样x不再“声称”左侧,它只是在其空间块内与左侧(或西部)对齐。

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.打包是按照 .pack 方法被调用的顺序进行的,所以一旦 x 已经“声明”了左侧,就是这样——它将占据其父级的左侧部分,而其父级中的所有其他内容都将在其右侧。 You need a Frame to "mediate", eg...:您需要一个框架来“调解”,例如...:

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()

(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;-). (将 Texts 更改为 Buttons 仅用于更直接的布局可见性-此 Mac 上的 Tkinter 在获得焦点之前不会清楚地显示 Texts,但 Buttons 非常清晰;-)。

Do it the same way that WebView does using the Mosaic Canvas Widget Sets internals(which are very similar to Tk).使用 Mosaic Canvas Widget Sets 内部组件(与 Tk 非常相似)的方式与 WebView 相同。 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.诀窍在于,第二个相同命名的框架对象作为块级浮点(inline:block;)用于放置在它之后的所有内容,并且已经调用“fr”的所有内容将自动在其内部重新开始。

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.您可以让许多 TOP 对齐的小部件执行此操作,只需添加另一个相同的命名框架,您希望在 side=LEFT 之间断开。 Works after Bottom also.在底部之后也有效。

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.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM