从另一个线程修改kivy属性

8

我正在尝试一些kivy的代码。我尝试使用线程库创建的线程修改了一个kivy属性(text_colour)。程序运行良好,但线程没有改变该属性。

我还尝试在类中创建一个方法来获取值作为参数,但也失败了。

from kivy.app import App

from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ListProperty


import threading
import random
import time


def zaaa():
    import time
    time.sleep(3)
    ScatterTextWidget.text_colour = [0, 0, 1, 1]
    print "function ran"   

t = threading.Thread(target= zaaa)
t.start()


class ScatterTextWidget(BoxLayout):

    text_colour = ListProperty([1, 0, 0, 1])

    def change_label_colour(self, *args):
        colour = [random.random() for i in xrange(3)] + [1]
        self.text_colour = colour

    def press(self, *args):
        self.text_colour = [1, 1, 1, 1]


class TataApp(App):
    def build(self):
        return ScatterTextWidget()


if __name__ == "__main__":
    TataApp().run()

输出:

[INFO              ] Kivy v1.8.0
[INFO              ] [Logger      ] Record log in /home/mbp/.kivy/logs/kivy_14-02-26_44.txt
[INFO              ] [Factory     ] 157 symbols loaded
[DEBUG             ] [Cache       ] register <kv.lang> with limit=None, timeout=Nones
[DEBUG             ] [Cache       ] register <kv.image> with limit=None, timeout=60s
[DEBUG             ] [Cache       ] register <kv.atlas> with limit=None, timeout=Nones
[INFO              ] [Image       ] Providers: img_tex, img_dds, img_pygame, img_pil, img_gif 
[DEBUG             ] [Cache       ] register <kv.texture> with limit=1000, timeout=60s
[DEBUG             ] [Cache       ] register <kv.shader> with limit=1000, timeout=3600s
[DEBUG             ] [App         ] Loading kv </home/mbp/workspace/KiviPlay/tata.kv>
[DEBUG             ] [Window      ] Ignored <egl_rpi> (import error)
[INFO              ] [Window      ] Provider: pygame(['window_egl_rpi'] ignored)
libpng warning: iCCP: known incorrect sRGB profile
[DEBUG             ] [Window      ] Display driver x11
[DEBUG             ] [Window      ] Actual window size: 800x600
[DEBUG             ] [Window      ] Actual color bits r8 g8 b8 a8
[DEBUG             ] [Window      ] Actual depth bits: 24
[DEBUG             ] [Window      ] Actual stencil bits: 8
[DEBUG             ] [Window      ] Actual multisampling samples: 2
[INFO              ] [GL          ] OpenGL version <4.3.12618 Compatibility Profile Context 13.251>
[INFO              ] [GL          ] OpenGL vendor <ATI Technologies Inc.>
[INFO              ] [GL          ] OpenGL renderer <AMD Radeon HD 7700 Series>
[INFO              ] [GL          ] OpenGL parsed version: 4, 3
[INFO              ] [GL          ] Shading version <4.30>
[INFO              ] [GL          ] Texture max size <16384>
[INFO              ] [GL          ] Texture max units <32>
[DEBUG             ] [Shader      ] Fragment compiled successfully
[DEBUG             ] [Shader      ] Vertex compiled successfully
[DEBUG             ] [ImagePygame ] Load </usr/lib/python2.7/site-packages/Kivy-1.8.0-py2.7-linux-x86_64.egg/kivy/data/glsl/default.png>
[INFO              ] [Window      ] virtual keyboard not allowed, single mode, not docked
[INFO              ] [Text        ] Provider: pygame
[DEBUG             ] [Cache       ] register <kv.loader> with limit=500, timeout=60s
[INFO              ] [Loader      ] using a thread pool of 2 workers
[DEBUG             ] [Cache       ] register <textinput.label> with limit=None, timeout=60.0s
[DEBUG             ] [Cache       ] register <textinput.width> with limit=None, timeout=60.0s
[DEBUG             ] [Atlas       ] Load </usr/lib/python2.7/site-packages/Kivy-1.8.0-py2.7-linux-x86_64.egg/kivy/data/../data/images/defaulttheme.atlas>
[DEBUG             ] [Atlas       ] Need to load 1 images
[DEBUG             ] [Atlas       ] Load </usr/lib/python2.7/site-packages/Kivy-1.8.0-py2.7-linux-x86_64.egg/kivy/data/../data/images/defaulttheme-0.png>
[DEBUG             ] [ImagePygame ] Load </usr/lib/python2.7/site-packages/Kivy-1.8.0-py2.7-linux-x86_64.egg/kivy/data/../data/images/defaulttheme-0.png>
[INFO              ] [GL          ] NPOT texture support is available
[INFO              ] [OSC         ] using <multiprocessing> for socket
[DEBUG             ] [Base        ] Create provider from mouse
[DEBUG             ] [Base        ] Create provider from probesysfs
[DEBUG             ] [ProbeSysfs  ] using probsysfs!
[INFO              ] [Base        ] Start application main loop
<kivy.properties.ListProperty object at 0x124f870>
function ran
[INFO              ] [Base        ] Leaving application in progress...
2个回答

