批量运行时,Tkinter GUI控制台未刷新

时间:2019-05-31 09:10:14

标签: python python-3.x multithreading tkinter

我开发了一个显示conf文件内容的GUI,可以对其进行修改,然后启动一些大批量处理。

import tkinter as Tk
from tkinter import ttk,messagebox
from sorter import Sorter

class GUI():

def __init__(self,logger) :
    self.window = Tk.Tk()
    self.window.resizable(False,False)
    self.window.title('BestArcade')
    self.logger = logger

def draw(self) :
    self.root = Tk.Frame(self.window,padx=10,pady=5)
    self.root.grid(column=0,row=0)
    self.drawConsole()
    self.window.mainloop()

def clickProceed(self) :
    self.logger.log('\n<--------- Starting Process --------->')
    sorter = Sorter(self.logger)
    # Big batch processes start here, from now on logs are not displayed
    sorter.prepare()
    self.logger.log('\n<--------- Create Sets --------->')
    sorter.createSets(sorter.allTests,sorter.dats)
    # Logs from the process are displayed all together here
    self.logger.log("\n<--------- Detecting errors ----------->")
    self.logger.log('<--------- Process finished ----------->')

def drawConsole(self) :
    self.consoleFrame = Tk.Frame(self.root, padx=10)
    self.consoleFrame.grid(column=0,row=4,sticky="EW",pady=5)
    self.consoleFrame.grid_columnconfigure(0, weight=1)
    self.logTest = Tk.Text(self.consoleFrame, height=20, state='disabled', wrap='word',background='black',foreground='yellow')
    self.logTest.grid(column=0,row=0,sticky="EW")
    self.scrollbar = Tk.Scrollbar(self.consoleFrame, orient=Tk.VERTICAL,command=self.logTest.yview)
    self.scrollbar.grid(column=1,row=0,sticky=(Tk.N,Tk.S))
    self.logTest['yscrollcommand'] = self.scrollbar.set
    self.logTest.after(10,self.updateConsoleFromQueue)

def updateConsoleFromQueue(self):
    while not self.logger.log_queue.empty():
        line = self.logger.log_queue.get()
        print('WRITECONSOLE')
        self.writeToConsole(line)
    self.logTest.after(10,self.updateConsoleFromQueue)

def writeToConsole(self, msg):
    numlines = self.logTest.index('end - 1 line').split('.')[0]
    self.logTest['state'] = 'normal'
    if numlines==24:
        self.logTest.delete(1.0, 2.0)
    if self.logTest.index('end-1c')!='1.0':
        self.logTest.insert('end', '\n')
    self.logTest.insert('end', msg)
    self.logTest.see(Tk.END)
    self.logTest['state'] = 'disabled'

GUI的控制台部分使用队列显示所有发生的事件的日志记录,记录器推送和控制台Text小部件在其中获得

import queue

class Logger() :

def __init__(self) :
    self.log_queue = queue.Queue()

def log(self,msg) :
    self.log_queue.put(msg.rstrip('\n'))
    print(msg.rstrip('\n'))

主启动器非常简单:

from gui import GUI
from logger import Logger

if __name__ == "__main__":
   logger = Logger()
   logger.log('Start')
   gui = GUI(logger)
   logger.log('\n<--------- Load Configuration File --------->')
   gui.draw()

问题在于,从GUI内部(或在主循环之前)记录的每个部分都立即出现,而大批处理过程的许多日志在结束时都在过程结束时一起出现。 大批处理过程在类Sorter中,该类使用以下行进行记录:

self.logger.log('\n<--------- Load Favorites Ini Files --------->')

在大批处理过程中,GUI在前5秒钟左右似乎正常,但是在所有过程中都冻结了。

显然这是一个多线程问题,可以从记录器实时将日志很好地添加到队列中,但是在批处理过程中根本不访问GUI的功能updateConsoleFromQueue,即使使用after(),实际上是所有print(大批处理过程结束后也会出现“ WRITECONSOLE”

我知道这与窗口的主循环和/或大批处理/记录器的线程的脚步有关,不允许控制台的任何文本自动刷新

我更像是一个Java专家,所以我想我应该定期产生proces / logger的线程,以使GUI的线程能够运行updateConsoleFromQueue,但无法理解如何在Python中做到这一点。

0 个答案:

没有答案