Pysimplegui: [ Enhancement ] New Multi-Window Architecture - Alpha version ready to try....

Created on 22 Jul 2020  路  1Comment  路  Source: PySimpleGUI/PySimpleGUI

Type of Issues (Enhancement, Error, Bug, Question)

Enhancement

PySimpleGUI Port and Version

PySimpleGUI - tk

Description of Problem / Question / Details

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.

Download the experimental PySimpleGUI.py file:

https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/Dev-latest/PySimpleGUI.py

read_all_windows

Like 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)]
    """

Demo - 2 windows

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

Demo 3 windows - 2 are plain and 3rd is an async window (normally used with a timeout)

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

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_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.

>All comments

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_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.

Was this page helpful?
0 / 5 - 0 ratings