13

您不能从外部线程修改kivy属性或进行任何OpenGL相关的工作。

解决方案是使用kivy的Clock调度callbacks,该回调将从kivy的主线程调用函数并为您完成工作。

个人而言,在使用第二个线程时,我使用以下方法进行线程间通信:

from Queue import Queue

 class KivyQueue(Queue):
    '''
    A Multithread safe class that calls a callback whenever an item is added
    to the queue. Instead of having to poll or wait, you could wait to get
    notified of additions.

    >>> def callabck():
    ...     print('Added')
    >>> q = KivyQueue(notify_func=callabck)
    >>> q.put('test', 55)
    Added
    >>> q.get()
    ('test', 55)

    :param notify_func: The function to call when adding to the queue
    '''

    notify_func = None

    def __init__(self, notify_func, **kwargs):
        Queue.__init__(self, **kwargs)
        self.notify_func = notify_func

    def put(self, key, val):
        '''
        Adds a (key, value) tuple to the queue and calls the callback function.
        '''
        Queue.put(self, (key, val), False)
        self.notify_func()

    def get(self):
        '''
        Returns the next items in the queue, if non-empty, otherwise a
        :py:attr:`Queue.Empty` exception is raised.
        '''
        return Queue.get(self, False)

第二个线程使用put将事物放入队列。当回调被调用时,使用trigger计划了一个kivy回调。然后kivy的主线程调用函数调用队列的get函数并设置适当的属性。
如果您需要设置许多属性,则这非常有用。如果您只需要设置单个属性,则我所做的是从第二个线程中安排一个回调,该回调使用partial使值成为函数的一部分。例如:
# this may only be called from the main kivy thread
def set_property(value, *largs):
    self.kivy_property = value

# the second thread does this when it wants to set self.kivy_property to 10
Clock.schedule_once(partial(set_property, 10))

1

它对我有效:

from kivy.app import App
from kivy.uix.label import Label
import threading

import time

class ScatterTextWidget(Label):

    def __init__(self,**kwargs):
    self.text = 'nima'
    self.color = [0, 1, 1, 1]
    super(ScatterTextWidget, self).__init__(**kwargs)
a = ScatterTextWidget()
def zaaa():
    import time
    time.sleep(3)
    a.color = [0, 0, 1, 1]
    print "function ran"   

t = threading.Thread(target= zaaa)
t.start()

class TataApp(App):
    def build(self):
        return a


if __name__ == "__main__":
    TataApp().run()

即使有时它能够工作,但在Kivy中这样做是不安全的。 - Matt
4
为什么不安全? - droptop
此外,在2021年它仍然不安全吗? - Sixtyfive

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接