【问题标题】:Getting Kivy to update PopUp before finishing execution of function called by button在完成按钮调用的函数执行之前让 Kivy 更新 PopUp
【发布时间】:2020-09-29 14:01:06
【问题描述】:

关于问题: 在 sutPopUp.create() 中,我试图让弹出窗口自行更新(删除它的两个按钮并更改“隐藏”标签) .我已经尝试过线程更新函数和调用 Clock.schedule_once(self.update_txt, -1),但都没有工作。他们似乎都在等待 run_local_command,这只是一个运行本地命令的阻塞函数。下面是python代码:

class sutPopUp(Popup):
    pop_float = ObjectProperty(None)
    sutPopUp_create = ObjectProperty(None)
    sutPopUp_cancel = ObjectProperty(None)
    sut_wait_text = ObjectProperty(None)
    sutPopUp_input = ObjectProperty(None)

    def __init__(self, my_widget,**kwargs):
        super(sutPopUp,self).__init__(**kwargs)
        self.title = "Test Station Setup"
        self.size_hint = (None, None)
        self.size = (400, 200)

    def create(self, *args):
        self.quick_change_thread = threading.Thread(target=self.update_txt)
        self.quick_change_thread.start()
        time.sleep(1)

        sut_name = self.sutPopUp_input.text
        create_cmd = "python project.py -c " + sut_name
        create_handle = run_local_command(create_cmd, True, "C:\Project")

        wm.current = "blank"
        wm.remove_widget(screens[2])
        screens[2] = Dashboard(name="dashboard_screen")
        wm.add_widget(screens[2])
        wm.current = "dashboard_screen"

        self.dismiss()
        self.quick_change_thread.join()

    def update_txt(self):
        self.sutPopUp_create.disabled = True
        self.sutPopUp_cancel.disabled = True
        self.pop_float.remove_widget(self.sutPopUp_create)
        self.pop_float.remove_widget(self.sutPopUp_cancel)
        self.sut_wait_text.text = "Creating Test Station ..."

这是kv:

<sutPopUp@Popup>
    pop_float:pop_float
    sutPopUp_create:sutPopUp_create
    sutPopUp_cancel:sutPopUp_cancel
    sut_wait_text:sut_wait_text
    sutPopUp_input:sutPopUp_input

    FloatLayout:
        id: pop_float
        size: root.height, root.width
        Label:
            text: "Enter Test Station Name:"
            pos_hint:{"x":0.1,"top":0.9}
            size_hint: 0.25, 0.2
        TextInput:
            id: sutPopUp_input
            multiline: False
            pos_hint:{"x":0,"top":0.7}
            size_hint: 1, 0.2
        Label:
            id: sut_wait_text
            text: ""
            pos_hint:{"x":0.4,"top":0.3}
            size_hint: 0.25, 0.2
        Button:
            id: sutPopUp_create
            text: "Create"
            pos_hint:{"x":0.1,"top":0.3}
            size_hint: 0.3, 0.2
            on_release: root.create()

        Button:
            id: sutPopUp_cancel
            text: "Cancel"
            pos_hint:{"x":0.6,"top":0.3}
            size_hint: 0.3, 0.2
            on_release: root.dismiss()

【问题讨论】:

  • 您的blocking 函数显然是blocking。如果它不返回,那么一切都将被阻止。也许您的run_local_command 应该类似于run_local_command_in_another_thread()
  • @JohnAnderson 我尝试在另一个线程中运行本地命令,但这并不能解决问题。我需要弹出窗口自行更新,然后等待命令完成,然后使用本地命令创建的新文件切换回它所在的屏幕(更新)。所以,我所做的是在run_local_command_in_another_thread() 中设置一个线程布尔变量,以便主线程知道 cmd 何时完成,但这仍然只是阻止主线程更新。
  • @JohnAnderson 在 kivy 中是否有办法强制弹出窗口在阻塞函数内部进行更新?或者,告诉 screenmanager 从不是主线程的线程中切换屏幕?

标签: python multithreading popup kivy clock


【解决方案1】:

我建议将create() 方法分成三个方法。由于create()方法是由Button按下发起的,它会运行在主线程上,所以直接调用update_text()方法即可。然后使用另一个线程运行create_cmd。然后,该新线程使用Clock.schedule_once() 将原始create() 方法(新的finish_create() 方法)的剩余代码运行回主线程。

def create(self, *args):
    self.update_text()  # this needs to run on the main thread
    # time.sleep(1)  # ??? this will freeze your app for 1 second

    Thread(target=self.do_create).start()

def do_create(self):
    sut_name = self.sutPopUp_input.text
    create_cmd = "python project.py -c " + sut_name
    create_handle = run_local_command(create_cmd, True, "C:\Project")

    # after above command completes, run the rest of the former create() back on the main thread
    Clock.schedule_once(self.finish_create)

def finish_create(self, dt):
    wm.current = "blank"
    wm.remove_widget(screens[2])
    screens[2] = Dashboard(name="dashboard_screen")
    wm.add_widget(screens[2])
    wm.current = "dashboard_screen"

    self.dismiss()

无论你做什么,当有一个函数保持主线程时,GUI 中的任何内容都不会更新。所以这种方法最大限度地减少了花在主线程上的时间。此代码未经测试,因此可能存在错误。但我相信这种方法应该可以实现您想要的。

【讨论】:

  • 谢谢你,这么多的人!那行得通!我没想到从线程内部运行时钟,所以谢谢你!!!
猜你喜欢
  • 1970-01-01
  • 2019-02-22
  • 2021-01-07
  • 2012-08-10
  • 2020-08-05
  • 1970-01-01
  • 2021-08-02
  • 2018-08-12
  • 1970-01-01
相关资源
最近更新 更多