Calificación:
  • 0 voto(s) - 0 Media
  • 1
  • 2
  • 3
  • 4
  • 5
Interactuar con clases tkinter
#1
Buenas:

Tengo un problema a la hora de interactuar con dos clases.

 tengo el siguiente código (es un ejemplo y no hagáis caso a los import porque son de la aplicación que estoy haciendo): 

from tkinter import *
from tkinter import ttk
from datetime import *
from tkinter import messagebox
import time
import calendar
import threading
from threading import Timer
import psycopg2
import os
import sys


class A:
    
    def __init__(self):
        
        # MAIN WINDOW
        
        def cambio():
            self.boton.configure(style="Esti.TButton")    
            
        self.root = Tk()
        self.root.title('PRUEBAS')
        self.root.geometry('400x400')    
    
        estilo = ttk.Style()
        estilo.configure("Esti.TButton", background = 'light green')
        
        self.boton = ttk.Button(self.root, text='PRUEBA', command=B)
        self.boton.grid(row=0, column=1)
    
        self.root.mainloop()

class B:
    
    def __init__(self):
        
        # MAIN WINDOW
        
        def instanciar():
            self.a = A()
            self.boton.configure(style="Esti.TButton")          
    
        self.top = Toplevel()
        self.top.title('A VER')
        self.top.geometry('400x400')
        
        self.boton1 = ttk.Button(self.top, text='CAMBIO', command=instanciar)
        self.boton1.grid(row=0, column=0)
        
        self.top.mainloop()
        

def main():
    my_app = A()

if __name__ == '__main__':
    main()

