1

Tengo un problema al crear una clase para hacer listbox's no puedo "individualizar" las listbox's que creo con mi clase y esto no me deja manipularlas a mi antojo, como en la parte de listBox1.insert(0,"Prueba") que me salta error, ¿como podría solucionarlo?

Mi codigo:

from tkinter import Entry
from tkinter import Listbox
from tkinter import Menu
from tkinter import Button
from tkinter import RAISED
from tkinter import Tk
from tkinter import Label
import tkinter as tk
import ctypes
from tkinter import messagebox
from tkinter.font import Font

ventana1 = tk.Tk()

class editlistBox(tk.Listbox):
    def __init__(self,listbox,ventana,posx,posy):

        self.ventana = ventana
        self.listbox = Listbox(self.ventana,width=27)
        self.listbox.config(borderwidth=2,highlightthickness=4,highlightcolor="#0000ff",selectforeground="#ffffff",selectbackground="#00aa00",selectborderwidth=2,font=Font(family="Sans Serif", size=10),activestyle=tk.NONE)
        self.listbox.bind('<Double-Button-1>', self.dobleClick)
        self.listbox.place(x=posx,y=posy)

    def dobleClick(self,_):
        if self.listbox.size() > 0:
            self.listbox.config(state="disabled",disabledforeground="#A2A2A2")
            global select
            select = self.listbox.curselection()

            _, y, _, h = self.listbox.bbox(self.listbox.curselection())
            x = self.listbox.winfo_x()+5
            y += self.listbox.winfo_y()
            w = self.listbox.winfo_width() - 12

            global entrylistBox
            valor = self.listbox.get(self.listbox.curselection())
            entrylistBox = Entry(self.ventana)
            entrylistBox.config(font=Font(family="Sans Serif", size=10))
            entrylistBox.focus_set()
            entrylistBox.place(x=x,y=y,width=w,height=h)
            entrylistBox.config(highlightthickness=1,highlightcolor="green")
            entrylistBox.insert(0,valor)
            entrylistBox.bind('<Return>', self.keyEnter)
            self.listbox.insert(0,1)


    def keyEnter(self,_):
        entrylistBox.place_forget()
        self.listbox.config(state="normal")
        valor_ = entrylistBox.get()
        self.listbox.delete(select)
        self.listbox.insert(select,valor_)

listBox1 = editlistBox("name",ventana1,10,30)

listBox1.insert(0,"Prueba")

ventana1.mainloop()
Franco
  • 1,075
  • 4
  • 20
  • Hola acabo de copiar y pegar tu código en el editor IDLE y me arroja el error: `Traceback (most recent call last): File "", line 1, in from tkinter import Entry ImportError: No module named tkinter.` Al revisar con el explorador encuentro que el módulo se debe invocar como Tkinter al menos linux es case sensitivo – quevedo Feb 04 '20 at 03:50
  • No, a mi no me sale ese error, me sale otro, yo tengo windows. – Franco Feb 04 '20 at 05:57
  • Para aclarar, el error mencionado por @quevedo se debe realmente a ejecutar dicho código en Python 2.x, dónde el módulo se llama efectivamente `Tkinter`. En Python 3.x se renombró para cumplir con las convenciones de estilo y pasó a llamarse `tkinter` (en minúscula). – FJSevilla Feb 04 '20 at 20:02
  • Gracias @FJSevilla todavía estoy en el neolítico. – quevedo Feb 04 '20 at 20:32

1 Answers1

1

Tienes dos errores a grandes rasgos:

  • Estás intentando resolver el problema usado dos paradigmas de la POO conjuntamente, herencia y composición.

  • El otro problema es el de "individualizar". Para que cada instancia de tu Editable ListBox se se comporte de forma individual al hacer doble click debes usar atributos de instancia para definir select y entrylistBox y no variables globales. Al usar variables globales todas las instancias de la clase comparten estos dos valores cosa que no quieres obviamente. Para más información mirate:

Usando herencia

Tu clase debe heredar de tkinter.ListBox (cosa que ya hace) y además se debe invocar de forma explícita al inicializador (__init__) de la clase padre (tkinter.ListBox). Esto se debe a que en la clase hija EditableListbox sobrescribes el método __init__ heredado del padre que no va a ser llamado por tanto al instanciar tu clase. el problema es que el init de la clase padre contiene código que permite a un ListBox comportarse como tal por lo que se debe llamar a su inicializador de forma explícita desde el __init__ de la clase hija. esto podemos hacerlo de forma directa:

ListBox.__init__(self, ventana)

o usando super (superclass):

