Sep-23-2021, 01:47 PM
(Sep-23-2021, 12:57 PM)deanhystad Wrote: I played around with your code. It is an, um, er, interesting approach. I would never have come up with the idea of destroying and re-creating windows just to update the widgets. The top row of buttons is also an unusual way to present different views.
Here are some ideas you may find interesting. I modified the code to remove recursion.
Recursion is when a function calls itself, either directly or through indirectly. Your code has a lot of recursion. Functions call themselves to update the window or call functions to draw other windows that may in turn call the original function. This is a bad thing because it eats up memory. It is so bad that Python places an upper limit on how many levels of function calls are allowed. If you program reaches that limit, an excpetion is thrown.
To remove the recursion I rewrote the code to return control to a window switcher which calls the function to draw the next window. Instead of login() calling main(), login() now sets a variable and returns. The window switcher.
switch_window(login) # Start with login window while next_window: next_window() # execute function to draw next windowTo switch from the current window to a new window, the window event loop assigns "next_window" to be the function that draws the next window, then the current window exits its event loop and lets control return to the window switcher loop. It uses a couple of convenience functions to help with this.
def switch_window(window_func): '''Close current window and set function to open new window''' global next_window, window_open next_window = window_func window_open = False def show_window(title, layout): '''Create new window using layout. Position window in same location as current window''' global window, window_open if window: window.close() window = sg.Window(title, layout, size=(600, 500), enable_close_attempted_event=True, location=sg.user_settings_get_entry('-WINDOW_LOCATION-', (None, None))) window_open = Trueswitch_window() sets the next_window function variable and sets window_open to False, causing the event loop to exit. show_window() draws the new window.
I changed the way window location was saved and restored. I have the window send an event if you click on the close window decoration. In the event handler I capture that event, save the window location, and close the window. I save the window location in a PySimpleGUI user setting named '-WINDOW_LOCATION-', and when the new window is drawn it uses the user setting to set the location of the new window.
I rewrote the login window to allow multiple login attempts without having to redraw the window. If the user enters in invalid username or password it clears the inputs, displays a message in a popup, and sets focus back to the user input.
Clearing the inputs is easy. You can set a flag to automatically clear an input when it is read, and I did that in the layou
layout = [ [sg.T("Username")], [sg.InputText(key = "-USER-", do_not_clear=False)], [sg.T("Password")], [sg.InputText(key = "-PASSWORD-", do_not_clear=False)], [sg.Button("OK", bind_return_key=True, key="-OK-")], ]Setting the focus back to the user input was a bit trickier. I had to call the set_focus() method for the user input.
window['-USER-'].set_focus()The entire program:
import PySimpleGUI as sg accounts = {"Admin":"Administrator", "User":"OneTwoThree"} window = None window_open = False next_window = None def switch_window(window_func): '''Close current window and set function to open new window''' global next_window, window_open next_window = window_func window_open = False def show_window(title, layout): '''Create new window using layout. Position window in same location as current window''' global window, window_open if window: window.close() window = sg.Window(title, layout, size=(600, 500), enable_close_attempted_event=True, location=sg.user_settings_get_entry('-WINDOW_LOCATION-', (None, None))) window_open = True def main_window_menu(event, values): '''Process events common to all windows''' if event == sg.WINDOW_CLOSE_ATTEMPTED_EVENT: sg.user_settings_set_entry('-WINDOW_LOCATION-', window.current_location()) # Save window location before closing window.close() if event == sg.WIN_CLOSED: switch_window(login) if event == "User List": switch_window(user_list) if event == "View Logged Equipment": switch_window(user_equip) def login(): '''User login window''' layout = [ [sg.T("Username")], [sg.InputText(key = "-USER-", do_not_clear=False)], [sg.T("Password")], [sg.InputText(key = "-PASSWORD-", do_not_clear=False)], [sg.Button("OK", bind_return_key=True, key="-OK-")], ] show_window("Login", layout) while window and window_open: event, values = window.read() if event == sg.WINDOW_CLOSE_ATTEMPTED_EVENT: window.close() if event == sg.WIN_CLOSED: switch_window(None) if event == "-OK-": if accounts.get(values['-USER-']) == values['-PASSWORD-']: switch_window(user_list) else: sg.popup('Invalid Login.','Please try again.') window['-USER-'].set_focus() def user_list(): '''Some window that does something''' layout = [ [sg.B("View Logged Equipment"), sg.B("User List")], [sg.B("User List Push Me", bind_return_key=True, key='-PUSH_ME-')] ] show_window("User List", layout) while window and window_open: event, values = window.read() if event == "-PUSH_ME-": print('In user list window') else: main_window_menu(event, values) def user_equip(): '''Some window that does different things''' layout = [ [sg.B("View Logged Equipment"), sg.B("User List")], [sg.B("User Equipment Push Me", bind_return_key=True, key='-PUSH_ME-')] ] show_window("User Equipment", layout) while window and window_open: event, values = window.read() if event == "-PUSH_ME-": print('In user equipment window') else: main_window_menu(event, values) switch_window(login) # Start with login window while next_window: next_window() # execute function to draw next windowI do not think this is the right way to write this program. I would make a tabbed window and create tabs for Logged Equipment, User List, Log Equipment Out, Open Tickets and Open Requests. Instead of destroying and re-creating the windows, the event loop would update the existing widgets to display new information. The resulting program would maybe be 200 lines long to do everything your program currently does.
Hello mate,
See I wanted to have one window that updates based on which tab the user wanted to view, however i couldn't figure out how to have a single dynamic window.
Could you show me how you'd have two layouts and have a single window update based on user input?
If that is even possible :')
I appreciate your feedback, it's really helping me understand further.
while dad_has_cigs == True: happiness = True if dad_has_cigs == False: print("Dad come home!") happiness = not happiness break