SungyongAn
@SungyongAn

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

buttonを使用した表示の仕方について教えてください

解決したいこと

Streamlitを使って簡単な算数の問題をランダムで出力して答え合わせまでできるWebアプリを作っています。
「正解表示」ボタンを押すと希望する表示がなされないことと、今まで表示されていた内容も合わせて消えてしまうことを解決したいです。
よろしくお願いします。

発生している問題

問題を出力すると同時に「正解表示」ボタンを作成して、「正解表示」ボタンを押した時に問題を表示したままで正解が表示されるようにしたいのですが、現状では「正解表示」ボタンを押すと正解は表示されず問題も消えてしまう状態です。
1枚目が問題を作成後の画面、2枚目が「正解表示」ボタンを押した画面です。

スクリーンショット 2024-11-17 9.53.15.png

スクリーンショット 2024-11-17 9.56.53.png

該当するソースコード

import requests
import streamlit as st

st.title('算数の勉強部屋')
st.write('')

st.sidebar.write("注意:半角小文字の数字を入力してください。")
a = st.sidebar.text_input("問題数")
b = st.sidebar.text_input("桁数")

if st.sidebar.button(" + (足し算)"):
    count = 0
    for i in range(int(a)):
        url = '使用している関数のパス'
        response = requests.post(url, json={"num_times": 2, "num_range": int(b)})
        answer_list = []
        if response.status_code == 200:
            multiply_file = response.json()
            question_list = multiply_file["question_list"]
            answer = multiply_file["answer"]
            answer_list.append(answer)
            question_no = count +1
            st.write(f'<p style="font-size: 20px;">問{question_no}){question_list[0]} + {question_list[1]} =</p>', unsafe_allow_html=True)
            count += 1
            if count == int(a):
                if st.button('正解表示'):
                    for i in range(int(a)):
                        answer_no = i + 1
                        st.write(f'<p style="font-size: 20px;">問{answer_no}){answer_list[i]} =</p>', unsafe_allow_html=True)
        else:
            st.error(f"{response.status_code}エラーが発生しました。詳細は以下を参照ください")
            st.json(response.json())
0

1Answer

「正解表示」ボタンが押された際に再度、コードがが上から下まで再実行されます。
このとき各変数は初期化されif st.sidebar.button(" + (足し算)"):の方がTrueにならないためif st.button('正解表示')までたどり着けていない形となります。

これを防ぐには、st.session_stateを使用して変数をセッション間で状態を保持する必要があります。

計算部分のAPIurl = '使用している関数のパス'をダミー化していますが、以下のような処理で動作を確認しました。

import requests
import streamlit as st

# セッションステートの初期化
if 'questions' not in st.session_state:
    st.session_state.questions = []
if 'answers' not in st.session_state:
    st.session_state.answers = []
if 'show_answers' not in st.session_state:
    st.session_state.show_answers = False

st.title('算数の勉強部屋')
st.write('')

st.sidebar.write("注意:半角小文字の数字を入力してください。")
a = st.sidebar.text_input("問題数", value='5')  # デフォルト値を設定
b = st.sidebar.text_input("桁数", value='2')  # デフォルト値を設定

if st.sidebar.button(" + (足し算)"):
    try:
        num_questions = int(a)
        num_digits = int(b)
    except ValueError:
        st.sidebar.error("問題数と桁数には整数を入力してください。")
    else:
        st.session_state.questions = []
        st.session_state.answers = []
        st.session_state.show_answers = False  # 正解表示をリセット

        for i in range(num_questions):
            # ★APIが不明のためダミー処理
            #url = '使用している関数のパス'
            #response = requests.post(url, json={"num_times": 2, "num_range": num_digits})
            # if response.status_code == 200:
            #     data = response.json()
            #     question = f"{data['question_list'][0]} + {data['question_list'][1]} ="
            #     answer = data['answer']
                st.session_state.questions.append("ダミー+ダミー")
                st.session_state.answers.append("ダミー回答")
            # else:
            #     st.error(f"{response.status_code}エラーが発生しました。詳細は以下を参照ください")
            #     st.json(response.json())
            #     break  # エラーが発生したらループを抜ける

# 問題の表示
if st.session_state.questions:
    st.write("### 問題一覧")
    for idx, question in enumerate(st.session_state.questions, 1):
        st.write(f'<p style="font-size: 20px;">問{idx}{question}</p>', unsafe_allow_html=True)

    # 正解表示ボタン
    if st.button('正解表示'):
        st.session_state.show_answers = True

    # 正解の表示
    if st.session_state.show_answers:
        st.write("### 正解一覧")
        for idx, answer in enumerate(st.session_state.answers, 1):
            st.write(f'<p style="font-size: 20px;">問{idx}{answer}</p>', unsafe_allow_html=True)

1Like

Comments

  1. @SungyongAn

    Questioner

    丁寧な回答ありがとうございます。

    「正解表示」ボタンが押された際に再度、コードが上から下まで再実行されます。このとき各変数は初期化されif st.sidebar.button(" + (足し算)"):の方がTrueにならないためif st.button('正解表示')までたどり着けていない形となります。
    なんとなくですが、表示が初期化されてるのかな?という疑問はあったのですが、まさかコードが上から下まで再度実行されているとは思いませんでした。
    頂いたコードを参考に色々と試してみたいと思います!

Your answer might help someone💌