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
|
||||
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,
|
||||
|
|
Loading…
Reference in New Issue