Dynamically generating a random # of buttons

I have a piece of code (written in python using streamlit) that creates a random number of clickable buttons (between 2 and 5) and the number of buttons are regenerated after the user clicks on one. I’ve tried having a textbox that always prints what buttons was clicked last but there’s an issue when the current buttonLen is longer than the previous and the final button was clicked on, the textbox doesn’t print the correct button (as it somehow loops over the shorter loop instead of the loop index being the max??), why is that?
another issue is that for some reason the text input for the prompt reappears after the second button click.

import streamlit as st
import random

st.set_page_config(page_title="Story", page_icon="🧩")
st.title("Story")

sub_container = st.empty()
sub = sub_container.subheader("Begin by entering a starting point for your story")
st.caption("make it your very own.")

prompt_container = st.empty()
prompt = prompt_container.text_input('init story prompt', label_visibility="collapsed", placeholder='write me a story about...')

if 'story' not in st.session_state:
    st.session_state.story = "Once upon a time there was..."

if 'lastClick' not in st.session_state:
    st.session_state.lastClick = -1

if 'buttonLen' not in st.session_state:
    st.session_state.buttonLen = random.randint(2, 5)

fake = st.button("stupid", disabled=True)
if 'buttons' not in st.session_state:
    st.session_state.buttons = [fake] * 5

col1, col2, col3, col4, col5 = st.columns(5, gap="medium")
cols = [col1, col2, col3, col4, col5]

if prompt != "" and st.session_state.lastClick == -1:
    # prompt gets printed TWICE in storybox instead of ONCE
    prompt_container.empty()
    st.info(prompt)
    st.session_state.story = st.session_state.story + (f" {prompt}")
    sub = sub_container.subheader("Continue your story by choosing from the options below")

# storyBox = st.text_area("storybox", value=st.session_state.story, disabled=False)
# ADD HERE
storyBox = st.write(st.session_state.story)

for i in range(st.session_state.buttonLen):
    with cols[i]:
        st.session_state.buttons[i] = st.button(str(i))

for i in range(5):
    if st.session_state.buttons[i]:
        if i != st.session_state.lastClick:
            st.session_state.buttons[i] = False
        st.session_state.lastClick = i
        st.session_state.buttonLen = random.randint(2, 5)
        st.session_state.story = st.session_state.story + (f"\n \nYou have chosen option: {i}")
        # adds to textbox a click late,
        # and ofc if ncurr> nlast and click on button[n-1], that one won't show up AT ALL.
        break  

st.write(f"{st.session_state.lastClick} last clicked")

i tried using the session state variables as seen in the code. i used a ‘fake’ button that is always disabled and so has value ‘False’ to populate the buttons list, and rewrite the buttons as fit when generating them, this didn’t fix the bug.

  • Streamlit version: Streamlit, version 1.24.0
  • Python version: Python 3.9.12
  • Using pvenv (?)

It is much easier if you use callbacks.

import random


def on_button_click(button):
    st.session_state.last_clicked = button


nbuttons = random.randint(2, 5)
cols = st.columns(5)

for n in range(nbuttons):
    with cols[n]:
        st.button(f"Button #{n}", on_click=on_button_click, kwargs={"button": n})

if "last_clicked" in st.session_state:
    st.write(f"Last button clicked: **{st.session_state.last_clicked}**")

1 Like

thank you so much! i just started using streamlit so excuse my ignorance :sweat_smile:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.