如何实时更新 Kivy Scrollview Label?

How to update a Kivy Scrollview Label in real time?

我真的很需要一些帮助来解决我实际上非常简单的 Python Kivy 问题!我写了一个程序,首先宣布数到 5,然后应该开始从 1 数到 5。信息应该显示在滚动视图标签中。该代码大致完成了它的工作,但不会逐步更新滚动视图,而是在时间过去后立即全部更新......有人可以帮忙吗?提前致谢!

import kivy
from kivy.config import Config
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.core.window import Window
from kivy.uix.scrollview import ScrollView
import time
 
kivy.require("2.0.0")
Config.set('kivy', 'keyboard_mode', 'systemandmulti')
 
class MainMenu(GridLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.cols = 1
        self.rows = 2
        
        self.infowindow = ScrollableInfo(height=Window.size[1]*0.8, size_hint_y=None)
        self.add_widget(self.infowindow)
 
        self.ButtonCheckConnection = Button(text="Start Counting to 5")
        self.ButtonCheckConnection.bind(on_press=self.countingtofive)
        self.add_widget(self.ButtonCheckConnection)
 
    def countingtofive(self, *_):
        self.infowindow.update_scrollview(f"Counting to 5 is going to start in 3 seconds")
        time.sleep(3)
        countingmaximum = 5
 
        for i in range(countingmaximum):
            currentnumber = i+1
            self.infowindow.update_scrollview(str(currentnumber))
            time.sleep(1)
 
 
 
class ScrollableInfo(ScrollView):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.layout = GridLayout(cols=1, size_hint_y=None)
        self.add_widget(self.layout)
 
        self.connectioninfo_history = Label(size_hint_y=None, markup=True)
 
        self.layout.add_widget(self.connectioninfo_history)
 
    def update_scrollview(self, newinfo):
        self.connectioninfo_history.text += '\n' + newinfo
        
        self.layout.height = self.connectioninfo_history.texture_size[1]+15
        self.connectioninfo_history.height = self.connectioninfo_history.texture_size[1]
        self.connectioninfo_history.text_size = (self.connectioninfo_history.width*0.98, None)
 
class Counting(App):
    def build(self):
        self.screen_manager = ScreenManager()
 
        self.mainmenu_page = MainMenu()
        screen = Screen(name="MainMenu")
        screen.add_widget(self.mainmenu_page)
        self.screen_manager.add_widget(screen)
 
        return self.screen_manager
 
if __name__ == "__main__":
    counting_app = Counting()
    counting_app.run()

问题是您在主线程上 运行ning 您的 countingtofive() 方法。因为 Kivy 使用主线程来更新 GUI,所以在你释放主线程(通过从 countingtofive() 方法返回)之前它不能这样做。这就是为什么在该方法完成之前你看不到任何东西的原因。

要解决这个问题,运行 另一个线程中的 countingtofive() 方法,如下所示:

def start_counting_thread(self, *args):
    Thread(target=self.countingtofive, daemon=True).start()

并更改 Button 以绑定到 start_counting_thread() 方法:

    self.ButtonCheckConnection.bind(on_press=self.start_counting_thread)

并对 update_scrollview() 方法做了一个小改动(添加 @mainthread 装饰器):

@mainthread
def update_scrollview(self, newinfo):

@mainthread 装饰器强制装饰方法在主线程上 运行。同样可以使用 Clock.schedule_once() 来完成,但装饰器更容易。只是实际更新 GUI 的代码必须在主线程上 运行。一般来说,你应该尽量避免在主线程上使用长 运行ning 方法。