Streamlight同步输入字段

2024-05-15 23:19:18 发布

您现在位置:Python中文网/ 问答频道 /正文

我有两个输入字段,允许用户通过

  • ID,在数字输入中
  • (已排序)名称,在选择框中

更改一个输入字段应更新另一个字段以保持同步

enter image description here

如何使用Streamlight实现这种行为

我到目前为止所做的尝试

已选择ID->;更新名称选择框:

users = [(1, 'Jim'), (2, 'Jim'), (3, 'Jane')]
users.sort(key=lambda user: user[1])  # sort by name

selected_id = st.sidebar.number_input('ID', value=1)

options = ['%s (%d)' % (name, id) for id, name in users]
index = [i for i, user in enumerate(users) if user[0] == selected_id][0]
selected_option = st.sidebar.selectbox('Name', options, index)

所选名称->;更新ID号输入(使用st.empty()):

users = [(1, 'Jim'), (2, 'Jim'), (3, 'Jane')]
users.sort(key=lambda user: user[1])  # sort by name

id_input = st.sidebar.empty()

options = ['%s (%d)' % (name, id) for id, name in users]
selected_option = st.sidebar.selectbox('Name', options)

# e.g. get 2 from "Jim (2)"
id = int(re.match(r'\w+ \((\d+)\)', selected_option).group(1))
selected_id = id_input.number_input('ID', value=id)

Tags: namein名称idforinputsortusers
1条回答
网友
1楼 · 发布于 2024-05-15 23:19:18

要使小部件保持同步,需要解决两个问题:

  1. 我们需要能够告诉任何一个小部件何时导致当前选择发生变化;及
  2. 我们需要在脚本末尾更新这两个小部件的状态,以便在重新运行脚本进行视觉更新时,浏览器保留新值

对于(1),看起来如果不引入某种持久状态,就没有办法做到这一点。如果无法在脚本运行之间存储当前选择,我们只能将两个小部件的值相互比较,并与默认值进行比较。一旦小部件发生更改,就会出现问题:例如,如果默认值为1,数字输入的值为2,选择框的值为3,我们无法判断最近更改的是数字输入还是选择框(因此更新为最新的值)

对于(2),只要在选择发生更改时使用占位符并刷新小部件就可以了。重要的是,如果选择没有改变,小部件应该而不是被刷新,否则我们将得到DuplicateWidgetID错误(因为小部件的内容也不会改变,它们将具有相同的生成键)

下面的一些代码显示了处理这两个问题的一种方法,并在最后捕获用户的选择。请注意,以这种方式使用@st.cache将在多个浏览器会话中保留单个全局选择,并允许任何人通过streamlight菜单清除选择->;'清除缓存”,如果多个用户同时访问脚本,则可能会出现问题

import re

import streamlit as st

# Simple persistent state: The dictionary returned by `get_state()` will be
# persistent across browser sessions.
@st.cache(allow_output_mutation=True)
def get_state():
    return {}


# The actual creation of the widgets is done in this function.
# Whenever the selection changes, this function is also used to refresh the input
# widgets so that they reflect their new state in the browser when the script is re-run
# to get visual updates.
def display_widgets():
    users = [(1, "Jim"), (2, "Jim"), (3, "Jane")]
    users.sort(key=lambda user: user[1])  # sort by name
    options = ["%s (%d)" % (name, id) for id, name in users]
    index = [i for i, user in enumerate(users) if user[0] == state["selection"]][0]

    return (
        number_placeholder.number_input(
            "ID", value=state["selection"], min_value=1, max_value=3,
        ),
        option_placeholder.selectbox("Name", options, index),
    )


state = get_state()

# Set to the default selection
if "selection" not in state:
    state["selection"] = 1

# Initial layout
number_placeholder = st.sidebar.empty()
option_placeholder = st.sidebar.empty()

# Grab input and detect changes
selected_number, selected_option = display_widgets()

input_changed = False

if selected_number != state["selection"] and not input_changed:
    # Number changed
    state["selection"] = selected_number
    input_changed = True
    display_widgets()

selected_option_id = int(re.match(r"\w+ \((\d+)\)", selected_option).group(1))
if selected_option_id != state["selection"] and not input_changed:
    # Selectbox changed
    state["selection"] = selected_option_id
    input_changed = True
    display_widgets()

st.write(f"The selected ID was: {state['selection']}")

相关问题 更多 >