【问题标题】:Calling sequential Threads for Kivy app with Progress Bar使用进度条为 Kivy 应用程序调用顺序线程
【发布时间】:2021-09-03 10:33:49
【问题描述】:

我正在编写一个 Kivy 应用程序,其中用户提供各种输入,然后单击一个按钮,该按钮应该调用一系列 python 函数,这些函数在顺序后台线程中运行,同时在 GUI 中更新进度条。我有三个函数应该一个接一个地调用,在前一个函数完成并且进度条为 100% 之后,进度条返回 0% 并报告下一个函数的进度等。问题是,如果我按顺序调用它们,看起来它们在后台同时运行,只有最后一个更新进度条。如何设置线程仅在前一个线程完成后才被调用?

我尝试了join 方法,但它只是通过将线程放在主线程上来冻结 GUI。

这是按下按钮时调用的当前函数:

scripts_to_run = ListProperty([])

def process_data(self):
    to_run = []
    if "move_data" in self.scripts_to_run:
        self.move_data()
        to_run.append(Thread(target=self.produce_data_file))
    if "histograms" in self.scripts_to_run:
        to_run.append(Thread(target=self.histograms))
    if "log_histograms" in self.scripts_to_run:
        to_run.append(Thread(target=self.log_histograms))

    for thread in to_run:
        thread.start()

【问题讨论】:

    标签: python kivy kivy-language


    【解决方案1】:

    您只需要在前一个线程完成后运行每个下一个线程,因此您将使用如下条件语句:

    if not thread1.is_alive():
        thread2.start()
            if not thread2.is_alive():
                thread3.start()
    

    【讨论】:

    • 我试过这个,问题是条件语句只被触发一次,而第一个线程仍在运行,所以一旦第一个线程完成,它们就不会再次被调用。
    • 在第一次完成之前不要运行线程
    • 这就是您发布的代码所做的,它调用第一个线程,然后立即调用条件语句,因为第一个线程还活着,所以没有调用其他线程,但条件语句是'没有再次调用
    • 我试过 while 循环,但他们似乎不同意 Kivy
    • 好吧,这意味着当最后一个线程死掉时,你希望第一个线程再次运行,对吧?
    【解决方案2】:

    因此,在 @TwfyqBhyry 的帮助下,我设法将一个可行的解决方案组合在一起,但可能有一种更巧妙的方法。

    由于 while 循环与 Kivy 不一致,我使用我认为的 Kivy 替代 while 循环 Clock.schedule_interval 来重复调用一个函数,该函数检查一个线程是否处于活动状态并在何时调用下一个线程前一个已经不存在了。

    scripts_to_run = ListProperty([])
    
    def process_data(self):
        for script in self.scripts_to_run:
            if script == "move_data":
                self.move_data()
                move_data_thread = Thread(target=self.produce_data_file)
                move_data_thread.start()
            if script == "histograms":
                histo_thread = Thread(target=self.histograms)
                if move_data_thread.is_alive():
                    self.event = Clock.schedule_interval(partial(self.check_for_thread, move_data_thread, histo_thread))
                else:
                    histo_thread.start()
            if script == "log_histograms":
                log_histo_thread = Thread(target=self.log_histograms)
                if move_data_thread.is_alive():
                    self.event = Clock.schedule_interval(partial(self.check_for_thread, move_data_thread, log_histo_thread), 1)
                elif histo_thread.is_alive():
                    self.event = Clock.schedule_interval(partial(self.check_for_thread, histo_thread, log_histo_thread), 1)
                else:
                    log_histo_thread.start()
        
    def check_for_thread(self, thread1, thread2, dt):
        if thread1.is_alive():
            pass
        elif thread2.is_alive():
            self.event.cancel()
        else:
            thread2.start()
    

    虽然该方法在这种情况下运行良好,但您需要为所需的每个进程的代码添加一个新的if script == "function_tag" 部分。这可能会导致先前进程和最后一个进程的每个组合的代码段越来越大。如果有人知道更流畅、更可升级的版本,我会全力以赴!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多