Foro de elhacker.net

Programación => Scripting => Mensaje iniciado por: minak en 11 Mayo 2018, 11:58 am



Título: Refresco tkinter de texto recibido en un callback
Publicado por: minak en 11 Mayo 2018, 11:58 am
Hola estoy haciendo un pequeño programa en python que escucha un servidor mqtt y lo muestra en pantalla en el modo consola no tengo problema pero quise poner una gui con tkinter y no se como hacer que cuando el callback de mensaje recibido refresque un text que esta dentro de una clase que corresponde a la ventana principal. Me podéis ayudar a ver como puedo hacerlo por que es lo unico que me falta y no se me ocurre.

Ventana Principal
Código:
class MyApp:
    def __init__(self, parent):
        self.parent = parent  
        self.parent.protocol("WM_DELETE_WINDOW", self.on_closing) #Indicas que cuando presiones la x de cerrar ventana

        #Ventana principal
        root.title(proyect +" "+ version)                      
        root.resizable (True, True)
        root.iconbitmap('pyc.ico')
        #root.geometry ("650x400")
        root.config (bg="black",bd="10", relief ="sunken")

        ventanainfo = Frame()
        ventanainfo.grid()
        #ventanainfo.config (bg="white", width ="630", height ="380", bd="10", relief ="sunken", cursor ="pirate")
        ventanainfo.config (bg="white", bd="10", relief ="sunken", cursor ="arrow")


        #Configuracion de elemetos sobre frame Principal
        #*****PANTALLA LOG**************
        pantallaLOG = Text(ventanainfo, width ="90", height ="18")
        pantallaLOG.grid (row="0", column ="0", padx=1,pady=1,rowspan=4)
        scrollLog = Scrollbar (ventanainfo, command = pantallaLOG.yview)
        scrollLog.grid (row="0", column ="1", padx=1,pady=1, sticky = "nSeW",rowspan=4)
        pantallaLOG.config (yscrollcommand = scrollLog.set)

        pantallaLOG.insert(INSERT, 'test.\n')
        global ultimoMensaje;
        pantallaLOG.insert(INSERT, ultimoMensaje +'\n')

Callback
Código:
def on_message(client, userdata, msg):
    
    global ultimoMensaje
    ultimoMensaje = (time.strftime("%d/%m/%y - %H:%M -> ")+"[" + msg.topic+"] "+str(msg.payload))
    print (ultimoMensaje)
Dejo el main desde el que se inician callback
Código:
if __name__ == "__main__":

    openConfig(); 

    myIP = getipextern()
    print (myIP)

    client = mqtt.Client(client_name)
    client.username_pw_set(user, password=password)
    client.on_connect = on_connect
    client.on_disconnect = on_disconnect
    client.on_publish = on_publish
    client.on_message = on_message
    #client.on_log = on_log              # Descomenta para activar el modo Debug
    client.on_subscribe = on_subscribe   # Callback de una supcripcion

    #Comienzo del GUI de usuario

    root = tk.Tk()
    app = MyApp(root)
   
    #****Bucle**********************
    root.mainloop()

    #*** Salida del programa
    print("Cerrando...")
    try:
        client.disconnect()
        client.loop_stop()
    except:
        print ("No procede desconectar")
    print ("Adios")

El programa es mucho mas grande pero es que son mas de 500 lineas para ponerlo aqui. Lo que quiero conseguir es que ese cuadro sea como una consola donde se vaya escribiendo lo que pasa en el programa.
Muchas gracias


Título: Re: Refresco tkinter de texto recibido en un callback
Publicado por: minak en 11 Mayo 2018, 13:48 pm
Encontre una solucion pero no la entiendo y no es la mejor opcion porque me crea una ventana trasera que entiendo que es para hacer un bucle de refresco el caso que pongo lo que modifique.
Esta parte no entiendo porque se tiene que hacer asi pero si no lo hago asi after no me deja usarla dentro de la funcion.
Código:
class MyApp(tk.Tk):
    def __init__(self, parent, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
y añado esta funcion
Código:
    def update_logtext(self):
        if (ultimoMensaje!=""):

            global ultimoMensaje;
            self.pantallaLOG.insert(INSERT, ultimoMensaje +'\n')
            ultimoMensaje =""

        self.after(1000, self.update_logtext)

Ahora mientras encuentro otra solucion voy a ver si consigo que la ventana secundaria que se crea sea invisible.

PD : Hecho invisible pero no comprendo muy bien todo esto que hize
Código:
class MyApp(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self)

Os pongo el codigo del que saque la solucion por si alguien lo quiere :
Código:
import Tkinter as tk
import time

class SampleApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.clock = tk.Label(self, text="")
        self.clock.pack()

        # start the clock "ticking"
        self.update_clock()

    def update_clock(self):
        now = time.strftime("%H:%M:%S" , time.gmtime())
        self.clock.configure(text=now)
        # call this function again in one second
        self.after(1000, self.update_clock)

if __name__== "__main__":
    app = SampleApp()
    app.mainloop()