diff options
author | emkael <emkael@tlen.pl> | 2015-10-27 19:26:40 +0100 |
---|---|---|
committer | emkael <emkael@tlen.pl> | 2015-10-27 19:26:40 +0100 |
commit | b7a229b74d02fbfb291d2c32a3a3f134cae26de3 (patch) | |
tree | c4815d0026bc48939a84efdeb846bfe3339c64d2 /src/bidding_data_gui.py | |
parent | 74148e918eb7876883e268e95ba8902516acc47b (diff) |
* background thread-enabled GUI
Diffstat (limited to 'src/bidding_data_gui.py')
-rw-r--r-- | src/bidding_data_gui.py | 68 |
1 files changed, 43 insertions, 25 deletions
diff --git a/src/bidding_data_gui.py b/src/bidding_data_gui.py index 298ae1b..ad1fe59 100644 --- a/src/bidding_data_gui.py +++ b/src/bidding_data_gui.py @@ -10,6 +10,7 @@ files generated by JFR Pary. import Tkinter as tk import tkFileDialog import tkMessageBox +import Queue import logging as log import os @@ -17,7 +18,6 @@ import threading class BiddingGUI(tk.Frame): - """GUI frame class.""" # Tk variable to store tournament result file path @@ -33,7 +33,7 @@ class BiddingGUI(tk.Frame): Sanitizes input parameters, handles warning/error messages, imports main module (from CLI script) and runs it. """ - self.run_btn['state'] = tk.DISABLED + self.queue(self.run_btn.__setitem__, 'state', tk.DISABLED) try: # reset error/warning count and log output field self.__gui_logger.reset_counts() @@ -55,26 +55,28 @@ class BiddingGUI(tk.Frame): # inform of any warnings/errors that might have occuerd if self.__gui_logger.errors(): - tkMessageBox.showerror( - 'Błąd!', - ('Podczas wykonywania programu wystąpiły błędy ' + - 'w liczbie: %d\n' + - 'Sprawdź dziennik logów') % self.__gui_logger.errors()) + self.queue(tkMessageBox.showerror, + 'Błąd!', + ('Podczas wykonywania programu wystąpiły błędy ' + + 'w liczbie: %d\n' + + 'Sprawdź dziennik logów') + % self.__gui_logger.errors()) elif self.__gui_logger.warnings(): - tkMessageBox.showwarning( - 'Błąd!', - ('Podczas wykonywania programu wystąpiły ostrzeżenia ' + - 'w liczbie: %d\n' + - 'Sprawdź dziennik logów') % self.__gui_logger.warnings()) + self.queue(tkMessageBox.showwarning, + 'Błąd!', + ('Podczas wykonywania programu wystąpiły ' + + 'ostrzeżenia w liczbie: %d\n' + + 'Sprawdź dziennik logów') + % self.__gui_logger.warnings()) except Exception as ex: # JFRBidding errors are logged # (and notified of after entire execution), # other exceptions should halt execution and display error message log.getLogger('root').error(ex) - tkMessageBox.showerror('Błąd!', ex) + self.queue(tkMessageBox.showerror, 'Błąd!', ex) raise finally: - self.run_btn['state'] = tk.NORMAL + self.queue(self.run_btn.__setitem__, 'state', tk.NORMAL) def tour_select(self): """ @@ -100,6 +102,26 @@ class BiddingGUI(tk.Frame): title='Wybierz plik z danymi licytacji', filetypes=[('BWS files', '.bws'), ('all files', '.*')])) + __queue = None + + def queue(self, callback, *args, **kwargs): + """Add message (function call) to GUI interaction queue.""" + if self.__queue is None: + self.__queue = Queue.Queue() + self.__queue.put((callback, args, kwargs)) + + def process_queue(self): + """Process GUI interaction queue from other threads.""" + if self.__queue is None: + self.__queue = Queue.Queue() + try: + callback, args, kwargs = self.__queue.get_nowait() + except Queue.Empty: + self.master.after(100, self.process_queue) + else: + callback(*args, **kwargs) + self.master.after(10, self.process_queue) + def __init__(self, master=None): """ Construct the frame. @@ -122,6 +144,8 @@ class BiddingGUI(tk.Frame): self.pack(expand=1, fill=tk.BOTH) # finally, set logging up self.__configure_logging() + # fire up interthread queue + self.after(100, self.process_queue) def __configure_grid_cells(self, columns, rows): """Set expand with window resize for cells of layout grid.""" @@ -211,7 +235,6 @@ class BiddingGUI(tk.Frame): def __configure_logging(self): """Set up logging facility, bound to log output field.""" class GUILogHandler(log.Handler): - """Log handler which allows output to Tk Text widget.""" def __init__(self, text): @@ -222,15 +245,10 @@ class BiddingGUI(tk.Frame): def emit(self, record): """Output the message.""" msg = self.format(record) - - def append(): - """Append message to the Text widget, at the end.""" - self.text.insert(tk.END, msg + '\n') - # scroll to the bottom, afterwards - self.text.yview(tk.END) - - # call log output asynchronously - self.text.after(0, append) + # Append message to the Text widget, at the end.""" + self.text.master.queue(self.text.insert, tk.END, msg + '\n') + # scroll to the bottom, afterwards + self.text.master.queue(self.text.yview, tk.END) def handle(self, record): """Handle log message record (count errors/warnings).""" @@ -256,7 +274,7 @@ class BiddingGUI(tk.Frame): """Reset stats and log output.""" self.__warning_count = 0 self.__error_count = 0 - self.text.delete(1.0, tk.END) + self.text.master.queue(self.text.delete, 1.0, tk.END) # disable default logging limits/thresholds log.basicConfig( |