I'm relatively new to kivy and am having an intermittent issue with certain images and button images not loading correctly, even when the same image loads correctly for other widgets using the same image. I think it's an issue with threading and kivy drawing not working well together. For the code below that reproduces the issue threading isn't necessary, but in the full app, loading all the images blocks for too long. Thanks for any help.
from kivy.app import App
from kivy.core.window import Window
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import Screen
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.scrollview import ScrollView
from kivy.effects.opacityscroll import OpacityScrollEffect
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.image import AsyncImage, Image
from kivy.uix.screenmanager import ScreenManager, Screen
from _functools import partial
from threading import Thread
class resultLine(RelativeLayout):
def __init__(self, title, coverUrl, showid):
super(RelativeLayout, self).__init__(size_hint=(None, None), size=(Window.width * 0.945, 0.12 * Window.height))
self.cover = AsyncImage(source=coverUrl, loading_image='loading.gif', error_image='../../tv.png',
size=(0.2 * self.width, 0.85 * self.height), pos=(0, 0.125 * self.height), size_hint=(None, None),
nocache=True)
self.cover.width = Window.width * 0.2
self.nameButton = Button(text='', size=(self.width, self.height), x=0, size_hint=(None, None), opacity=0.85,
background_normal='../../button.png', background_down='../../button_pressed.png')
fontSize=0.05 * Window.width
self.nameTag = Label(text=' ' + title, font_size=fontSize, width=Window.width * 0.945,
height=self.height, x=0, y=0.05*self.height,
size_hint=(None, None), valign='middle', halign='left', opacity=0.85,
padding_x=Window.width * 0.025)
self.nameTag.text_size = self.nameTag.size
self.nameTag.shorten = True
self.nameTag.shorten_from = 'right'
self.nameTag.split_str = ' ...'
self.nameButton.bind(on_press=self.doNameButtonPress)
self.nameButton.bind(on_release=self.doNameButtonRelease)
self.add_widget(self.nameButton)
self.add_widget(self.nameTag)
self.add_widget(self.cover)
self._trigger_layout()
def doNameButtonPress(self, instance):
self.nameTag.x += 0.01 * self.width
self.nameTag.y -= 0.1 * self.height
# self.cover.pos_hint = {'x':0.01, 'y':0.025}
self.cover.x += 0.01 * self.width
self.cover.y -= 0.1 * self.height
def doNameButtonRelease(self, instance):
self.nameTag.x -= 0.01 * self.width
self.nameTag.y += 0.1 * self.height
# self.cover.pos_hint = {'x':0, 'y':0.1}
self.cover.x -= 0.01 * self.width
self.cover.y += 0.1 * self.height
class ShowSelector(Screen):
bottomLayout = ScrollView(size=(0.95 * Window.width, Window.size[1] * 0.875), pos=(0.025 * Window.width, 0),
size_hint=(None, None), bar_margin=-0.0125 * Window.width, effect_cls=OpacityScrollEffect)
scrollLayout = GridLayout(cols=1, size_hint=(None, None), height=Window.height, spacing=Window.height * .01)
def __init__(self, **kwargs):
super(Screen, self).__init__(**kwargs)
self.add_widget(self.bottomLayout)
self.bottomLayout.add_widget(self.scrollLayout)
self.scrollLayout.bind(minimum_height=self.scrollLayout.setter('height'))
self.scrollLayout.height = (Window.height * 0.12 + self.scrollLayout.spacing[1]) * 100
Thread(target=self.action).start()
def action(self):
for i in xrange(1,100):
self.scrollLayout.add_widget(resultLine(str(i), '1.jpg', 0))
class theApp(App):
smMain =ScreenManager()
selectorScreen = ShowSelector(name='showsel')
def build(self):
self.smMain.add_widget(self.selectorScreen)
return self.smMain
thisApp=theApp()
thisApp.run()
I figured it out. In case anyone else runs into this problem. Any changes to the GUI have to be done in the main thread. You can force a function by putting @mainthread on the line above the function definition. For example:
from kivy.clock import mainthread
@mainthread
def add something(self, w):
self.add_widget(w)
You have to "import mainthread" for this to work.
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