python - 以编程方式添加和删除 tkinter python 标签会导致 IndexError : list index out of range

标签 python python-2.7 tkinter ttk

抱歉标题含糊,但我不知道如何更好地解释自己。基本上我在 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 看起来像这样:

enter image description here

感谢您的帮助!

最佳答案

设计

  1. 主要问题出现在处理不同的索引时。尝试小心地操作它们会导致复杂的操作,从而导致代码冗长且低效。为了解决这个问题,我们只需摆脱它们并利用您已经使用的标签类变量 Tkinter.IntVar() 。这使我们能够完全控制标签和关联的小部件。

  2. 另一个避免令人头疼的有效决定是将每个(标签、按钮)对小部件附加到唯一的 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 个标签:

enter image description here

现在让我们删除标签编号3。您可以看到标签的编号已自动更新:

enter image description here

现在让我们添加一个新标签。您可以看到新添加的标签的编号与列表中最后一个现有标签编号连续:

enter image description here

请注意,列表的长度会根据您的需要随时更新。

关于python - 以编程方式添加和删除 tkinter python 标签会导致 IndexError : list index out of range,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38006251/

相关文章:

python - 编程新手,无法打开我的主窗口

python - 如何返回多列和限制行

python - 使用python opencv进行预处理以查找两个图像之间的差异

python - 如何在Python中动态引用变量?

python - 检索 ttk.Treeview 项目的 'open' 选项作为 bool 值

Python 3.4.4 在 Tkinter 中设置参数?

python - 如何设置 DJANGO_SETTINGS_MODULE 环境变量?

python - 如何检查requirements.txt文件中包含哪些包?

python - 为什么安装mysqlclient时显示错误?

python - 如何修改csv文件中的重复字段?