Added tons of comments, new itertools use, uses 3 threads now

This commit is contained in:
MikeTheWatchGuy 2019-03-09 12:31:45 -05:00
parent 1b88993244
commit bed31c7580
1 changed files with 62 additions and 23 deletions

View File

@ -1,8 +1,20 @@
from queue import Queue
from threading import Thread
from time import sleep
#!/usr/bin/python3
# Rather than importing individual classes such as threading.Thread or queue.Queue, this
# program is doing a simple import and then indicating the package name when the functions
# are called. This seemed like a great way for the reader of the code to get an understanding
# as to exactly which package is being used. It's purely for educational and explicitness purposes
import queue
import threading
import time
import itertools
# This program has been tested on all flavors of PySimpleGUI and it works with no problems at all
# To try something other than tkinter version, just comment out the first import and uncomment the one you want
import PySimpleGUI as sg
# import PySimpleGUIQt as sg
# import PySimpleGUIWx as sg
# import PySimpleGUIWeb as sg
"""
DESIGN PATTERN - Multithreaded GUI
@ -21,60 +33,87 @@ import PySimpleGUI as sg
"""
######## ## ## ######## ######## ### ########
## ## ## ## ## ## ## ## ## ##
## ## ## ## ## ## ## ## ## ##
## ######### ######## ###### ## ## ## ##
## ## ## ## ## ## ######### ## ##
## ## ## ## ## ## ## ## ## ##
## ## ## ## ## ######## ## ## ########
def worker_thread(thread_name, run_freq, gui_queue):
"""
A worker thrread that communicates with the GUI
These threads can call functions that block withouth affecting the GUI (a good thing)
Note that this function is the code started as each thread. All threads are identical in this way
:param thread_name: Text name used for displaying info
:param run_freq: How often the thread should run in milliseconds
:param gui_queue: Queue used to communicate with the GUI
:return:
"""
print('Starting thread - ', thread_name)
i = 0
while True:
sleep(run_freq/1000)
gui_queue.put('{} - {}'.format(thread_name, i))
i += 1
print('Starting thread - {} that runds every {} ms'.format(thread_name, run_freq))
for i in itertools.count(): # loop forever, keeping count in i as it loops
time.sleep(run_freq/1000) # sleep for a while
gui_queue.put('{} - {}'.format(thread_name, i)) # put a message into queue for GUI
###### ## ## ####
## ## ## ## ##
## ## ## ##
## #### ## ## ##
## ## ## ## ##
## ## ## ## ##
###### ####### ####
def the_gui(gui_queue):
"""
starts and executes the GUI. Returns when the user exits / closes the window
reads data from a Queue and displays the data
Starts and executes the GUI
Reads data from a Queue and displays the data to the window
Returns when the user exits / closes the window
(that means it does NOT return until the user exits the window)
:param gui_queue: Queue the GUI should read from
:return:
"""
layout = [ [sg.Text('Your GUI Window')],
layout = [ [sg.Text('Multithreaded Window Example')],
[sg.Text('', size=(15,1), key='_OUTPUT_')],
[sg.Button('Exit')],]
window = sg.Window('Window Title').Layout(layout)
while True: # Event Loop
event, values = window.Read(timeout=100) # wait for up to 200 ms for a GUI event
window = sg.Window('Multithreaded Window').Layout(layout)
# --------------------- EVENT LOOP ---------------------
while True:
event, values = window.Read(timeout=100) # wait for up to 100 ms for a GUI event
if event is None or event == 'Exit':
break
#--------------- Handle stuff coming in from threads ---------------
#--------------- Loop through all messages coming in from threads ---------------
while True: # loop executes until runs out of messages in Queue
try: # see if something has been posted to Queue
message = gui_queue.get_nowait()
except: # will get exception when Queue is empty
except queue.Empty: # get_nowait() will get exception when Queue is empty
break # break from the loop if no more messages are queued up
# if message received from queue, display the message in the Window
if message:
window.Element('_OUTPUT_').Update(message)
window.Refresh()
window.Refresh() # do a refresh because could be showing multiple messages before next Read
# if user exits the window, then close the window and exit
# if user exits the window, then close the window and exit the GUI func
window.Close()
## ## ### #### ## ##
### ### ## ## ## ### ##
#### #### ## ## ## #### ##
## ### ## ## ## ## ## ## ##
## ## ######### ## ## ####
## ## ## ## ## ## ###
## ## ## ## #### ## ##
if __name__ == '__main__':
#-- Create a Queue to communicate with GUI --
gui_queue = Queue() # queue used to communicate between the gui and the worker
gui_queue = queue.Queue() # queue used to communicate between the gui and the threads
#-- Start worker threads, one runs twice as often as the other
Thread(target=worker_thread, args=('Thread 1', 500, gui_queue,), daemon=True).start()
Thread(target=worker_thread, args=('Thread 2', 200, gui_queue,), daemon=True).start()
threading.Thread(target=worker_thread, args=('Thread 1', 500, gui_queue,), daemon=True).start()
threading.Thread(target=worker_thread, args=('Thread 2', 200, gui_queue,), daemon=True).start()
threading.Thread(target=worker_thread, args=('Thread 3', 1000, gui_queue,), daemon=True).start()
#-- Start the GUI passing in the Queue --
the_gui(gui_queue)
print('Exiting Program')