New Demo - Multithreaded logging
This commit is contained in:
parent
8eeec3e2e8
commit
e89e55f69a
|
@ -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()
|
|
@ -3083,7 +3083,7 @@ class Window:
|
||||||
self.RootNeedsDestroying = True
|
self.RootNeedsDestroying = True
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def CloseNonBlocking(self):
|
def Close(self):
|
||||||
if self.TKrootDestroyed:
|
if self.TKrootDestroyed:
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
|
@ -3092,13 +3092,12 @@ class Window:
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
CloseNonBlockingForm = CloseNonBlocking
|
CloseNonBlockingForm = Close
|
||||||
Close = CloseNonBlockingForm
|
CloseNonBlocking = Close
|
||||||
|
|
||||||
|
|
||||||
# IT FINALLY WORKED! 29-Oct-2018 was the first time this damned thing got called
|
# IT FINALLY WORKED! 29-Oct-2018 was the first time this damned thing got called
|
||||||
def OnClosingCallback(self):
|
def OnClosingCallback(self):
|
||||||
print('Got closing callback')
|
# print('Got closing callback')
|
||||||
self.TKroot.quit() # kick the users out of the mainloop
|
self.TKroot.quit() # kick the users out of the mainloop
|
||||||
if self.CurrentlyRunningMainloop: # quit if this is the current mainloop, otherwise don't quit!
|
if self.CurrentlyRunningMainloop: # quit if this is the current mainloop, otherwise don't quit!
|
||||||
self.TKroot.destroy() # kick the users out of the mainloop
|
self.TKroot.destroy() # kick the users out of the mainloop
|
||||||
|
@ -5810,7 +5809,7 @@ PopupNoWait = PopupNonBlocking
|
||||||
|
|
||||||
# --------------------------- PopupQuick - a NonBlocking, Self-closing Popup ---------------------------
|
# --------------------------- PopupQuick - a NonBlocking, Self-closing Popup ---------------------------
|
||||||
def PopupQuick(*args, button_type=POPUP_BUTTONS_OK, button_color=None, background_color=None, text_color=None,
|
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)):
|
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
|
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 ---------------------------
|
# --------------------------- 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,
|
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)):
|
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
|
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)
|
font=font, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------------- PopupNoTitlebar ---------------------------
|
# --------------------------- PopupNoTitlebar ---------------------------
|
||||||
def PopupNoTitlebar(*args, button_type=POPUP_BUTTONS_OK, button_color=None, background_color=None, text_color=None,
|
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,
|
auto_close=False, auto_close_duration=None, non_blocking=False, icon=DEFAULT_WINDOW_ICON,
|
||||||
|
|
Loading…
Reference in New Issue