如何动态更新tkinter小部件的图层?

时间:2018-11-06 11:39:44

标签: python tkinter

Tkinter要求

diagram showing tkinter layout

因此,我对使用tkinter还是比较陌生的,我在这里遇到一个非常具体的疑问。我试图找到解决方案,但就我看来显而易见的是,解决方案似乎并不容易理解。因此,如果您可以看到上面的图像,我正在尝试为需要多层(我称其为基于3D数组的)小部件的特定项目创建GUI。 假设用于此指针系统的变量为 i j k

我正在使用for循环创建单个图层小部件:

for n in range(i):
    frame_x[i] = Frame(root).grid(row = 1, column = i)
    entry_x[i] = Entry(frame_x[i]).grid(row = 2, column = i)
    button_x[i] = Button(frame_x[i]).grid(row=3, column = i)

请注意,这不是功能代码,为了使我对所使用的方法有所了解,我尝试将其保持在正确的位置。 (如果您需要更详细的代码块,请告诉我。)

现在要解决这个问题。我能够做到这一点的基本部分。但是问题是我希望它动态地工作。

假设用户首先输入j = 4。将创建4个块。 稍后,如果他将值更改为j = 2并按下按钮,则理想情况下,它将使块j = 3和4处的小部件消失。但是我猜想tkinter是在重叠的基础上工作的,并且直到有特定的重叠元素时,网格元素才会改变。我怎么做。我尝试在进入for循环后立即销毁整个框架,但这无法正常工作,因为第一次销毁之前未创建任何小部件,并且python抛出NameError说我不能使用变量在分配之前。

无论如何,请让我知道如何有效地做到这一点。 而且总的来说,如果有更好的方法可以解决整个问题。请参考上面的图片,如果没有用,请告诉我。

我对一般的课程不太满意。我更喜欢低效的方式,仅使用函数来完成我必须做的所有事情。因此,如果您可以不使用类就共享给我一个框架,那就太好了。但是,如果您使用它们,也可以。我知道我应该在某个时候开始上课。

1 个答案:

答案 0 :(得分:1)

首先,我要解决问题的这一部分:

  

我想tkinter可以在重叠的基础上工作,并且直到有特定的重叠在网格元素上才改变。

我不能完全确定您的意思,但是如果它代表我的意思,那是错误的陈述。 tkinter不会“重叠工作”。如果销毁小部件,则该小部件也将销毁。重叠与否无关紧要。


基于您发布的一小段代码,主要问题是您没有将输入和按钮放在框架中。因此,在销毁框架时不会销毁它们。

不将小部件放入框架的原因是因为以下这一行:

frame_x[i] = Frame(root).grid(row = 1, column = i)

在python中,当您执行x=y().z()时,x的值为z()。因此,当您执行frame_x[i] = Frame(...).grid(...)时,frame_x[i]的值为.grid(...),并且.grid(...) 总是返回None 。因此,frame_x[i]将是None

下次执行entry_x[i] = Entry(frame_x[i]).grid(...)时,与执行entry_x[i] = Entry(None).grid(...)相同。由于Entry的主文件是None,因此它成为根窗口的子项。

因此,第一步是将小部件的创建与小部件的布局分开。

frame_x[i] = Frame(root)
frame_x[i].grid(row = 1, column = i)

一旦这样做,EntryButton小部件将成为框架的子级,您可以通过销毁框架来删除不需要的小部件(例如:{{1} }),因为销毁小部件也会导致该小部件的所有子级都被销毁。

一旦安装到位,只需在框架上调用frame_x[i].destroy(),即可销毁不需要的小部件。例如,如果您以前创建了10个组,现在只需要5个,则可以销毁其他组,然后将其从列表中删除,如下所示:

.destroy()

这里是一个完整的工作程序来说明。输入一个数字,然后单击按钮。它将创建许多frame + entry + button组合。输入一个更大或更小的新数字,它将添加或删除小部件。

如果您使用类,这会更容易,但是您特别要求一种不使用类的解决方案。在实际的代码中,您可能还需要将条目小部件保存在数组中,以便以后可以引用它们,但是此示例着重于小部件的创建,而不是为您编写整个程序。

# assume 'num' contains the number of frames that we want,
# and that it is smaller than the number of items in frames_x
for frame in frames_x[num:]:
    frame.destroy()
frames_x = frames_x[:num]