[英]How can i avoid Tkinter GUI freezing in Python3?
I am quite new in python and made a Tkinter application that will execute all python files existing in the directory when pressed the start button.我是 python 的新手,并制作了一个 Tkinter 应用程序,当按下开始按钮时,该应用程序将执行目录中存在的所有 python 文件。 My GUI also has progressbar to see the current progress.
我的 GUI 也有进度条来查看当前进度。
so here is my code所以这是我的代码
import os
from tkinter import *
from tkinter.ttk import *
from tkinter import messagebox
directory = dir_path = os.path.dirname(os.path.realpath(__file__))
files = os.listdir(directory)
root = Tk()
root.geometry('200x200')
root.maxsize(200,200)
root.minsize(200,200)
root.title('PYTOEXE')
v = 0
def begin():
global v
for x in files:
os.system('pyinstaller '+x)
v=v+1
p['value']=v
p = Progressbar(root,length=200,max=len(files))
b = Button(root,text="Start",command=lambda: begin())
p.place(x=0,y=0)
b.place(x=62,y=30)
root.mainloop()
but my problem is, Whenever i press start button, The GUI freezes and codes start getting compiled and when completed, the GUI unfreezes and the Progressbar fills itself full at once...但我的问题是,每当我按下开始按钮时,GUI 冻结,代码开始编译,完成后,GUI 解冻,进度条立即填满......
So i want the GUI not to freeze while processing and show correct progress on the Progressbar.所以我希望 GUI 在处理时不要冻结并在进度条上显示正确的进度。
Example code and Explanation will be better for me.示例代码和解释对我来说会更好。
Thanks for your valuable time...感谢您宝贵的时间...
This worked.No need to use .after()
to check the thread is finished.这行得通。无需使用 .after
.after()
来检查线程是否完成。
import os
from tkinter import *
from tkinter.ttk import *
import threading
def use_pyinstaller(): # this function is to execute pyinstaller command and add value to progressbar.
v = 0
for x in files:
os.system('pyinstaller '+x)
v+=1
p['value'] = v
def begin():
threading.Thread(target=use_pyinstaller).start() # create a non-block thread to start the function.
directory = dir_path = os.path.dirname(os.path.realpath(__file__))
files = os.listdir(directory)
root = Tk()
root.geometry('200x200')
root.maxsize(200,200)
root.minsize(200,200)
root.title('PYTOEXE')
p = Progressbar(root,length=200,max=len(files))
b = Button(root,text="Start",command=begin)
p.place(x=0,y=0)
b.place(x=62,y=30)
root.mainloop()
First off, the command
argument for the button can just be: command=begin
.首先,按钮的
command
参数可以是: command=begin
。
GUI toolkits like tkinter
are event-driven .像
tkinter
这样的 GUI 工具包是事件驱动的。 They depend on a smooth flow of keyboard and mouse events to work properly.它们依赖于流畅的键盘和鼠标事件流才能正常工作。 Callbacks (like the
command
from a button) are called from witin the event loop ( root.mainloop
).回调(如按钮的
command
)是从事件循环( root.mainloop
)中调用的。 So a callback should only take a short time (say 50 ms) as to not freeze the GUI.因此,回调应该只需要很短的时间(比如 50 毫秒)就不会冻结 GUI。 You should therefore never run a long-running loop in a callback.
因此,您不应该在回调中运行长时间运行的循环。 You have to program in a different style .
你必须以不同的风格进行编程。
The above link takes you to an article on my website where I compare a simple command-line program with an equivalent GUI program.上面的链接将您带到我网站上的一篇文章,我将一个简单的命令行程序与等效的 GUI 程序进行了比较。 While that program doesn't use external processes, it illustrates the principle.
虽然该程序不使用外部进程,但它说明了原理。
The proper way to do this in a GUI, is to start a multiprocessing.Process
from the button callback.在 GUI 中执行此操作的正确方法是从按钮回调启动
multiprocessing.Process
。 Then use the root.after
method to periodically run a callback that checks if the Process
is finished, and then start a new process.然后使用
root.after
方法定期运行一个回调来检查Process
是否完成,然后启动一个新进程。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.