Kivy-如何在循环中调用trigger_action()使其正常运行?

时间:2019-02-05 05:02:28

标签: python kivy

我想模拟一个反复按下的按钮。示例:如果按下按钮2,则按钮1应该激活,并在设定的时间间隔内点亮for循环中设置的次数。我简化了下面的代码。

问题是,trigger_action()方法中的'duration'属性不能正确地调节循环的时间,并且打印功能和按钮立即亮起。

我试图在for循环中插入time.sleep()函数以“减慢速度”。这确实可以正确计时打印功能,但是,模拟的按钮按下(按钮点亮)不是按固定的间隔发生,而是一次完成。

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button


class TestApp(App):
    def build(self):
        layout = BoxLayout()
        self.b1 = Button(text="Button 1", on_press=self.on_press_button_1)
        self.b2 = Button(text="Button 1", on_press=self.on_press_button_2)
        layout.add_widget(self.b1)
        layout.add_widget(self.b2)
        return layout

    def on_press_button_1(self, *args):
        print("on press button 1")

    def on_press_button_2(self, *args):
        for x in range(5):
            self.b1.trigger_action(0.5)
            print(x, "on press button 2")

if __name__ == "__main__":
    TestApp().run()

1 个答案:

答案 0 :(得分:0)

使用kivy进行编程时,必须记住所有GUI事件都在主线程上发生,并且所有代码(除非采取预防措施)也将在主线程上运行。因此,您的for循环正在主线程上运行,并且如果您向该循环中添加sleep,它也将在主线程上运行。因此该代码使主线程处于繁忙状态。结果是您的所有trigger_action调用(以及任何其他更改GUI的调用)都必须等到您的代码停止保留主线程之后才能影响GUI。因此,在您的for循环结束时,GUI有机会赶上来,并且所有等待的GUI按钮效果都已执行,并显示为一长按。通常,您希望GUI事件调用的任何方法(例如按下按钮)尽快返回或创建新线程进行冗长的处理。

因此,这是使代码正常工作的一种方法:

from kivy.app import App
from kivy.clock import Clock
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button


class TestApp(App):
    def build(self):
        layout = BoxLayout()
        self.b1 = Button(text="Button 1", on_press=self.on_press_button_1)
        self.b1.click_count = 0
        self.max_clicks = None
        self.clock_event = None
        self.b2 = Button(text="Button 2", on_press=self.on_press_button_2)
        layout.add_widget(self.b1)
        layout.add_widget(self.b2)
        return layout

    def on_press_button_1(self, *args):
        print("on press button 1")
        if self.max_clicks is not None and self.clock_event is not None:
            self.b1.click_count += 1
            if self.b1.click_count >= self.max_clicks:
                self.clock_event.cancel()
                self.clock_event = None
                self.max_clicks = None

    def on_press_button_2(self, *args):
        self.max_clicks = 5
        self.b1.click_count = 0
        self.clock_event = Clock.schedule_interval(lambda dt: self.b1.trigger_action(), 1)

if __name__ == "__main__":
    TestApp().run()

这使用Clock.schedule_interval来安排某些内容在主线程上运行,但立即返回,以允许GUI正常运行。 Clock.schedule_interval()使用参数dt(自计划事件以来的时间)调用指定的方法,但是trigger_action()不需要这样的参数,因此我使用了{{1 }}。参见documentationlambdaclick_countmax_clicks仅用于管理事件的取消。