2017-03-01 75 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.