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.
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.
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.
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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With