Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kivy and Python threading - how get data between them

I've some problems with python(threading) and kivy:

Here is some code:

import kivy
import threading 
import time
from kivy.app import App
from kivy.uix.button import Button

class Thread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)  
        self.counter = 0        
    def run(self):
        while True:
            print "Thread is running "+str(self.counter)
            app.button.text = self.set_button(self.counter)
            app.button.text = str(self.counter)
            time.sleep(0.5)
    def count(self):
        self.counter += 1
        app.button.text = str(self.counter)     
    def set_button(self, value):
        app.button.text = str(value)

class MyApp(App):
    def __init__ (self, thread_object):
        App.__init__(self) 
        self.thread_object = thread_object      
    def callback(self,instance):
        print('The button <%s> is being pressed' % instance.text)
        self.thread_object.count()
    def build(self):
        self.button = Button(text='Hello World')
        self.button.bind(on_press=self.callback)
        return self.button

thread = Thread()
thread.start()
app = MyApp(thread)
app.run()

Now - this code opens a kivy app with one button. The task is: pressing the button some data should appear in the threaded code (it does by the "count" method.

Problem is the reverse way - the threaded code should change the text of the button. I've tried two ways:

  • Write it directly: app.button.text = str(self.counter)

  • Write it via a method "set_button": app.button.text = self.set_button(self.counter)

Both of them show up an error "Attribute Error: 'MyApp' object has no attribute 'button'".

Is there any way to exchange data directly without requesting, even without doing that pointer stuff here with "thread_object"

def __init__ (self, thread_object):

Thanks for your help.

like image 878
user3082089 Avatar asked Jul 05 '15 20:07

user3082089


People also ask

How do you share data between two threads in Python?

You can protect data variables shared between threads using a threading. Lock mutex lock, and you can share data between threads explicitly using queue. Queue.

How does Python threading work?

Multithreading (sometimes simply "threading") is when a program creates multiple threads with execution cycling among them, so one longer-running task doesn't block all the others. This works well for tasks that can be broken down into smaller subtasks, which can then each be given to a thread to be completed.


1 Answers

This will probably solve all your problems. That's the way I like to code while dealing with threads and with kivy language.

Here is thread.py file

import threading   
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import NumericProperty

class Thread(BoxLayout):
    counter = NumericProperty(0)

    def Counter_function(self):
        self.counter += 1
        self.ids.lbl.text = "{}".format(self.counter)

    def First_thread(self):
        threading.Thread(target = self.Counter_function).start()
        self.counter += 1
        self.ids.lbl.text = "{}".format(self.counter)

class MyApp(App):
    def build(self):
        self.load_kv('thread.kv')
        return Thread() 

if __name__ == "__main__":
    app = MyApp()
    app.run()

Here is thread.kv file

<Thread>:
    Button:
        text: "use thread"
        on_release: root.First_thread()
    Button:
        text: "Hit me"
        on_release: root.Counter_function()
    Label:
        id: lbl
        text: "Numbers"

Now, You said in your comment that you struggle with dynamically loading the GUI. So, here's an example. threading.py

import threading   
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import NumericProperty
from kivy.lang.builder import Builder
from kivy.uix.button import Button

Builder.load_string('''
[SideBar@BoxLayout]:
    content: content
    orientation: 'vertical'
    size_hint: .2,1
    BoxLayout:
        orientation: 'vertical'
        # just add a id that can be accessed later on
        id: content

<Root>:
    Button:
        center_x: root.center_x
        text: 'press to add_widgets'
        size_hint: .2, .2
        on_press:
            sb.content.clear_widgets()
            root.load_content(sb.content)
    SideBar:
        id: sb
''')

class Root(BoxLayout):

    def load_content(self, content):
        for but in range(20):
            content.add_widget(Button(text=str(but)))

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

if __name__ == "__main__":
    app = MyApp()
    app.run()
like image 64
kiok46 Avatar answered Sep 18 '22 02:09

kiok46