简体   繁体   English

如何避免 Tkinter GUI 在 Python3 中冻结?

[英]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.

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