New Demo Program - a multi-threaded example using a queue to send data to your application
This commit is contained in:
		
							parent
							
								
									14e8cbae3d
								
							
						
					
					
						commit
						95fd3c53a2
					
				
					 1 changed files with 142 additions and 0 deletions
				
			
		
							
								
								
									
										142
									
								
								DemoPrograms/Demo_Multithreaded_DataPump.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								DemoPrograms/Demo_Multithreaded_DataPump.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,142 @@ | |||
| import PySimpleGUI as sg | ||||
| import random | ||||
| import time | ||||
| import queue | ||||
| 
 | ||||
| """ | ||||
|     Demo - Multi-threaded "Data Pump" Design Pattern | ||||
| 
 | ||||
|     Send data to your PySimpleGUI program through a Python Queue, enabling integration with many | ||||
|     different types of data sources. | ||||
| 
 | ||||
|     A thread gets data from a queue object and passes it over to the main event loop. | ||||
|     The external_thread is only used here to generaate random data.  It's not part of the | ||||
|     overall "Design Pattern". | ||||
|      | ||||
|     The thread the_thread IS part of the design pattern.  It reads data from the thread_queue and sends that | ||||
|     data over to the PySimpleGUI event loop. | ||||
| 
 | ||||
|     Copyright 2022 PySimpleGUI | ||||
| """ | ||||
| 
 | ||||
| gsize = (400, 400)  # size of the graph | ||||
| 
 | ||||
| THREAD_KEY = '-THREAD-' | ||||
| THREAD_INCOMING_DATA = '-INCOMING DATA-' | ||||
| THREAD_EXITNG = '-THREAD EXITING-' | ||||
| THREAD_EXTERNAL_EXITNG = '-EXTERNAL THREAD EXITING-' | ||||
| 
 | ||||
| # This queue is where you will send your data that you want to eventually arrive as an event | ||||
| thread_queue = queue.Queue() | ||||
| 
 | ||||
| # M""""""""M dP                                        dP | ||||
| # Mmmm  mmmM 88                                        88 | ||||
| # MMMM  MMMM 88d888b. 88d888b. .d8888b. .d8888b. .d888b88 | ||||
| # MMMM  MMMM 88'  `88 88'  `88 88ooood8 88'  `88 88'  `88 | ||||
| # MMMM  MMMM 88    88 88       88.  ... 88.  .88 88.  .88 | ||||
| # MMMM  MMMM dP    dP dP       `88888P' `88888P8 `88888P8 | ||||
| # MMMMMMMMMM | ||||
| # | ||||
| # MP""""""`MM oo                     dP            dP   oo | ||||
| # M  mmmmm..M                        88            88 | ||||
| # M.      `YM dP 88d8b.d8b. dP    dP 88 .d8888b. d8888P dP 88d888b. .d8888b. | ||||
| # MMMMMMM.  M 88 88'`88'`88 88    88 88 88'  `88   88   88 88'  `88 88'  `88 | ||||
| # M. .MMM'  M 88 88  88  88 88.  .88 88 88.  .88   88   88 88    88 88.  .88 | ||||
| # Mb.     .dM dP dP  dP  dP `88888P' dP `88888P8   dP   dP dP    dP `8888P88 | ||||
| # MMMMMMMMMMM                                                            .88 | ||||
| #                                                                    d8888P | ||||
| # M""""""'YMM            dP               MP""""""`MM | ||||
| # M  mmmm. `M            88               M  mmmmm..M | ||||
| # M  MMMMM  M .d8888b. d8888P .d8888b.    M.      `YM .d8888b. dP    dP 88d888b. .d8888b. .d8888b. | ||||
| # M  MMMMM  M 88'  `88   88   88'  `88    MMMMMMM.  M 88'  `88 88    88 88'  `88 88'  `"" 88ooood8 | ||||
| # M  MMMM' .M 88.  .88   88   88.  .88    M. .MMM'  M 88.  .88 88.  .88 88       88.  ... 88.  ... | ||||
| # M       .MM `88888P8   dP   `88888P8    Mb.     .dM `88888P' `88888P' dP       `88888P' `88888P' | ||||
| # MMMMMMMMMMM                             MMMMMMMMMMM | ||||
| # | ||||
| 
 | ||||
| def external_thread(thread_queue:queue.Queue): | ||||
|     """ | ||||
|     Represents some external source of data. | ||||
|     You would not include this code as a starting point with this Demo Program. Your data is assumed to | ||||
|     come from somewhere else. The important part is that you add data to the thread_queue | ||||
|     :param thread_queue: | ||||
|     :return: | ||||
|     """ | ||||
|     i = 0 | ||||
|     while True: | ||||
|         time.sleep(.01) | ||||
|         point = (random.randint(0,gsize[0]), random.randint(0,gsize[1])) | ||||
|         radius = random.randint(10, 40) | ||||
|         thread_queue.put((point, radius)) | ||||
|         i += 1 | ||||
| 
 | ||||
