2014-02-26 33 views
5

我正在試驗一些kivy代碼。我嘗試用線程庫創建一個腳本來修改一個kivy屬性(text_colour)。程序工作正常,但線程不會更改屬性。從另一個線程變更kivy屬性

我也嘗試在類中創建一個方法,該方法獲取值作爲參數,也失敗了。

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

OUTPUT:

[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... 

回答

4

不能修改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) 

第二個線程採用放放東西的隊列。當回調函數被調用時,使用trigger安排一個kivy回調。 kivy主線程調用的函數調用隊列的get函數並設置相應的屬性。

如果您需要設置許多屬性,這會很有幫助。如果你只需要設置一個屬性,我所做的就是從第二個線程中調度一個callabck,它使用partial來使值的一部分成爲函數的一部分。 E.g:

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