diff --git a/Demo_Multithreaded_Logging.py b/Demo_Multithreaded_Logging.py new file mode 100644 index 00000000..095433a2 --- /dev/null +++ b/Demo_Multithreaded_Logging.py @@ -0,0 +1,98 @@ +import sys +if sys.version_info[0] >= 3: + import PySimpleGUI as sg +else: + import PySimpleGUI27 as sg + +import queue +import logging +import threading +import time + +""" + This code originated in this project: + https://github.com/john144/MultiThreading + Thanks to John for writing this in the early days of PySimpleGUI + Demo program showing one way that a threaded application can function with PySimpleGUI + Events are sent from the ThreadedApp thread to the main thread, the GUI, by using a queue +""" + +logger = logging.getLogger('mymain') + + +def externalFunction(): + logger.info('Hello from external app') + logger.info('External app sleeping 5 seconds') + time.sleep(5) + logger.info('External app waking up and exiting') + + +class ThreadedApp(threading.Thread): + def __init__(self): + super().__init__() + self._stop_event = threading.Event() + + def run(self): + externalFunction() + + def stop(self): + self._stop_event.set() + + +class QueueHandler(logging.Handler): + def __init__(self, log_queue): + super().__init__() + self.log_queue = log_queue + + def emit(self, record): + self.log_queue.put(record) + + +def main(): + window = sg.FlexForm('Log window', default_element_size=(30, 2), font=('Helvetica', ' 10'), default_button_element_size=(8, 2), return_keyboard_events=True) + + layout = \ + [ + [sg.Multiline(size=(50, 15), key='Log')], + [sg.Button('Start', bind_return_key=True, key='_START_'), sg.Button('Exit')] + ] + + window.LayoutAndRead(layout, non_blocking=True) + appStarted = False + + # Setup logging and start app + logging.basicConfig(level=logging.DEBUG) + log_queue = queue.Queue() + queue_handler = QueueHandler(log_queue) + logger.addHandler(queue_handler) + threadedApp = ThreadedApp() + + # Loop taking in user input and querying queue + while True: + # Wake every 100ms and look for work + event, values = window.Read(timeout=100) + + if event == '_START_': + if appStarted is False: + threadedApp.start() + logger.debug('App started') + window.FindElement('_START_').Update(disabled=True) + appStarted = True + elif event in (None, 'Exit'): + break + + # Poll queue + try: + record = log_queue.get(block=False) + except queue.Empty: + pass + else: + msg = queue_handler.format(record) + window.FindElement('Log').Update(msg+'\n', append=True) + + window.Close() + exit() + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/PySimpleGUI.py b/PySimpleGUI.py index fac937f5..447ac011 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -3083,7 +3083,7 @@ class Window: self.RootNeedsDestroying = True return None - def CloseNonBlocking(self): + def Close(self): if self.TKrootDestroyed: return try: @@ -3092,13 +3092,12 @@ class Window: except: pass - CloseNonBlockingForm = CloseNonBlocking - Close = CloseNonBlockingForm - + CloseNonBlockingForm = Close + CloseNonBlocking = Close # IT FINALLY WORKED! 29-Oct-2018 was the first time this damned thing got called def OnClosingCallback(self): - print('Got closing callback') + # print('Got closing callback') self.TKroot.quit() # kick the users out of the mainloop if self.CurrentlyRunningMainloop: # quit if this is the current mainloop, otherwise don't quit! self.TKroot.destroy() # kick the users out of the mainloop @@ -5810,7 +5809,7 @@ PopupNoWait = PopupNonBlocking # --------------------------- PopupQuick - a NonBlocking, Self-closing Popup --------------------------- def PopupQuick(*args, button_type=POPUP_BUTTONS_OK, button_color=None, background_color=None, text_color=None, - auto_close=True, auto_close_duration=1, non_blocking=True, icon=DEFAULT_WINDOW_ICON, line_width=None, + auto_close=True, auto_close_duration=2, non_blocking=True, icon=DEFAULT_WINDOW_ICON, line_width=None, font=None, no_titlebar=False, grab_anywhere=False, keep_on_top=False, location=(None, None)): """ Show Popup box that doesn't block and closes itself @@ -5840,7 +5839,7 @@ def PopupQuick(*args, button_type=POPUP_BUTTONS_OK, button_color=None, backgroun # --------------------------- PopupQuick - a NonBlocking, Self-closing Popup with no titlebar and no buttons --------------------------- def PopupQuickMessage(*args, button_type=POPUP_BUTTONS_NO_BUTTONS, button_color=None, background_color=None, text_color=None, - auto_close=True, auto_close_duration=1, non_blocking=True, icon=DEFAULT_WINDOW_ICON, line_width=None, + auto_close=True, auto_close_duration=2, non_blocking=True, icon=DEFAULT_WINDOW_ICON, line_width=None, font=None, no_titlebar=True, grab_anywhere=False, keep_on_top=False, location=(None, None)): """ Show Popup box that doesn't block and closes itself @@ -5868,8 +5867,6 @@ def PopupQuickMessage(*args, button_type=POPUP_BUTTONS_NO_BUTTONS, button_color= font=font, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location) - - # --------------------------- PopupNoTitlebar --------------------------- def PopupNoTitlebar(*args, button_type=POPUP_BUTTONS_OK, button_color=None, background_color=None, text_color=None, auto_close=False, auto_close_duration=None, non_blocking=False, icon=DEFAULT_WINDOW_ICON,