Kivy 标签文本未更新 - 仅在方法的最后一次更改时更新
Posted
技术标签:
【中文标题】Kivy 标签文本未更新 - 仅在方法的最后一次更改时更新【英文标题】:Kivy Label text not updating - only updates at the last change in the method 【发布时间】:2021-02-28 23:10:36 【问题描述】:使用 Kivy 1.11.1 和 Python 3.7.6。
我有这个特殊的问题,我无法在任何地方找到答案。
我想在按钮按下时调用的方法中两次更新 Label 的文本(此处为:status
Label)(在本例中为display_hello_status()
。但似乎Kivy 仅在方法调用完成后 更新接口 - 仅导致对标签文本的最新更改呈现。
您可以在下面找到有问题的方法的代码。
main.py:
import time
import kivy
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.app import App
kivy.require('1.11.1')
class WindowManager(ScreenManager):
pass
class PrintHello(Screen):
username = ObjectProperty(None)
status = ObjectProperty(None)
def display_hello_status(self):
# Inform about process of generating hello text.
self.status.text = "printing hello..." # this text is never displayed.
# Pretend something is happening in the background.
time.sleep(2)
self.username.text = f"Hello, self.username.text!"
# Display information indicating successful printing.
self.status.text = "printed!"
class MyApp(App):
pass
if __name__ == '__main__':
MyApp().run()
my.kv:
WindowManager:
PrintHello:
<PrintHello>:
username: username_text_input
status: status_label
BoxLayout:
orientation: "vertical"
GridLayout:
cols: 2
padding: 8
spacing: 8
Label:
text: "Your name:"
size_hint_y: None
height: 32
bold: True
TextInput:
id: username_text_input
size_hint_y: None
height: 32
multiline: False
FloatLayout:
Button:
text: "Print"
size_hint: 0.2, 0.2
pos_hint: "center_x": 0.6, "y": 0.4
on_release: root.display_hello_status()
BoxLayout:
orientation: "horizontal"
size_hint: 0.2, 0.2
pos_hint: "center_x": 0.2, "y": 0.4
padding: 4
Label:
text: "Status:"
bold: True
Label:
id: status_label
text: "off"
background_color: 0, 0, 0, 0 # black
color: 1, 1, 1, 1 # white
所以我想要实现的是:
-
通过文本和颜色更改通知用户某些过程正在进行。
在后台做一些处理,需要一些时间(模拟
time.sleep(2)
。
显示程序成功完成进程的信息。
问题是:我该怎么做?如何强制 Widget(在本例中为标签)在方法中间更新?
谢谢!
【问题讨论】:
请发minimal reproducible example。 @JohnAnderson 我按照建议实现了该问题的独立版本。感谢您的帮助! 【参考方案1】:问题是只要你有一个在主线程上运行的方法,就像你的display_hello_status()
一样,kivy 是无法更新 GUI 的。因此,当display_hello_status()
方法运行时,会对username
和status
小部件进行更改,但是这些更改不能由kivy 显示,直到它有机会在主线程上运行。到 kivy 恢复主线程时,第一个更改已经再次更改,因此只显示最终更改。
解决方法是快速从display_hello_status()
方法返回,让kivy 反映您所做的更改。 background
实际上可以使用Thread
在后台运行。然后Thread
可以在主线程上安排另一个 GUI 更新。
通常,您应该避免在主线程上进行冗长的处理。由于事件(如按下按钮)而运行的任何内容都将在主线程上运行。因此,在另一个线程(或在某些情况下甚至是另一个进程)上进行该处理允许 kivy 使 GUI 保持最新和响应。除此之外,您对 GUI 所做的任何更改都应在主线程上完成。这就是Clock.schedule_once()
派上用场的地方。
这是您的 PrintHello
类的修改版本,它遵循上述建议:
class PrintHello(Screen):
username = ObjectProperty(None)
status = ObjectProperty(None)
def display_hello_status(self):
# Inform about process of generating hello text.
self.status.text = "printing hello..." # this text is never displayed.
# Pretend something is happening in the background. Actually make it happen on a background thread
threading.Thread(target=self.do_somehing).start()
def do_somehing(self):
print('starting something')
time.sleep(2)
print('finished something')
# schedule the GUI update back on the main thread
Clock.schedule_once(self.something_finished)
def something_finished(self, dt):
self.username.text = f"Hello, self.username.text!"
# Display information indicating successful printing.
self.status.text = "printed!"
【讨论】:
以上是关于Kivy 标签文本未更新 - 仅在方法的最后一次更改时更新的主要内容,如果未能解决你的问题,请参考以下文章