2017-03-01 77 views
4

我尝试在for循环中更新标签文本时出现问题。有类似的条目(例如:Update properties of a kivy widget while running code),但它们似乎并不完全符合我的问题(或者我错过了这一点...)。 我运行下面的代码:Kivy:标签文本在for循环中不更新

*的.py:

from kivy.app import App 
from kivy.uix.boxlayout import BoxLayout 
from kivy.properties import StringProperty 
#from time import sleep 

class MyBox(BoxLayout): 
    tobeupd = StringProperty() 

    def __init__(self,*args,**kwargs): 
     super(MyBox,self).__init__(*args,**kwargs) 
     self.tobeupd = '#' 

    def upd_ltxt(self): 
     for i in range(1,10): 
      self.tobeupd = str(i) 
      print(self.tobeupd) 
      input('Write something: ') # new line, see edit below 
      #sleep(0.5) 

class updApp(App): 
    def build(self): 
     return MyBox() 

if __name__ == '__main__': 
    updApp().run() 

* .kv

<MyBox>: 
    orientation: 'horizontal' 
    cols: 2 
    Label: 
     text: root.tobeupd 
    Button: 
     text: 'Start Update' 
     on_release: root.upd_ltxt() 

尽管 '印刷' 在声明的最后定期更新的外壳,标签文字更新仅for循环。 任何人都可以向我解释为什么Kivy以这种方式工作,以及我如何克服这个问题?

编辑:根据PM2Ring和Gugas,我改变了代码,以避免睡眠功能。如果我要求用户在继续循环之前输入内容,问题依然存在。值在shell中更新,但不在标签上。

+0

我不知道Kivy,但在GUI代码中调用'time.sleep'通常是个坏主意,因为它会阻塞_everything_,所以GUI引擎没有机会更新布局。如果您需要延迟,您必须使用GUI框架为此提供的功能/方法。 –

+0

@ PM2Ring实际上是正确的,系统可能会更改标签,并在被睡眠打中后不会更新,尝试没有睡眠声明并检查问题是否仍然存在。 –

+0

@ PM2ring,Gugas:我编辑了代码,但问题依然存在。任何想法? – dade100

回答

2

您可以使用threading
当您在kivy中执行循环或等待输入时,主线程正在等待,并且没有任何内容会在应用程序上更新。 threading会阻止这一点。
使用threading在主线程之外创建另一个线程。
例子:

from kivy.app import App 
from kivy.uix.boxlayout import BoxLayout 
from kivy.properties import StringProperty 
from kivy.lang import Builder 
import threading 

Builder.load_string(''' 

<MyBox>: 
    orientation: 'horizontal' 
    cols: 2 
    Label: 
     text: root.tobeupd 
    Button: 
     text: 'Start Update' 
     on_release: root.upd_ltxt() 

''') 

class MyBox(BoxLayout): 
    tobeupd = StringProperty() 

    def __init__(self,*args,**kwargs): 
     super(MyBox,self).__init__(*args,**kwargs) 
     self.tobeupd = '#' 

    def upd_ltxt(self): 
     threading.Thread(target=self.update_label).start() 

    def update_label(self): 
     for i in range(1,10): 
      print(self.tobeupd) 
      self.tobeupd = str(i) 
      input('Write something: ') # new line, see edit below 



class updApp(App): 
    def build(self): 
     return MyBox() 

if __name__ == '__main__': 
    updApp().run() 

现在,它值得一提的,你可以保持按下按钮,启动线程,即使起初并没有结束。这可能是一种不需要的行为。
这可以通过禁用线程开始处的按钮并在最后再次启用它来防止。

给该按钮的ID在KV:

Button: 
    id: updatebutton 
    text: 'Start Update' 
    on_release: root.upd_ltxt() 

而在线程这样做:

def update_label(self): 

    self.ids.updatebutton.disabled = True 

    for i in range(1,10): 
     self.tobeupd = str(i) 
     input('Write something: ') 

    self.ids.updatebutton.disabled = False 
0

您还可以使用Kivys clock类,这是一个事件调度。它会安排一个事件,这是一个功能。例如,更新标签文本。

from kivy.clock import Clock 

def to_be_called_back(self,dt): 
    print("This function should be periodically executed") 

def do_the_loop(self): 
    Clock.schedule_interval(self.to_be_called(),0.5) 

这里函数to_be_called()将每0.5秒调用一次。 dt变量代表deltatime,只是显然需要的时钟类(没有它,它使我的代码的问题)

我仍然把do_the_loop()函数放入一个单独的线程。但那是基维为它提供的。 If you want to know more about the clock Class head over here.