How to change a text dynamically in kivy, python from a thread

1

I am trying to change the text of a stringProperty from a thread but I do not know how to access the string property from the thread This is the thread:

   def worker():
    dev = InputDevice('/dev/input/by-id/usb-Logitech_USB_Keyboard-event-kbd')
    # Provided as an example taken from my own keyboard attached to a Centos 6 box:
    scancodes = {
        # Scancode: ASCIICode
        0: None, 1: u'ESC', 2: u'1', 3: u'2', 4: u'3', 5: u'4', 6: u'5', 7: u'6', 8: u'7', 9: u'8',
        10: u'9', 11: u'0', 12: u'-', 13: u'=', 14: u'BKSP', 15: u'TAB', 16: u'Q', 17: u'W', 18: u'E', 19: u'R',
        20: u'T', 21: u'Y', 22: u'U', 23: u'I', 24: u'O', 25: u'P', 26: u'[', 27: u']', 28: u'CRLF', 29: u'LCTRL',
        30: u'A', 31: u'S', 32: u'D', 33: u'F', 34: u'G', 35: u'H', 36: u'J', 37: u'K', 38: u'L', 39: u';',
        40: u'"', 41: u''', 42: u'LSHFT', 43: u'\', 44: u'Z', 45: u'X', 46: u'C', 47: u'V', 48: u'B', 49: u'N',
        50: u'M', 51: u',', 52: u'.', 53: u'/', 54: u'RSHFT', 56: u'LALT', 100: u'RALT'
    }

    for event in dev.read_loop():
        if event.type == evdev.ecodes.EV_KEY:
            data = evdev.categorize(event)  # Save the event temporarily to introspect it
            if data.keystate == 1:  # Down events only
                key_lookup = scancodes.get(data.scancode) or u'UNKNOWN:{}'.format(data.scancode)  # Lookup or return UNKNOWN:XX
                print(u'You Pressed the {} key!'.format(key_lookup))  # Print it all out!


t = Thread(target=worker)
t.start()

this is the code where I define the stringProperty:

class Controller(BoxLayout):
random_string = StringProperty("hola")


def do_action(self):
    self.random_string="h22l"
    print(self.random_string)
def do_action2(self):
    self.random_string="hl2332323"
    print(str(self.random_string))

The idea would be to change the text after the thread print

    
asked by Aurelio Fernandez 11.06.2018 в 13:10
source

1 answer

1

Always keep in mind that any operation involving OpenGL should only be done from the main thread. Never interact with the widgets of the interface from another thread that is not the main thread directly, for this use the decorator @mainthread so that the call is made from the main thread in the next frame.

An example with a counter from 0 to 10 implemented in a thread and that updates a StringProperty in the app:

import threading
import time
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.properties import StringProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import mainthread



class MainWidget(BoxLayout):
    label_str = StringProperty("")
    def __init__(self, *args, **kwargs):
        super(MainWidget, self).__init__(*args, **kwargs)
        self.orientation = "vertical"

        self.label = Label(text=self.label_str)
        self.bind(label_str=self.label.setter('text'))
        self.add_widget(self.label)
        self.add_widget(Button(text="Iniciar hilo", on_press=self.iniciar_hilo))

    def iniciar_hilo(self, *args):
        if self.label_str == '':
            t = threading.Thread(target=self.worker)
            t.start()

    def worker(self):
        self.update_label("Iniciando")
        time.sleep(1)
        for n in range(10):
            self.update_label(str(n))
            time.sleep(1)
        self.update_label("Terminado")
        time.sleep(1)
        self.update_label("")

    @mainthread
    def update_label(self, value):
        self.label_str = value



class MyApp(App):
    def build(self):
        return MainWidget()


if __name__ == '__main__':
    MyApp().run()

When the method update_label is called from the thread, the call is carried out in the main thread thanks to the decorator @mainthread , you can update a widget directly in the same way.

    
answered by 11.06.2018 / 16:42
source