Todo funciona perfectamente excepto que soy incapaz de hacer que desde la clase B, al pulsar el botón de cambio, me cambie el color del botón de la clase A.
siempre me dice que la clase B no tiene los atributos de A (Lo máximo que he conseguido es instanciar un objeto con la clase A. (Que conste que mediante funciones sin clases es relativamente sencillo hacerlo y que funcione pero no es lo que estoy buscando hacer aunque si no tengo más remedio lo haré.

Alguna idea de como ejecutar comandos desde una clase para interactuar con otra?

Sé que me explico como un libro cerrado.
Responder
#2
Hola. Si quieres acceder al botón de la clase A debería ser:

  1. self.a = A()
  2. # En lugar de self.boton...
  3. self.a.boton.configure(style="Esti.TButton")


De todas formas ya tienes una instancia de la clase A (my_app), tal vez te convendría pasarla como argumento a la clase B en lugar de crear una nueva instancia.

  1. class B:
  2. def __init__(self, my_app):
  3. self.my_app = my_app
  4. def cambiar_color():
  5. self.my_app.boton.configure(style="Esti.TButton")
  6.  
  7. # Y al crear una instancia de B:
  8. b = B(my_app)


La idea de las clases es hacer el código menos repetitivo, más ordenado y más fácil de mantener. Si el código no lo amerita no es una buena práctica crear una clase para todo.

Saludos
Responder
#3
(03-02-2019, 05:12 PM)Francisco escribió: Hola. Si quieres acceder al botón de la clase A debería ser:

  1. self.a = A()
  2. # En lugar de self.boton...
  3. self.a.boton.configure(style="Esti.TButton")


De todas formas ya tienes una instancia de la clase A (my_app), tal vez te convendría pasarla como argumento a la clase B en lugar de crear una nueva instancia.

  1. class B:
  2.    def __init__(self, my_app):
  3.        self.my_app = my_app
  4.        def cambiar_color():
  5.            self.my_app.boton.configure(style="Esti.TButton")
  6.  
  7. # Y al crear una instancia de B:
  8. b = B(my_app)


La idea de las clases es hacer el código menos repetitivo, más ordenado y más fácil de mantener. Si el código no lo amerita no es una buena práctica crear una clase para todo.

Saludos

Muchas Gracias.

La primera solución ya la había probado pero no funciona. Te copio el error que da:

Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
    return self.func(*args)
  File "untitled.py", line 43, in instanciar
    return self.a.boton.configure(style="Esti.TButton")
  File "/usr/lib/python3.7/tkinter/__init__.py", line 1485, in configure
    return self._configure('configure', cnf, kw)
  File "/usr/lib/python3.7/tkinter/__init__.py", line 1476, in _configure
    self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: invalid command name ".!button"

Desgraciadamente la segunda tampoco funciona.

Os mando el error que da:

class B:
    
    def __init__(self, my_app):
        
        self.my_app = my_app
        
        # MAIN WINDOW
        
        def cambiocolor():
            self.my_app.boton.configure(style="Esti.TButton")            
    
        self.top = Toplevel()
        self.top.title('A VER')
        self.top.geometry('400x400')
        
        self.boton1 = ttk.Button(self.top, text='CAMBIO', command=instanciar)
        self.boton1.grid(row=0, column=0)
        
        self.top.mainloop()

ERROR:

Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
    return self.func(*args)
TypeError: __init__() missing 1 required positional argument: 'my_app'

Otra prueba más y el error:

class B:
    
    def __init__(self):
        # MAIN WINDOW
        
        def cambiocolor():
            self.my_app.boton.configure(style="Esti.TButton")            
    
        self.top = Toplevel()
        self.top.title('A VER')
        self.top.geometry('400x400')
        
        self.boton1 = ttk.Button(self.top, text='CAMBIO', command=cambiocolor)
        self.boton1.grid(row=0, column=0)
        
        self.top.mainloop()

def main():
    my_app = A()

if __name__ == '__main__':
    main()


Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
    return self.func(*args)
  File "untitled.py", line 41, in cambiocolor
    self.my_app.boton.configure(style="Esti.TButton")
AttributeError: 'B' object has no attribute 'my_app'
Responder
#4
Debería quedarte así el código:

  1. class A:
  2.  
  3. def __init__(self):
  4.  
  5. # MAIN WINDOW
  6.  
  7. def cambio():
  8. self.boton.configure(style="Esti.TButton")
  9.  
  10. self.root = Tk()
  11. self.root.title('PRUEBAS')
  12. self.root.geometry('400x400')
  13.  
  14. estilo = ttk.Style()
  15. estilo.configure("Esti.TButton", background = 'light green')
  16.  
  17. self.boton = ttk.Button(self.root, text='PRUEBA',
  18. command=self.boton_clicked)
  19. self.boton.grid(row=0, column=1)
  20.  
  21. self.root.mainloop()
  22.  
  23. def boton_clicked(self):
  24. b = B(self)
  25.  
  26.  
  27. class B:
  28.  
  29. def __init__(self, a):
  30. self.a = a
  31. # MAIN WINDOW
  32.  
  33. def instanciar():
  34. self.a.boton.configure(style="Esti.TButton")
  35.  
  36. self.top = Toplevel()
  37. self.top.title('A VER')
  38. self.top.geometry('400x400')
  39.  
  40. self.boton1 = ttk.Button(self.top, text='CAMBIO', command=instanciar)
  41. self.boton1.grid(row=0, column=0)
  42.  
  43. self.top.mainloop()
  44.  
  45.  
  46. def main():
  47. my_app = A()


Te recomiendo el siguiente artículo para una introducción al propósito y funcionamiento de las clases: https://recursospython.com/guias-y-manua...a-objetos/.

Saludos
Responder
#5
MUCHÍSIMAS GRACIAS

He tenido que hacer alguna modificación porque la función boton_clicked tiene que ir antes de la asignación en command porque sí no da error.

He aquí el script definitivo por si alguien tiene el mismo problema que yo lo eche un vistazo

class A:

    
    def __init__(self):
        
        def boton_clicked():
            b = B(self)

            
        self.root = Tk()
        self.root.title('PRUEBAS')
        self.root.geometry('400x400')    
    
        estilo = ttk.Style()
        estilo.configure("Esti.TButton", background = 'light green')
        
        self.boton = ttk.Button(self.root, text='PRUEBA', command=boton_clicked)
        self.boton.grid(row=0, column=1)
    
    
        self.root.mainloop()

class B:
    
    def __init__(self, a):
        self.a = a
        
        def cambiocolor():
            self.a.boton.configure(style="Esti.TButton")            
    
        self.top = Toplevel()
        self.top.title('A VER')
        self.top.geometry('400x400')
        
        self.boton1 = ttk.Button(self.top, text='CAMBIO', command=cambiocolor)
        self.boton1.grid(row=0, column=0)
        
        self.top.mainloop()
        

def main():
    my_app = A()

if __name__ == '__main__':
    main()

P.D. Muy bueno el aporte con la explicación de las clases. El 90% del tema de clases que se ve por internet es un (class a: pass) y luego b = a(). Y con eso termina la explicación de clases. Vaya tela.
Responder
#6
Vaya...... mi gozo en un pozo. Despues de tanto tiempo y conseguir lo que quería parece que no me va a servir.....

La interfaz gráfica con Tkinter responde de un modo rarísimo.

Tengo una app que es una clase. Dentro de la pantalla principal (Tk()) hay muchos botones que inicizalizan otras clases (Toplevels). A su vez tengo un Treeview con fomato columnas con scrollbar horizontal ajustado al tamaño de las columnas. Pues bien, despues de conseguir que unas clases interactuen con otras me encuentro con que cada vez que "abro" una clase ¡SE ME EXPANDEN LAS COLUMNAS DEL TREEVIEW!!!!!. ¡WTF???!!!!. Claro como el scrollbar está ajustado al tamaño inicial dejo de ver la información que necesito.

Si puedo mañana os envío un vídeo.
Responder
#7
Buenas:

Aquí tenéis el vídeo por si alguien se le ocurre que puede estar pasando:






No sé si lo he hecho bien lo de insertar el vídeo
Responder
#8
(06-02-2019, 07:39 AM)Myszowor escribió: Buenas:

Aquí tenéis el vídeo por si alguien se le ocurre que puede estar pasando:






No sé si lo he hecho bien lo de insertar el vídeo
Nada chic@s , asunto solucionado. Tema de ipadx e ipady en el treeview y las scrollbar.

Muchas gracias. (Sigo trabajando).
Responder


Salto de foro:


Usuarios navegando en este tema: 1 invitado(s)