简体   繁体   English

如何创建不确定的进度并在后台启动线程,然后在python中完成线程后再次执行一些操作

[英]How to create an indeterminate progress and start a thread in background and again do some operation after the thread is complete in python

I am trying create a indeterminate progress bar in python 3 in new top level window for some process and then starting the thread for that process. 我正在尝试在新顶层窗口的python 3中为某个进程创建一个不确定的进度条,然后为该进程启动线程。 What I want is that the progress bar starts and the thread is also started in background and as soon as the thread completes executing, some message is shown that the task is complete. 我想要的是进度条启动,并且线程也在后台启动,一旦线程完成执行,就会显示一些消息,说明任务已完成。

Code : 代码:

class myThread(threading.Thread):
    def __init__(self, threadID):
        threading.Thread.__init__(self)
        self.threadID = threadID


    def run(self):
        print("Starting the thread")
        func()
        print("Ending the thread")

def func():
    some task

...
new_top = Toplevel()
new_top.title("New Top Level")
new_top.geometry("400x170")

label = Label(new_top, text='Doing some work', justify=CENTER, bg="#CBFDCB").place(x=43,y=30)

progress_bar = ttk.Progressbar(new_top, orient="horizontal", mode="indeterminate", takefocus=True, length=320)
progress_bar.place(x=40, y=80)
progress_bar.start()

thread1 = myThread(1)
thread1.start()
thread1.join()

...

Perform post thread operations 执行线程后操作

What my problem is, the top level window with label and progress bar never appears if thread1.join() is called and if i skip this part , then the operations post thread execution does not run 我的问题是,如果调用thread1.join(),并且带有标签和进度条的顶级窗口永远不会出现,并且如果我跳过了这一部分,则线程执行后的操作将无法运行

TKinter works by using an infinite main loop to wait for and process events - intercept presses, redraw elements etc. (Take a look here for some more info). TKinter通过使用无限的主循环来等待和处理事件-拦截印刷机,重绘元素等来工作(请在此处查看更多信息)。

When you call join() , you force your main thread (in which tkinter runs) to wait until your newly started thread finished executing before proceeding, hence it is unable to draw your toplevel window with a progress bar. 当您调用join() ,您迫使主线程(运行tkinter的线程)等待直到新启动的线程完成执行后再继续操作,因此无法使用进度条绘制顶层窗口。 Thus, this is not really an option. 因此,这不是真正的选择。

On the other hand, you need to know when your child thread has finished executing. 另一方面,您需要知道子线程何时完成执行。 You could check if the thread is still alive by using mythread.isAlive() , but then you can't do it in a loop, as it will again stop the tkinter's main loop from execution and thus drawing the interface. 您可以使用mythread.isAlive()检查线程是否仍然处于活动状态,但是您不能在循环中进行操作,因为它将再次使tkinter的主循环停止执行并从而绘制接口。 I suggest looking at the answer here to deal with this problem. 我建议在这里查看答案以解决此问题。

It can be a little tricky doing threading stuff with Tkinter. 用Tkinter进行线程处理可能有点棘手。 Here's some code that does what you want. 这是一些您想要执行的代码。 My first version didn't work properly because I tried to destroy the Tkinter window from inside the thread's .run method. 我的第一个版本无法正常工作,因为我试图从线程的.run方法内部破坏Tkinter窗口。 That didn't work: the window closed, but the .run method didn't progress after the root.destroy call. 那是行不通的:窗口关闭了,但是root.destroy调用后.run方法没有root.destroy So now we have a function that checks every 100 milliseconds to see if the thread is still alive, and if it's not alive we close the Tkinter window. 因此,现在我们有了一个函数,该函数每100毫秒检查一次线程是否仍然处于活动状态,如果线程仍然处于活动状态,则关闭Tkinter窗口。

import threading
import tkinter as tk
from tkinter import ttk
from time import sleep

class myThread(threading.Thread):
    def __init__(self, threadID):
        threading.Thread.__init__(self)
        self.threadID = threadID

    def run(self):
        print("Starting the thread")
        func()
        print("Ending the thread")

def func():
    for i in range(10):
        print(i)
        sleep(1)

def check_thread(th):
    if not th.isAlive():
        root.destroy()
    root.after(100, check_thread, th)

root = tk.Tk()
root.title("New Top Level")
root.geometry("400x170")

tk.Label(root, text='Doing some work', justify=tk.CENTER, bg="#CBFDCB").place(x=43, y=30)
progress_bar = ttk.Progressbar(root, orient="horizontal", 
    mode="indeterminate", takefocus=True, length=320)
progress_bar.place(x=40, y=80)
progress_bar.start()

thread1 = myThread(1)
thread1.start()
root.after(100, check_thread, thread1)
root.mainloop()

print("Doing post-thread stuff")

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM