Python 如何动态更新tkinter小部件的层?
特金特要求 因此,我对使用Python 如何动态更新tkinter小部件的层?,python,tkinter,Python,Tkinter,特金特要求 因此,我对使用tkinter比较陌生,我在这里遇到了一个非常具体的疑问。我试图找到解决办法,但我发现很明显,解决办法似乎并不容易理解。因此,如果您可以看到上面的图像,我正在尝试为一个需要多层(我称之为基于3D阵列)小部件的特定项目创建GUI。 假设此指针系统使用的变量是i、j和k 我正在使用for循环创建各个层小部件: for n in range(i): frame_x[i] = Frame(root).grid(row = 1, column = i) entr
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抛出namererror
说我不能在赋值之前使用变量
无论如何,请让我知道我如何有效地做到这一点。
总的来说,如果有更好的方法来处理整个事情的话。请参考上面的图片,如果没有意义请告诉我
总的来说,我不太喜欢上课。我更喜欢低效的方式,只使用函数来完成所有我必须做的事情。因此,如果您可以在不使用类的情况下与我共享一个框架,那就太好了。但如果你用它们也没关系。我知道我应该在某个时候开始学习课程。首先,我想解决这部分问题: 我猜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(…)
始终返回无。因此,frame_x[i]
将是None
下次执行entry\ux[i]=entry(frame\ux[i]).grid(…)
时,与执行entry\ux[i]=entry(None).grid(…)
时相同。由于条目的主项是None
,因此它成为根窗口的子项
因此,第一步是将小部件的创建与小部件的布局分开
frame_x[i] = Frame(root)
frame_x[i].grid(row = 1, column = i)
一旦您这样做,条目
和按钮
小部件将成为框架的子部件,您可以通过销毁框架(例如:frame\u x[i].destroy()
)删除您不想要的小部件,因为销毁小部件也会导致小部件的所有子部件被销毁
一旦设置好了,只需在框架上调用.destroy()
,就可以销毁不需要的小部件。例如,如果您以前创建了10个组,现在只需要5个,则可以销毁其他组,然后将其从列表中删除,如下所示:
# 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]
这里有一个完整的工作程序来说明。输入一个数字,然后单击按钮。它将创建许多帧+条目+按钮组合。输入一个较大或较小的新数字,它将添加或删除小部件
如果您使用类,这将更容易,但您特别要求提供一个不使用类的解决方案。在实际代码中,您可能还需要将条目小部件保存在一个数组中,以便以后可以引用它们,但本示例主要关注小部件的创建,而不是为您编写整个程序
import tkinter as tk
frames_x = [] def create_widgets():
global frames_x
num = int(num_widgets.get())
# if the number is less than the previous number of
# widgets, delete the widgets we no longer want
for frame in frames_x[num:]:
frame.destroy()
frames_x = frames_x[:num]
# if the number is greater than the previous number of
# widgets, create additional widgets
for i in range(len(frames_x), num):
# create new widget
frame = tk.Frame(root, bd=1, relief="raised")
entry = tk.Entry(frame)
button = tk.Button(frame, text="click me")
# pack entry and button in frame
button.pack(side="right")
entry.pack(side="left", fill="x", expand=True)
# grid the frame in the parent
frame.grid(row=i+1, column=0, columnspan=2)
# save the new frame in the array
frames_x.append(frame)
root = tk.Tk() num_widgets = tk.Entry(root) button = tk.Button(root, text="Create widgets", command=create_widgets)
button.grid(row=0, column=1) num_widgets.grid(row=0, column=0, sticky="ew")
root.mainloop()
您需要提供更多的代码,请参阅。我认为您可以通过为每个您所称的“层”创建单独的页面来处理此问题,这将允许您轻松地从一个切换到另一个以及删除它们。首先,请参见@Bryan Oakley的问题解答,以获取创建它们的示例。关于tkinter
在循环之前抛出namererror
,应该比较容易找到允许删除单个页面的方法。如果您无法知道这是否是第一次,请将销毁帧包装在一个块中,尝试/,但
块除外并忽略它。你还需要克服上课时的不适感,因为上课通常是最简单、更好的方式,而且并不难理解。只要把它们想象成可重用的代码“小部件”。@martineau:我谦恭地请求您不要推荐这种解决方案。这从来不是为初学者设计的通用起点。这一答案引发了数百个新问题。我写这篇文章时假设页面是静态的,并且使用该模式的人已经理解了tkinter。@martineau:老实说?我会说艾尔