以编程方式添加和删除tkinter python标签会导致Indexer:list索引超出范围
很抱歉标题含糊不清,但我不知道如何更好地解释自己。基本上,我在tkinter中尝试做的是添加和删除标签。标签值得到更新,因此即使我在开始时删除了一个标签,我的增量始终为1。如果我生成标签并从下往上删除它们,我没有问题,但如果我从中间删除一个标签,然后尝试清理我的列表,我会得到一个错误:以编程方式添加和删除tkinter python标签会导致Indexer:list索引超出范围,python,python-2.7,tkinter,ttk,Python,Python 2.7,Tkinter,Ttk,很抱歉标题含糊不清,但我不知道如何更好地解释自己。基本上,我在tkinter中尝试做的是添加和删除标签。标签值得到更新,因此即使我在开始时删除了一个标签,我的增量始终为1。如果我生成标签并从下往上删除它们,我没有问题,但如果我从中间删除一个标签,然后尝试清理我的列表,我会得到一个错误: Exception in Tkinter callback Traceback (most recent call last): File "/opt/local/Library/Frameworks/Pyt
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
我的GUI如下所示:
#!/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()
谢谢你的帮助 设计
Tkinter.IntVar()
。这使我们能够完全控制标签和相关的小部件Tkinter.Frame()
实例上,这样可以避免麻烦。这提供了使用方法删除框架的优势,该方法会自动销毁框架中包含的小部件。同时,这保持了GUI的外观,并使您的应用程序更加灵活,因为它为您提供了添加更多小部件的可能性addNewLabel()
与您的原始代码相比,这里没有什么新的东西,除了,正如我在2中所说的。每个(标签、按钮)耦合将被绘制到一个唯一的Tkinter.Frame()
实例中。当然,在这个方法中,列表框架必须声明为全局的
设计移除标签()
从1。我们需要传递给removeLabel()
的唯一参数是我们想要去除的标签固有的Tkinter变量(var
)
然后,我们需要使用在帧列表上循环(frames
,在下面的代码中),以查找包含我们正在查找的文本变量的标签
请注意,我在各个帧中的按钮之前绘制标签,winfo_children()
将标签作为第一个小部件列表元素返回
winfo_children():
返回一个列表,其中包含窗口所有子级的路径名。顶级窗口作为其逻辑窗口的子窗口返回
父母列表按堆叠顺序排列,首先是最低的窗口,
顶层窗口除外,这些窗口不按堆叠顺序返回。
使用wm stackorder命令查询顶层的堆叠顺序
窗户
这就是为什么写入:if frame.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。您可以看到标签的编号会自动更新:
现在让我们添加一个新标签。您可以看到新添加的标签具有一个与列表中最后一个现有标签编号连续的编号:
请注意,列表的长度会根据您的需要随时更新。只是一个提示,现在它不会更新标签号,如果您添加或删除两次,您将得到多个相同编号的标签。是的,这不会减少列表大小并更新标签的IntVar()。是的,您是对的,这一次,我仅仅依靠Tkinter变量的内容来避免混乱@LafexlosWOW感谢这个惊人的解释。我仍然试图完全理解一切,但嘿,我在这里学习。非常感谢您的时间Billal BEGUERADJ和@Lafexlos!顺便说一句,我不知道你可以用你的方式(l.var=var)将一个变量/属性添加到一个小部件中。这真方便!