I'm working on an app, and I need the images to display independently at a specific timing. I have set up a thread using python's stock threading module, it runs and works normally instead of the image it displays a black square. Does anyone know how to fix it?
Here is my code to reproduce the issue:
import threading
from kivy.app import App
from kivy.uix.image import Image
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
class TestApp(App):
def build(self):
self.fl = FloatLayout()
self.fl.add_widget(Button(text="show image", on_press=self.start_thread))
return self.fl
def insertfunc(self):
self.fl.add_widget(Image(source="HeartIcon.png"))
def start_thread(self, instance):
threading.Thread(target=self.insertfunc).start()
TestApp().run()
Any help will be appreciated!
The add_widget() must be done on the main thread. I assume that you are using threading because you have additional things to do on the Thread aside from just the add_widget(). Based on that assumption, here is a modified version of your code that does what I think you want:
import threading
from kivy.app import App
from kivy.clock import Clock
from kivy.uix.image import Image
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
class TestApp(App):
def build(self):
self.fl = FloatLayout()
self.fl.add_widget(Button(text="show image", on_press=self.start_thread))
return self.fl
def insert_image(self, dt):
self.fl.add_widget(Image(source="HeartIcon.png"))
def insertfunc(self):
# do some calculations here
Clock.schedule_once(self.insert_image)
def start_thread(self, instance):
threading.Thread(target=self.insertfunc).start()
TestApp().run()
If you are not doing anything else in the new thread, then you don't actually need another thread. The start_thread() method can just do the:
self.fl.add_widget(Image(source="HeartIcon.png"))
Related
I'm trying to make an expense tracker app using KivyMD. I have built it already using kivy but it's design is awful, then i found out KivyMD and now i want to tweak the app using KivyMD but i want to do it without using a kv file because my app has a lot of nested if statements which are too complex to write in the kv file. Anyway, i'm trying to test KivyMD but running into this nasty ValueError
ValueError: KivyMD: App object must be initialized before loading root widget. See https://github.com/kivymd/KivyMD/wiki/Modules-Material-App#exceptions and idk how to fix it without using a kv file. This question is asked plenty times but every answer uses a kv file. Can someone please help me understand this error and tackle it without kv. Thank you... Here is some code
from kivymd.app import MDApp
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.app import App
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.stacklayout import MDStackLayout
from kivymd.uix.button import MDRaisedButton, MDRectangleFlatButton
from kivy.metrics import dp,sp
from kivymd.uix.screen import MDScreen
from kivy.uix.textinput import TextInput
from kivymd.uix.textfield import MDTextField
from kivy.uix.screenmanager import ScreenManager
import re
#ALL SCREENS
class MainScreen(MDScreen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
box = MDBoxLayout(orientation="vertical")
b = MDRaisedButton(text="Content",size_hint = (1,0.5))
box.add_widget(b)
t = MDTextField(size_hint=(1,0.5))
box.add_widget(t)
self.add_widget(box)
#ScreenManager
sm = ScreenManager()
sm.add_widget(MainScreen(name="main_screen"))
class MyApp(MDApp):
def build(self):
self.theme_cls.primary_palette = "DeepOrange"
self.theme_cls.accent_palette = "Lime"
return MainScreen()
if __name__ == "__main__":
MyApp().run()
works perfectly fine when i remove the screenmanager and just return the MainScreen.
Any help or guidance is highly appreciated.
getting the blank screen after running this code what is the problem
after adding .kv file everything is working fine and after removing .kv file and using the only python to show the layout it is not working
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
class BoxLayoutExample(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
b1 = Button(text="A")
b2 = Button(text="B")
b3 = Button(text="C")
self.clear_widgets()
self.add_widget(b1)
self.add_widget(b2)
self.add_widget(b3)
class MainWidget(Widget):
pass
class TheLabApp(App):
pass
TheLabApp().run()
This the output:)
Image
If you are not using a kv file named thelab.kv, then your App has no way of knowing what you want it to look like. You will at least need to add a build() method to your TheLabApp class that returns BoxLayoutExample().
I have problem with disabling of buttons in kivy library. When I disable button, it simply not disable. It waits in some strange way.
Let me show you my code:
import kivy
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
import time
class MainApp(App):
def build(self):
self.l = FloatLayout()
b = Button(text="BUTTON", pos_hint={"top":0.8, "right": 0.8}, size_hint=(0.6, 0.6))
b.bind(on_press=self.press)
self.l.add_widget(b)
return self.l
def press(self, btn):
btn.disabled = True
time.sleep(3.0)
btn.disabled = False
app = MainApp()
app.run()
When I press button, I want to disable it for 3 sec. But instead of it program "freeze" (without disabling of button), and then after 3 secs do animation of press (button blinks with blue color). Of cource program must "freeze" because of time.sleep(3.0), but after disabling of button (Which must be gray, but it dont change color...)
How to solve it? If I put there instead time.sleep() something like for cycle (with about 10 milions of cycle) to imitate of "doing something" by program, it behaves in the same way...
So how I can solve it? How to disable button in kivy, then do something and after it is done enable button again?
Thanks!
EDIT: My problem isn't, that program freezes for 3 seconds. I understand that calling time.sleep() is blocking. What I don't understand is why button is not disabled before (and during) sleep...
The time.sleep is blocking the code. Instead you need to use Clock to enable the button after 3 seconds. Below is the corrected code to achieve your target:
import kivy
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.clock import Clock
from functools import partial
class MainApp(App):
def build(self):
self.l = FloatLayout()
b = Button(text="BUTTON", pos_hint={"top":0.8, "right": 0.8}, size_hint=(0.6, 0.6))
b.bind(on_press=self.press)
self.l.add_widget(b)
return self.l
def press(self, btn):
btn.disabled = True
Clock.schedule_once(partial(self.btn_enable, btn), 3)
def btn_enable(self, btn, *args):
btn.disabled = False
app = MainApp()
app.run()
TL; DR
The animation happens after the press function is called. This means that you freeze the program when doing time.sleep.
What to do about it?
Instead, you need to do something non-blocking, meaning that it runs in three seconds, but it doesn't cause the program to freeze. Something that would probably work is to utilize threads (something similar to the example, but dealing with sending variables across threads).
Example
Here is an example for your code that does not work, so you can understand the gist of it. Most likely, you are going have to deal with passing variables across threads:
import kivy
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
# import time
import threading
class MainApp(App):
def build(self):
self.l = FloatLayout()
b = Button(text="BUTTON", pos_hint={"top":0.8, "right": 0.8}, size_hint=(0.6, 0.6))
b.bind(on_press=self.press)
self.l.add_widget(b)
return self.l
def press(self, btn):
btn.disabled = True
# time.sleep(3.0)
threading.Timer(3.0, lambda: btn.disabled = False).start()
app = MainApp()
app.run()
This was inspired by this answer.
this is my script ...
import kivy
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.image import Image
class MyApp(App):
def build(self):
return Image(source='go.jpg')
MyApp().run()
I won't to reload it becose the image is changing and I won't to see the new won all time
you can use reload() the read the image from the disk again
this will reload even if the original data of the image is updated or changed
self.ids.image1.source = './Images/file.png'
self.ids.image1.reload()
Make your own widget class, and make the image an attribute, so you can reference it. Then use clock to schedule an interval method, to constantly reload the image.
In the example below, the update_pic method is executed once every second.
import kivy
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.image import Image
from kivy.clock import Clock
from kivy.uix.widget import Widget
class MyImageWidget(Widget):
def __init__(self,**kwargs):
super(MyImageWidget,self).__init__(**kwargs)
self.image = Image(source='go.jpg')
self.add_widget(self.image)
Clock.schedule_interval(self.update_pic,1)
def update_pic(self,dt):
self.image.reload()
class MyApp(App):
def build(self):
return MyImageWidget()
MyApp().run()
You can use the Image.reload method
def build(self):
img = Image(source='go.jpg')
Clock.schedule_interval(lambda dt: img.reload(), 0.2) #5 per second
return img
So I'm writing a drum pad:
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.core.audio import SoundLoader
class GridAction(Button):
pass
class MakingGrid(GridLayout):
def __init__(self, *args, **kwargs):
super(MakingGrid, self).__init__(*args, **kwargs)
for i in range(16):
grid_action = GridAction()
grid_action.bind(on_release=self.button_pressed)
self.add_widget(grid_action)
def button_pressed(self, button):
print('pressed')
class MyApp(App):
def build(self):
return MakingGrid(cols=4)
if __name__ == "__main__":
MyApp().run()
There is a grid of buttons as a result, and the purpose is to make them sound different, but I don't know how to do this. Please, help. Thanks in advance) Also, if you see any disadvantages in this code, please, tell me about them, I`m a beginner.
A simple way to play audio is with kivy's soundloader.
Beyond this, I'm not clear on what your question actually is. The general answer is to do something like give each GridAction its own audio_file property holding a filepath to the sound you want, and bind the on_press events to play the sound at this location.