| 
 | ||||
| # M""""""""M dP                                        dP    MM""""""""`M | ||||
| # Mmmm  mmmM 88                                        88    MM  mmmmmmmM | ||||
| # MMMM  MMMM 88d888b. 88d888b. .d8888b. .d8888b. .d888b88    M'      MMMM .d8888b. 88d888b. | ||||
| # MMMM  MMMM 88'  `88 88'  `88 88ooood8 88'  `88 88'  `88    MM  MMMMMMMM 88'  `88 88'  `88 | ||||
| # MMMM  MMMM 88    88 88       88.  ... 88.  .88 88.  .88    MM  MMMMMMMM 88.  .88 88 | ||||
| # MMMM  MMMM dP    dP dP       `88888P' `88888P8 `88888P8    MM  MMMMMMMM `88888P' dP | ||||
| # MMMMMMMMMM                                                 MMMMMMMMMMMM | ||||
| # | ||||
| # MM"""""""`YM MP""""""`MM MM'"""""`MM    MM""""""""`M                              dP | ||||
| # MM  mmmmm  M M  mmmmm..M M' .mmm. `M    MM  mmmmmmmM                              88 | ||||
| # M'        .M M.      `YM M  MMMMMMMM    M`      MMMM dP   .dP .d8888b. 88d888b. d8888P .d8888b. | ||||
| # MM  MMMMMMMM MMMMMMM.  M M  MMM   `M    MM  MMMMMMMM 88   d8' 88ooood8 88'  `88   88   Y8ooooo. | ||||
| # MM  MMMMMMMM M. .MMM'  M M. `MMM' .M    MM  MMMMMMMM 88 .88'  88.  ... 88    88   88         88 | ||||
| # MM  MMMMMMMM Mb.     .dM MM.     .MM    MM        .M 8888P'   `88888P' dP    dP   dP   `88888P' | ||||
| # MMMMMMMMMMMM MMMMMMMMMMM MMMMMMMMMMM    MMMMMMMMMMMM | ||||
| 
 | ||||
| 
 | ||||
| def the_thread(window:sg.Window, thread_queue:queue.Queue): | ||||
|     """ | ||||
|     The thread that communicates with the application through the window's events. | ||||
|     Waits for data from a queue and sends that data on to the event loop | ||||
|     :param window: | ||||
|     :param thread_queue: | ||||
|     :return: | ||||
|     """ | ||||
| 
 | ||||
|     while True: | ||||
|         data = thread_queue.get() | ||||
|         window.write_event_value((THREAD_KEY, THREAD_INCOMING_DATA), data)  # Data sent is a tuple of thread name and counter | ||||
| 
 | ||||
| 
 | ||||
| def main(): | ||||
| 
 | ||||
|     layout = [  [sg.Text('My Simulated Data Pump')], | ||||
|                 [sg.Multiline(size=(60, 20), k='-MLINE-')], | ||||
|                 [sg.Graph(gsize, (0, 0), gsize, k='-G-', background_color='gray')], | ||||
|                 [sg.Button('Go'), sg.Button('Exit')] ] | ||||
| 
 | ||||
|     window = sg.Window('Simulated Data Pump', layout, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT) | ||||
| 
 | ||||
|     graph = window['-G-']       # type: sg.Graph | ||||
| 
 | ||||
|     while True:             # Event Loop | ||||
|         event, values = window.read() | ||||
|         # print(event, values) | ||||
|         if event == sg.WIN_CLOSED or event == 'Exit': | ||||
|             break | ||||
|         if event == 'Go': | ||||
|             window.start_thread(lambda: the_thread(window, thread_queue), (THREAD_KEY, THREAD_EXITNG)) | ||||
|             window.start_thread(lambda: external_thread(thread_queue), (THREAD_KEY, THREAD_EXTERNAL_EXITNG)) | ||||
|         # Events coming from the Thread | ||||
|         elif event[0] == THREAD_KEY: | ||||
|             if event[1] == THREAD_INCOMING_DATA: | ||||
|                 point, radius = values[event] | ||||
|                 graph.draw_circle(point, radius=radius, fill_color='green') | ||||
|                 window['-MLINE-'].print(f'Drawing at {point} radius {radius}', c='white on red') | ||||
|             elif event[1] == THREAD_EXITNG: | ||||
|                 window['-MLINE-'].print('Thread has exited') | ||||
|             elif event[1] == THREAD_EXTERNAL_EXITNG: | ||||
|                 window['-MLINE-'].print('Data Pump thread has exited') | ||||
|         if event == 'Edit Me': | ||||
|             sg.execute_editor(__file__) | ||||
|         elif event == 'Version': | ||||
|             sg.popup_scrolled(__file__, sg.get_versions(), location=window.current_location(), keep_on_top=True, non_blocking=True) | ||||
| 
 | ||||
|     window.close() | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     main() | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue