【问题标题】:kivy glitch with images and threading带有图像和线程的 kivy 故障
【发布时间】:2016-02-20 10:14:21
【问题描述】:

我对 kivy 比较陌生,并且在某些图像和按钮图像无法正确加载时出现间歇性问题,即使使用相同图像的其他小部件正确加载相同图像也是如此。我认为线程和kivy绘图不能很好地协同工作是一个问题。对于下面重现问题的代码,线程不是必需的,但在完整的应用程序中,加载所有图像块的时间过长。感谢您的帮助。

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()

【问题讨论】:

    标签: python multithreading kivy


    【解决方案1】:

    我想通了。以防其他人遇到这个问题。对 GUI 的任何更改都必须在主线程中完成。您可以通过将@mainthread 放在函数定义上方的行上来强制执行函数。例如:

    from kivy.clock import mainthread
    
    @mainthread
    def add something(self, w):
        self.add_widget(w)
    

    您必须“导入主线程”才能使其工作。

    【讨论】:

    • 我的意思是所有导入都在顶部,你必须添加from kivy.clock import mainthread
    • 来自 kivy.clock 模块?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-19
    • 1970-01-01
    • 2020-10-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多