I have a listBox in tkinter and 2 buttons. One of them delete the selected items in ListBox. If I select every items and y try delete them I get the follow error:
_tkinter.TclError: bad listbox index "0 1 2": must be active, anchor, end, @x,y, or a number
I don't find how I can to solve it.
This is my code:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Listas en tkinter")
root.columnconfigure(0, weight=4)
root.rowconfigure(0, weight=4)
def AgregarItem(event):
# Obtener elementos del listbox
elementos = lstProductos.get(0, tk.END)
# Combprobar si nuevo elemento existe en listbox
if item.get() in elementos:
tk.messagebox.showinfo(message="El elemento ya existe en la lista",
title="Error")
else:
lstProductos.insert(tk.END, item.get())
txtProducto.delete(0, "end")
def EliminarItem(event):
elementos = lstProductos.get(0, tk.END)
if elementos != ():
lstProductos.delete(lstProductos.curselection())
# Titulo
lblTitulo = ttk.Label(root, text="Lista de la compra")
lblTitulo.configure(font=("Arial", 24, 'bold'))
lblTitulo.grid(column=0, row=0, columnspan=4, padx=5, pady=5)
# Lista
lstProductos = tk.Listbox(root)
lstProductos.grid(column=0, row=1, rowspan=3, pady=5)
lstProductos.configure(selectmode="multiple")
# Scrollbar de la lista
scrollbar = ttk.Scrollbar(root, orient="vertical", command=lstProductos.yview)
scrollbar.grid(column=1, row=1, rowspan=3, sticky=tk.NS, pady=5)
lstProductos['yscrollcommand'] = scrollbar.set
# Etiqueta con instrucciones
lblInstrucciones = ttk.Label(root, text="Agregar: Introduce el nombre\ndel producto y pulsa Agregar\n\nEliminar: Selecciona producto\ny pulsa Eliminar")
lblInstrucciones.grid(column=2, row=1, columnspan=2, padx=5, pady=5)
# Cuadro de texto
item=tk.StringVar()
txtProducto = ttk.Entry(root, textvariable=item)
txtProducto.grid(column=2, row=2, columnspan=2, padx=5, pady=5)
# Boton agregar
botAgregar = tk.Button(root, text="Agregar item" )
botAgregar.grid(column=2, row=3)
botAgregar.bind('<Button-1>', AgregarItem)
# Boton eliminar
botEliminar = tk.Button(root, text="Eliminar item" )
botEliminar.grid(column=3, row=3)
botEliminar.bind('<Button-1>', EliminarItem)
root.mainloop()
Thanks
CodePudding user response:
The right way to delete a set of items in a listbox is by getting the list of selected indexes and then looping through it and then individually deleting them.
But there is a problem in that, if you delete the first selected index then you will notice the index positions of other elements below the deleted item now change too and hence deleting will not be proper. So you will have to delete from the bottom so the previous items do not get reindexed after deletion:
def EliminarItem(event):
elementos = lstProductos.get(0, tk.END)
items = lstProductos.curselection()
if elementos: # Same as `if elemntos != ()`
for i in items[::-1]: # items[::-1] will reverse the list
lstProductos.delete(i)
Note that you are using bind
with the buttons, which is absolutely unnecessary. You should really be using command
option of button, which will trigger the function when button is pressed.
# Boton agregar
botAgregar = tk.Button(root, text="Agregar item", command=AgregarItem)
botAgregar.grid(column=2, row=3)
... and don't forget to remove event
as a parameter in the functions as you are no longer passing it in.