首页 文章

tkinter避免GUI冻结

提问于
浏览
-1

我开发了一个简单的Python应用程序,然后我决定使用Tkinter添加一个简单的GUI .

问题是,当我调用一个名为startprocess的函数并开始处理处理器很重的东西并且窗口冻结时 .

我知道这是一个常见的问题,我已经读过我应该使用多线程(非常复杂,因为函数也更新了GUI)或者将我的代码分成不同的函数,每个函数都工作了一段时间 . 无论如何,下面的代码需要修改以避免GUI冻结?

import threading
import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
import os, datetime, sys, subprocess
import parselog_v1


# diplay messagebox window
def MessageBox(windowLable,msg):
   messagebox.showinfo(windowLable, msg)


# check if Dir empty
def checkDirEmpty(work_path):
    if os.path.isdir(work_path):
        if not os.listdir(work_path):
            print ("No Files found in directory")
            MessageBox('Log Parser', 'No Files found in directory.')
        else:
            return True



# launch app in center of screen
def center_window(width=300, height=200):
    # get screen width and height
    screen_width = root.winfo_screenwidth()
    screen_height = root.winfo_screenheight()
    # calculate position x and y coordinates
    x = (screen_width/2) - (width/2)
    y = (screen_height/2) - (height/2)
    root.geometry('%dx%d+%d+%d' % (width, height, x, y))

# application frame

class Application(tk.Frame):

    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.pack()
        self.createWidgets()
        self.master.title("Log Parser")

    def createWidgets(self):
        self.Run_Main = tk.Button(self)
        self.Run_Main["text"] = "Browse for logs"
        self.Run_Main["fg"] = "blue"
        self.Run_Main["command"] = self.startProcess
        self.Run_Main.pack(side='left',padx=0)

        self.QUIT = tk.Button(self)
        self.QUIT["text"] = "Quit!"
        self.QUIT["fg"]   = "red"
        self.QUIT["command"] =  self.quit
        self.QUIT.pack(side='right',padx=5)

    def startProcess(self):
        global Src_foldername
        Src_foldername = filedialog.askdirectory()
        Src_foldername = Src_foldername.replace("/", "\\")
        print("Source folder: " + Src_foldername)
        if checkDirEmpty(Src_foldername):
            # process logs
            # multithread
            print("Processing...")
            self.refresh()
            threading.Thread(target=parselog_v1.main(Src_foldername))



# scroll text inside application frame
class scrollTxtArea:

    def __init__(self, root):
        frame = tk.Frame(root)
        frame.pack()
        self.textPad(frame)
        return

    class IORedirector(object):
        '''A general class for redirecting I/O to this Text widget.'''
        def __init__(self, text_area):
            self.text_area = text_area

    class StdoutRedirector(IORedirector):
        '''A class for redirecting stdout to this Text widget.'''



    def textPad(self, frame):
        # add a frame and put a text area into it
        textPad = tk.Frame(frame)
        self.text = tk.Text(textPad, height=21, width=68)
        self.text.config()
        # add a vertical scroll bar to the text area
        scroll = tk.Scrollbar(textPad)
        self.text.configure(yscrollcommand=scroll.set,background="black", foreground="green")
        # pack everything
        self.text.pack(side=tk.LEFT, pady=2)
        scroll.pack(side=tk.RIGHT, fill=tk.Y)
        textPad.pack(side=tk.TOP)
        self.text.insert("end", "Begin by selecting log folder..." + "\n")
        self.text.configure(state='disabled') # disable text editing
        sys.stdout = (self) # to begin logging stdio to GUI
        return

    def write(self, txt):
        self.text.configure(state='normal')
        self.text.insert('end', txt)
        self.text.configure(state='disabled')

root = tk.Tk()
root.resizable(width=False, height=False)
center_window(500, 300) # launch in center of screen
app = Application(master=root)
scrollFrame = scrollTxtArea(root)
app.mainloop()
root.destroy()

1 回答

  • 0

    你以错误的方式使用线程 .

    First: target= 需要没有 () 和参数的函数名称 .
    您可以为 args= 分配参数(即使您只有一个参数,它也必须是 tuple

    threading.Thread(target=parselog_v1.main, args=(Src_foldername,) )
    

    现在你的代码作为普通函数运行 parselog_v1.main ,等待结果并将它作为函数名称分配给 taget= - 所以你有这样的东西:

    result = parselog_v1.main(Src_foldername)
    threading.Thread(target=result)
    

    它会停止 mainloop ,因此它无法获取鼠标/键盘事件,刷新窗口等,因此它看起来像窗口冻结 .

    Second: 正确创建线程后,您必须启动它

    my_thread = threading.Thread(target=parselog_v1.main, args=(Src_foldername,) )
    my_thread.start()
    

相关问题