How would I dynamically update buttons in PYSimpleGUI

Question:

I am trying to create a looping text based "choose your own adventure" story game. The code is built into separate functions. Each function has a story element (returned in text format), a selection of player choices used for updating the text on the buttons (returned in dictionary format) and then the next functions to pull up based on the choice the player makes (also in dictionary format.

When complete and properly working, there will be two buttons below the text, that once clicked, would instantly update the onscreen text and the buttons at the bottom of the screen.

From my experimentation so far, it seems that I cannot put a while loop before the point where it creates the window, and I cannot figure out how to build a loop after the point where it creates the window. I am thinking I have mapped the buttons wrong, but I am at a loss for where to go next. If anyone has any ideas, it would be most helpful.
Thank you.

Current main Function:

import PySimpleGUI as sg
def main ():
        sg.theme("default1")   
        # All the stuff inside your window.
        char_info = character_creation()
        char_name = char_info[0]
        char_gender = char_info[1]
    
        scene_loading(char_name,char_gender)
    
        # Maps the player choices to the variable current_scene
        current_scene = cabin_scene(char_name, char_gender)
        # Returns (story_text, player_choices, next_scenes)
    
        # Pulls display text from current scene to display to user
        display_text = current_scene [0]
        
        # Pulls returned options from current scene to be mapped to display
        current_options = current_scene [1]
        option_1 = current_options ["option_1"]
        option_2 = current_options ["option_2"]
    
        # Format of dictionary values
        # {"option_1":first_scene,"option_2":second_scene}
        next_scenes = current_scene [2]
        first_scene = next_scenes ["option_1"]
        second_scene = next_scenes ["option_2"]
    
        layout = [  [sg.Text(display_text) ],
            [sg.Button(option_1),sg.Button(option_2)], 
            [sg.Button("Cancel")] ]
     
        # Create the Window
        window = sg.Window("The Ultimate Choose Your Own Adventure Story", layout)
        # Event Loop to process "events" and get the "values" of the inputs
        while True:
            event, values = window.read()
            if event == sg.WIN_CLOSED or event == "Cancel": # if user closes window or clicks cancel
                break
     
        window. Close()

Sample function return values:

story_text = f"""Insert text personalized to user here."""
player_choices = {
        "option_1":"HIDE",
        "option_2":"ESCAPE"}

next_scenes = {
        "option_1":closet_scene,
        "option_2":forest_scene}

return story_text, player_choices, next_scenes
Asked By: Joseph

||

Answers:

A simple script here may help.

import PySimpleGUI as sg

layout = [
    [sg.Text('Page 1/5', size=20, key='TEXT')],
    [sg.pin(sg.Button('PREV', visible=False)), sg.Push(), sg.pin(sg.Button('NEXT'))],
]
window = sg.Window('Title', layout)
page = 1
while True:

    event, values = window.read()

    if event == sg.WIN_CLOSED:
        break
    elif event in ('PREV', 'NEXT'):
        page += 1 if event == 'NEXT' else -1
    window['TEXT'].update(f'Page {page}/5')
    window['PREV'].update(visible=(page!=1))
    window['NEXT'].update(visible=(page!=5))

window.close()
Answered By: Jason Yang

The short answer you can get what you want through selectively hiding buttons, but cannot change the layout once the window is built. The ‘fixed layout’ is a core requirement of PySimpleGUI.

You can make a page with enough buttons for any element in the game, say five. One each story element, you set the text of some buttons and hide
the others. Your update function might look something like this:

   # choice_names is a list of strings for the current story event
   for i in range(MAX_CHOICES):
       if i < len(choice_names):
          window[f'option_{i+1}'].update(choice_names[i], visible=True)
       else:
          window[f'option_{i+1}'].update(visible=False)

The code from Jason Wang above uses the visible parameter to hide the ‘PREV’ and ‘NEXT’ buttons, so you can use that as another example. This cookbook recipe has a more involved example.

Keep hacking! Keep notes.

Charles

Answered By: Charles Merriam