抱歉标题含糊,但我不知道如何更好地解释自己。基本上我在 tkinter 中尝试做的是添加和删除标签。标签值会更新,因此即使我一开始删除了标签,我的增量也始终为 1。如果我生成标签并从下往上删除它们,我没有问题,但如果我从中间删除一个标签,然后尝试清理我的列表,我会收到错误:
Exception in Tkinter callback
Traceback (most recent call last):
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 1536, in __call__
return self.func(*args)
File "/Users/XXXX/Helper/development/dynamicListLabels.py", line 21, in <lambda>
labelList[index].append(ttk.Button(root, text="Remove", command=lambda: removeLabel(labelList[index][0], index)))
IndexError: list index out of range
我的Python代码如下所示:
#!/usr/bin/python
from Tkinter import *
import ttk
def removeLabel(labelToRemove, bla):
labelList[labelToRemove.get()][1].destroy()
labelList[labelToRemove.get()][2].destroy()
del labelList[labelToRemove.get()]
for label in labelList:
index = labelList.index(label)
label[0].set(index)
def addNewLabel():
labelList.append([IntVar()])
index = len(labelList) - 1
labelList[index][0].set(index)
labelList[index].append(ttk.Label(root, textvariable=labelList[index][0]))
labelList[index].append(ttk.Button(root, text="Remove", command=lambda: removeLabel(labelList[index][0], index)))
labelList[index][1].grid(column=0)
labelList[index][2].grid(column=1, row=labelList[index][1].grid_info()['row'])
root = Tk()
labelList = []
ttk.Button(root, text="add label", command=addNewLabel).grid(column=1, row=0)
root.mainloop()
我的 GUI 看起来像这样:
感谢您的帮助!
最佳答案
设计
主要问题出现在处理不同的索引时。尝试小心地操作它们会导致复杂的操作,从而导致代码冗长且低效。为了解决这个问题,我们只需摆脱它们并利用您已经使用的标签类变量
Tkinter.IntVar()
。这使我们能够完全控制标签和关联的小部件。另一个避免令人头疼的有效决定是将每个(标签、按钮)对小部件附加到唯一的
Tkinter.Frame()
实例。这提供了使用destroy()
删除帧的优点。方法会自动导致其包含的小部件被破坏。同时,这可以保持 GUI 的外观并使其成为您的 scalable因为它为您提供了添加更多小部件的可能性。
设计addNewLabel()
与您的原始代码相比,这里没有什么新内容,除了我在 2 中所说的。每个(标签,按钮)对都将被绘制到一个唯一的 Tkinter.Frame()
实例中。当然,列表框架必须在此方法中声明为全局的。
设计removeLabel()
从 1 开始,我们需要传递给 removeLabel()
的唯一参数是我们想要获取的标签固有的 Tkinter 变量(下面代码中的 var
)摆脱。
然后我们需要使用 winfo_children()
循环遍历帧列表(下面代码中的frames
)寻找具有我们正在寻找的文本变量的标签。
请注意because我在各个框架内的按钮之前绘制标签,winfo_children()
返回标签作为第一个小部件列表元素
winfo_children():
Returns a list containing the path names of all the children of window. Top-level windows are returned as children of their logical parents. The list is in stacking order, with the lowest window first, except for Top-level windows which are not returned in stacking order. Use the wm stackorder command to query the stacking order of Top-level windows.
这就是为什么正确编写:ifframe.winfo_children()[0].var == var
并销毁包含满足此条件的标签的框架。
解决方案
这是程序。我评论了我认为值得评论的几行:
'''
Created on Jun 25, 2016
@author: billal begueradj
'''
from Tkinter import *
import ttk
def removeLabel(var):
global frames
z = -1
# Loop over the list of rames
for frame in frames:
z = z + 1
# Check the text variable of the label of this frame
if frame.winfo_children()[0].var == var:
# Destroy the related frame
frame.destroy()
# Update the size of the list of frames
frames = frames[:z] + frames[z+1:]
# Do not forget to always rest this flag back to -1
z = -1
# Update the labels' numbers
r = 0
for frame in frames:
frame.winfo_children()[0].var.set(r)
r = r + 1
def addNewLabel():
global frames, i
var = IntVar()
frame = Frame(root)
i = i + 1
frame.grid(row=i, column=0)
var.set(len(frames))
l = ttk.Label(frame, textvariable=var)
l.grid(row=0, column=0)
l.var = var
b = ttk.Button(frame, text="Remove", command=lambda: removeLabel(var))
b.grid(row=0, column=1)
frames.append(frame)
if __name__ == '__main__':
root = Tk()
frames = []
i = 1
ttk.Button(root, text="add label", command=addNewLabel).grid(column=0, row=0)
root.mainloop()
演示
让我们创建 6 个标签:
现在让我们删除标签编号3。您可以看到标签的编号已自动更新:
现在让我们添加一个新标签。您可以看到新添加的标签的编号与列表中最后一个现有标签编号连续:
请注意,列表的长度会根据您的需要随时更新。
关于python - 以编程方式添加和删除 tkinter python 标签会导致 IndexError : list index out of range,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38006251/