Я разработал графический интерфейс, отображающий некоторый контент conf-файла, позволяющий изменить его и затем запустить какой-то большой пакетный процесс.
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'
В графическом интерфейсе пользователя есть консольная часть, отображающая запись всех событий, которые происходят, используя очередь, в которой push-логгер и консольный виджет 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 (или до mainloop) появляется немедленно, тогда как многие журналы процесса большой партии появляются все вместе в конце процесса, когда он закончен.
Большой пакетный процесс находится в классе Sorter, который регистрирует строки наподобие:
self.logger.log('\n<--------- Load Favorites Ini Files --------->')
Во время процесса большой партии графический интерфейс отображается нормально в течение первых 5 секунд или около того, но затем останавливается в течение всего процесса.
Очевидно, что это проблема многопоточности, журналы прекрасно добавляются в очередь из регистратора в режиме реального времени, но функция GUI updateConsoleFromQueue вообще не доступна во время пакетного процесса, даже используя after (), фактически всю печать ( 'WRITECONSOLE') появляется и после окончания процесса большой партии
Я понимаю, что это как-то связано с протеканием основной петли окна и / или потока большого пакета процессов / регистратора, не позволяющего консоли освободить место для текста. Текст для обновления
Я в большей степени Java-парень, поэтому, я думаю, мне следует периодически выдавать поток обработчика / регистратора, чтобы позволить потоку графического интерфейса пользователя запускать updateConsoleFromQueue, но не понимает, как это сделать в Python .. .