Enhancement
PySimpleGUI - tk
The mutli-window design patterns are confusing. This has always been the case and has been a stop-gap until the "righter way" of doing it was done.
A fresh (ink still drying) version of the new way to deal with these multi-window situations has been released to the development branch only, something I rarely do. Seeing how experimental this code is and how many places it touches, it makes sense to be cautious.
There are 2 demo programs you can try as a starting point. One has a timeout value and one does not. The async/timeout version is the more difficult of the two, but figured if I showed a version with a timeout, it looks like the old way and this is very much NOT the old way of doing things.
https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/Dev-latest/PySimpleGUI.py
read_all_windowsLike most of the architecture of PySimpleGUI, it tends to find a way to simplify down the the base essentials. The recent threading call of write_event_values is a good example of how 1 function provided all that was needed.
The same goes here. There is a single function you call: read_all_windows that will read all currently "open" (read or finalized) windows.
Here's the definition:
def read_all_windows(timeout=None, timeout_key=TIMEOUT_KEY):
"""
Reads a list of windows. If any of the list returns a value then the window and its event and values
are returned.
:param timeout: Time in milliseconds to delay before a returning a timeout event
:type timeout: (int)
:param timeout_key: Key to return when a timeout happens. Defaults to the standard TIMEOUT_KEY
:type timeout_key: (Any)
:return: A tuple with the (Window, event, values dictionary/list)
:rtype: Tuple[Window, Any, (Dict or List)]
"""
import PySimpleGUI as sg
WIDTH = 500
LOC1 = (500,500)
LOC2 = (LOC1[0]+WIDTH, LOC1[1])
LOC3 = (LOC2[0]+WIDTH, LOC1[1])
layout1 = [ [sg.Text('My Window')],
[sg.Input(k='-IN-'), sg.Text(size=(12,1), k='-OUT-')],
[sg.CB('Check 1', k='-CB1-', enable_events=True), sg.CB('Check 2', k='-CB2-', enable_events=True), sg.CB('Mirror on Window 2', enable_events=True, k='-CB3-')],
[sg.Button('Go'), sg.B('Dummy'), sg.Button('Exit')] ]
window1 = sg.Window('Window 1 Title', layout1, finalize=True, location=LOC1)
layout2 = [ [sg.Text('My Window')],
[sg.Input(k='-IN-'), sg.Text(size=(12,1), k='-OUT-')],
[sg.CB('Check 1', k='-CB1-'), sg.CB('Check 2', k='-CB2-')],
[sg.Button('Go'), sg.B('Popup'), sg.Button('Exit')] ]
window2 = sg.Window('Window 2 Title', layout2, finalize=True, location=LOC2)
while True: # Event Loop
window, event, values = sg.read_all_windows()
if window is None and event != sg.TIMEOUT_EVENT:
print('exiting because no windows are left')
break
print(window.Title, event, values) if window is not None else None
if event == sg.WIN_CLOSED or event == 'Exit':
window.close()
if event == 'Go':
window['-OUT-'].update(values['-IN-'])
try: # try to update the other window
if window == window1:
window2['-OUT-'].update('The other window')
else:
window1['-OUT-'].update('The other window')
except:
pass
if event == 'Dummy':
sg.popup_non_blocking('Non-blocking popup')
if event == 'Popup':
sg.popup('plain popup')
try:
if window == window1 and values['-CB3-']:
window2['-CB1-'].update(values['-CB1-'])
window2['-CB2-'].update(values['-CB2-'])
except:
pass
import PySimpleGUI as sg
WIDTH = 500
LOC1 = (500,500)
LOC2 = (LOC1[0]+WIDTH, LOC1[1])
LOC3 = (LOC2[0]+WIDTH, LOC1[1])
layout1 = [ [sg.Text('My Window')],
[sg.Input(k='-IN-'), sg.Text(size=(12,1), k='-OUT-')],
[sg.CB('Check 1', k='-CB1-', enable_events=True), sg.CB('Check 2', k='-CB2-', enable_events=True), sg.CB('Mirror on Window 2', enable_events=True, k='-CB3-')],
[sg.Button('Go'), sg.B('Dummy'), sg.Button('Exit')] ]
window1 = sg.Window('Window 1 Title', layout1, finalize=True, location=LOC1)
layout2 = [ [sg.Text('My Window')],
[sg.Input(k='-IN-'), sg.Text(size=(12,1), k='-OUT-')],
[sg.CB('Check 1', k='-CB1-'), sg.CB('Check 2', k='-CB2-')],
[sg.Button('Go'), sg.B('Popup'), sg.Button('Exit')] ]
window2 = sg.Window('Window 2 Title', layout2, finalize=True, location=LOC2)
layout3 = [ [sg.Text('The Async Window')],
[sg.Text(size=(12,1), key='-OUT-', font='Any 15')],
[sg.Button('Exit')] ]
window3 = sg.Window('Window 3 Title', layout3, finalize=True, no_titlebar=True, grab_anywhere=True, location=LOC3)
count = 0
while True: # Event Loop
window, event, values = sg.read_all_windows(timeout=1000)
if window is None and event != sg.TIMEOUT_EVENT:
print('exiting because no windows are left')
break
print(window.Title, event, values) if window is not None else None
if event == sg.WIN_CLOSED or event == 'Exit':
window.close()
if event == 'Go':
window['-OUT-'].update(values['-IN-'])
try: # try to update the other window
if window == window1:
window2['-OUT-'].update('The other window')
else:
window1['-OUT-'].update('The other window')
except:
pass
if event == 'Dummy':
sg.popup_non_blocking('Non-blocking popup')
if event == 'Popup':
sg.popup('plain popup')
if event == sg.TIMEOUT_EVENT:
window3['-OUT-'].update(count)
try:
if window == window1 and values['-CB3-']:
window2['-CB1-'].update(values['-CB1-'])
window2['-CB2-'].update(values['-CB2-'])
except:
pass
count += 1
Heads-up
The new 4.26.0.2 release has been merged into the Master branch
This code uses the new function read_all_windows if you care to try it.
_It should not have a negative impact on your existing applications. They should function as if nothing changed!_
But, I did sorta touch a lot of places and I may have really messed things up... we'll see soon enough.
More demos coming of the new function. It's making multiple windows really trivial to do on so many levels. You will not need to change much about your code to begin to use it.
Most helpful comment
Released to Master Branch of GitHub!
Heads-up
The new 4.26.0.2 release has been merged into the Master branch
This code uses the new function
read_all_windowsif you care to try it._It should not have a negative impact on your existing applications. They should function as if nothing changed!_
But, I did sorta touch a lot of places and I may have really messed things up... we'll see soon enough.
More demos coming of the new function. It's making multiple windows really trivial to do on so many levels. You will not need to change much about your code to begin to use it.