我开发了一个显示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中做到这一点。