使用进度条调用 Kivy 应用程序的顺序线程

Calling sequential Threads for Kivy app with Progress Bar

我正在编写一个 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()

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

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

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

由于 while 循环与 Kivy 不一致,我使用了我认为是 while 循环的 Kivy 替代方法,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" 部分。这可能会导致前面流程和最后流程的每个组合的代码段越来越大。如果有人知道更漂亮、更高级的版本,我洗耳恭听!