super().__init__(ventana)

esto causa tu error al intentar insertar elementos en la lista.

El código podría quedar algo así:

import tkinter as tk
from tkinter import Entry
from tkinter import Listbox
from tkinter.font import Font



class EditListBox(tk.Listbox):
    def __init__(self, ventana, posx, posy):
        super().__init__(ventana, width=27)
        self.ventana = ventana
        self.config(borderwidth=2,
                    highlightthickness=4,
                    highlightcolor="#0000ff",
                    selectforeground="#ffffff",
                    selectbackground="#00aa00",
                    selectborderwidth=2,
                    font=Font(family="Sans Serif", size=10),
                    activestyle=tk.NONE
                    )
        self.bind('<Double-Button-1>', self.doble_click)
        self.place(x=posx,y=posy)
        self.select = None
        self.entrylistBox = None

    def doble_click(self,_):
        if self.size() > 0:
            self.config(state="disabled", disabledforeground="#A2A2A2")
            self.select = self.curselection()

            _, y, _, h = self.bbox(self.curselection())
            x = self.winfo_x() + 5
            y += self.winfo_y()
            w = self.winfo_width() - 12

            valor = self.get(self.curselection())
            self.entrylistBox = Entry(self.ventana)
            self.entrylistBox.config(font=Font(family="Sans Serif", size=10))
            self.entrylistBox.focus_set()
            self.entrylistBox.place(x=x, y=y, width=w, height=h)
            self.entrylistBox.config(highlightthickness=1, highlightcolor="green")
            self.entrylistBox.insert(0, valor)
            self.entrylistBox.bind('<Return>', self.key_enter)


    def key_enter(self,_):
        self.entrylistBox.place_forget()
        self.config(state="normal")
        valor_ = self.entrylistBox.get()
        self.delete(self.select)
        self.insert(self.select, valor_)



ventana1 = tk.Tk()
ventana1.geometry("670x320")
listBox1 = EditListBox(ventana1, 10, 30)
listBox1.insert(0, "Prueba")

listBox1 = EditListBox(ventana1, 350, 30)
listBox1.insert(0, "Prueba")

ventana1.mainloop()

Usando composición

En este caso tu clase no debe heredar de tkinter.ListBox, sino que actúa como un mero contenedor de dicho widget:

import tkinter as tk
from tkinter import Entry
from tkinter import Listbox
from tkinter.font import Font



class EditListBox:
    def __init__(self, ventana, posx, posy):
        self.ventana = ventana
        self.listbox = Listbox(ventana, width=27)
        self.listbox.config(borderwidth=2,
                    highlightthickness=4,
                    highlightcolor="#0000ff",
                    selectforeground="#ffffff",
                    selectbackground="#00aa00",
                    selectborderwidth=2,
                    font=Font(family="Sans Serif", size=10),
                    activestyle=tk.NONE
                    )
        self.listbox.bind('<Double-Button-1>', self.doble_click)
        self.listbox.place(x=posx,y=posy)
        self.select = None
        self.entrylistBox = None

    def doble_click(self,_):
        if self.listbox.size() > 0:
            self.listbox.config(state="disabled", disabledforeground="#A2A2A2")
            self.select = self.listbox.curselection()

            _, y, _, h = self.listbox.bbox(self.listbox.curselection())
            x = self.listbox.winfo_x() + 5
            y += self.listbox.winfo_y()
            w = self.listbox.winfo_width() - 12

            valor = self.listbox.get(self.listbox.curselection())
            self.entrylistBox = Entry(self.ventana)
            self.entrylistBox.config(font=Font(family="Sans Serif", size=10))
            self.entrylistBox.focus_set()
            self.entrylistBox.place(x=x, y=y, width=w, height=h)
            self.entrylistBox.config(highlightthickness=1, highlightcolor="green")
            self.entrylistBox.insert(0, valor)
            self.entrylistBox.bind('<Return>', self.key_enter)


    def key_enter(self,_):
        self.entrylistBox.place_forget()
        self.listbox.config(state="normal")
        valor_ = self.entrylistBox.get()
        self.listbox.delete(self.select)
        self.listbox.insert(self.select, valor_)



ventana1 = tk.Tk()
ventana1.geometry("670x320")
listBox1 = EditListBox(ventana1, 10, 30)
listBox1.listbox.insert(0, "Prueba")

listBox1 = EditListBox(ventana1, 350, 30)
listBox1.listbox.insert(0, "Prueba")

ventana1.mainloop()
FJSevilla
  • 55,603
  • 7
  • 35
  • 58