Why is the text label not changed?

Asked

Viewed 84 times

0

I have a screen class, which contains a label of text, the code loads an xml containing the objects.

py screen.:

#!/usr/bin/python3
import gi
import modulo_arquivos
import os

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk

# diretorios dos arquivos
diretorio_exe = os.path.dirname(os.path.realpath(__file__))
diretorio_proj = diretorio_exe + '/'
diretorio_tela = diretorio_proj + 'screens/tela_principal/tela_principal.glade'

class tela_principal():


    def carrega_arquivo_xml(self):


        self.tela_builder = Gtk.Builder()
        self.tela_builder.add_from_file(diretorio_tela)

        self.janela = self.tela_builder.get_object("Janela")
        self.label_txt = self.tela_builder.get_object('txt_ps_atual01')


    def abre_tela(self):
        self.janela.show()

    def fecha_tela(self):
        self.janela.hide()


    def escreve_txt(self, texto):
        self.label_txt.set_text(texto))

And I have a main file that creates the screen instance and has it open. In the main code I have two processes according to the code below:

#!/usr/bin/python3

#IMPORTS
import gi
gi.require_version("Gtk", "3.0")
from multiprocessing import Process, Queue, Pipe
from gi.repository import Gtk, GObject

import tela

tela_principal = tela.tela_principal()
tela_principal.carrega_arquivo_xml()
tela_principal.abre_tela()

def escreve_texto(texto):
    tela_principal.escreve_txt(texto)

def interface_grafica(tx, rx):

    while True:

        Gtk.main_iteration_do(False)

        #escreve_texto('HELLO')

def comunicacao_serial(tx,rx):
    escreve_texto('HELLO2')




if __name__ == "__main__":
    queue1 = Queue()
    queue2 = Queue()

    p1 = Process(target=interface_grafica, args=(queue1, queue2,))
    p2 = Process(target=comunicacao_serial, args=(queue2, queue1,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()

The problem is that the label is only modified within the graphical interface function, but within the communication function it is not changed. Why this happens and how to solve?

1 answer

1


In fact, it’s surprising that the label changes the way the code is, if you call the function escreve_texto from within interface_grafica.

A "process" is something independent at the level of the operating system - no variable, window, file, or other thing of a process should be visible from another process - unless explicit mechanisms of data sharing between processes are used. There are some resource inheritance rules - where, depending on the parameters used to create the child process, it may have access to some resources from the parent process.

This code actually has 3 processes: the main program - and you create a sub-process just to manage the graphical interface, and another just for serial communication. Your window stay open and do not close with an error when being called the .main_iteration_do is a surprise to me - it means that this second process actually had access to the GTK data structures that were in the first process (and this happened implicitly).

Well - there are some ways to solve the approach there; if you’re going to maintain the multi-process architecture, the recommended way would be to create queues (you can’t see how you create the ones there, but I suppose they’re correct) - and pass all the data you want to appear in the graphical interface through these queues. It is no use trying to call a method that accesses GTK directly from another process - the variables, objects, everything on the screen, do not even exist in the second process.

Now - the very recommendation there would be nay use this subprocess architecture in this program. As you can see, the complexity starts to increase (and you’re trying to change a simple label) - the complexity will increase, much more if you have uqe respond to more events on the interface than just changing a label - you will have to end up creating a function that reads the event Queue coming from the other process and dispatches to local functions - and to encode the events in the Queue, will end up developing a "mini-language".

A code with serial communication and GTK itnerface can work perfectly well in a single process. If you don’t want to write the serial code a little more complex to be non-blocking, you can use two threads. (But then always remember not to try to call any GTK functionality from within the second thread - just put data into structures that are consumed in functions within the first thread - you can use queues, or even Python lists for that).

Anyway, you have already solved the problem of GTK not giving you control of the program by calling the .main_iteration_do instead of the .mainloop. All you need to do is, at the same point you repeatedly call this GTK method, also call the function to interact with the serial port - and of course change the serial function to have a zero timeout - this way the program will not stand still waiting for bytes available.

...

def main():
    dados_lidos = b""
    dados_a_escrever = b""
    while True:
         # processa eventos da interface gráfica:
         if Gtk.main_iteration_do(False):
              # a interface gráfica recebeu um evento de sair:
              break
         # realiza a comunicação serial:
         comunicacao_serial(dados_a_escrever)
         # processa os dados lidos da serial, 
         # como está tudo no mesmo processo e mesma thread, essa
         # funçao vai poder alterar a interface gráfica
         # sem problemas
         dados_a_escrever = processa(dados_lidos)
         # repete.


def comunicacao_serial(dados_a_escrever):
     if dados_a_escrever:
         serial.write(dados_a_escrever)
     return serial.read(10000)

def setup():
    serial = Pyseral.Serial(..., timeout=0)

if __name__ == "__main__":
    setup()
    main()
  • Thank you for that enlightening reply!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.