Kivy:标签文本在for循环期间不会更新

时间:2017-03-01 09:31:46

标签: python for-loop label kivy

当我尝试在for循环期间更新标签文本时,我遇到了问题。有类似的条目(例如:Update properties of a kivy widget while running code)但它们似乎不适合我的问题(或者我错过了重点...)。 我运行以下代码:

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

'print'语句定期更新shell,而标签文本仅在for循环结束时更新。 任何人都可以向我解释为什么Kivy以这种方式工作以及我如何克服这个问题?

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

3 个答案:

答案 0 :(得分:3)

您可以使用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()

现在值得一提的是,你可以继续按下按钮并启动线程,即使第一个尚未完成。这可能是一种不受欢迎的行为 这可以通过禁用线程开头的按钮,并在结束时再次启用它来防止。

在kv中为按钮指定一个id:

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

答案 1 :(得分: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,而Clock类显然需要它(没有它,它会使我的代码出现问题)

我仍然将do_the_loop()函数放入一个单独的线程中。但这就是kivy为它提供的东西。 If you want to know more about the clock Class head over here.

答案 2 :(得分:0)

我相信你需要做的就是把

root.update()

每当您希望 GUI 更新时,因此在循环中,在文本更改完成后。在 tkinter 中像魅力一样工作。您还可以通过将 root(或 main)更改为文本区域的名称来限制对特定文本区域的更新。