如何让tkinter pack_forget调整父框架的大小?

时间:2017-02-13 23:59:17

标签: python tkinter

在使用tkinter的python(2.7.12)中,我尝试实现以下功能:我想动态隐藏和取消隐藏某些文本标签。我尝试使用pack_forget,然后再次执行pack。我即将隐藏和取消隐藏的标签位于其他标签之间的固定位置(相对位置)。当标签被隐藏时,它们不会占用空间。

例如,考虑一个标签,其中“not”文字作为句子的一部分出现或消失。句子的其他部分也将形成标签。因此,我不能简单地在{not}标签上使用pack_forget后跟packpack不会将标签放在其先前的位置,而是放在装箱单的末尾

因此,为了确保标签保持其相对位置(并避免重新包装所有内容),我执行以下操作:我创建一个框架,将其打包在我的标签应出现/消失的位置,然后放置标签里面。然后,我隐藏/取消隐藏标签,但不隐藏框架。

我的期望是,框架的大小应根据内部标签是否隐藏来自行调整。当然,当标签可见时,框架应足够大以容纳它。但是,在标签上调用pack_forget后,框架的大小应该再次缩小为零。

然而,这不起作用:最初,框架实际上没有大小。但是,在内部的文本标签可见一次后,框架会保持其大小。在框架内的标签上调用pack_forget后,标签的文本实际上消失了,但框架不会缩小到零。

我做错了什么?

这是一个完整的代码示例(改编自example by Tony Veijalainen)。在我的系统上至少它显示了行为,文本实际上消失了,但框架保持其宽度(和高度),这不应该是这种情况。

from Tkinter import *

def toggle():
    if label.winfo_ismapped():
        button['text']='unmap'
        label.pack_forget()
    else:
        button['text']='map'
        label.pack()

root = Tk()
button = Button(text="Push me", command=toggle)
button.pack()
labelFrame = Frame()
labelFrame.pack()
label = Label(labelFrame, text="Hello Big Big World")
label.pack()
root.wait_window()

如果您在示例中删除labelFrame并直接创建label作为root的子项,则一切正常:隐藏的标签确实占用零空间。

3 个答案:

答案 0 :(得分:1)

当您在容器中的最后一个窗口小部件上调用pack_forget时,容器会看到它没有子容,因此放弃了管理容器大小的责任。

一个简单的黑客攻击是在容器中打包1x1小部件。这样做会触发pack调整容器以使其适合,从而导致容器缩小。

pack具有允许您在其他窗口小部件之前或之后放置它的选项,因此您可以始终在隐藏窗口小部件之后跟踪窗口小部件,以便稍后将其还原到正确的位置。

您也可以切换为使用grid代替pack,因为grid可以记住每个小部件的相对位置。

答案 1 :(得分:0)

说我们有两个框架和一个像这样的根

frame2 |框架1 |根

如果您想隐藏它

protected override void WndProc(ref Message m) {
    base.WndProc(ref m);

    if(m.Msg == 0x0047) {   // WM_WINDOWPOSCHANGED = 0x0047 
        if (SelectionLength != 0) {
            SelectionLength = 0;
        }
    }
}

要调整其他小部件的大小,请执行此操作(lstb位于frame1中)

self.frame2.pack(side='left', fill=tk.Y)

在根中,我也有一个文本

self.frame1.pack(side='left', fill=tk.Y)
self.lstb.pack(fill=tk.Y, expand=1)

当我隐藏frame1时,其他2个(带有列表框的fram1和带有Text的root)将调整自身大小。框架的唯一问题是您不能通过pack()使它们再次可见。您可以使其他小部件再次可见,但是如果您打包_忘记它们,其他小部件将不会调整大小。我还没有找到一种使框架恢复可见性的解决方案。

答案 2 :(得分:0)

更新:毕竟有beforeafter pack()个选项!我不确定它们在哪个版本的Tkinter上可用,但它们至少在Py3.6和更高版本中可用。我在effbot.org上没有看到此消息,但我根据Bryan Oakley的答案进行了更深入的研究。

原件: 令人失望的是,before方法没有afterpack()选项。但是,如果您决定使用包管理器而不是网格管理器,则可以根据需要pack_forget()使用所需的窗口小部件。当需要将它们放回原处时,您可以解决打包限制,方法是简单地忘记其余的小部件,然后按所需顺序重新包装所有小部件。这可能不理想,但可以完成工作。