在阶段1和2中,我们可以使用回调函数来设置阶段的值。例如,在阶段1中,我们可以使用text_input小部件来获取用户的姓名,并在值更改时将阶段设置为2:
if st.session_state.stage >= 1: name = st.text_input('姓名', on_change=set_state, args=[2])
在阶段2中,我们可以显示根据用户输入的姓名显示的消息,并通过使用selectbox小部件来让用户选择颜色。如果颜色选择框的值为None,我们可以将阶段设置回2:
if st.session_state.stage >= 2: st.write(f'你好,{name}!') color = st.selectbox( '选择一种颜色', [None, '红色', '橙色', '绿色', '蓝色', '紫色'], on_change=set_state, args=[3] ) if color is None: set_state(2)
在阶段3中,我们可以显示一个带有感谢消息的消息,并创建一个按钮来将阶段重置为0:
if st.session_state.stage >= 3: st.write(f'😊谢谢你,{color}!') st.button('重新开始', on_click=set_state, args=[0])
3.5 动态添加小部件的按钮 ✔️💡💻🔄
在开始之前,我们需要确保使用唯一的索引来保持键的唯一性并避免错误。在本示例中,我们定义了一个display_input_row函数,用于渲染一行小部件。该函数接受一个索引作为参数。小部件的键(key)使用了传入的索引,以便可以在单个脚本重新运行时多次执行而不会重复任何小部件的键。
import streamlit as st def display_input_row(index): left, middle, right = st.columns(3) left.text_input('First', key=f'first_{index}') middle.text_input('Middle', key=f'middle_{index}') right.text_input('Last', key=f'last_{index}')
接下来,我们检查st.session_state中是否存在名为’rows’的键。如果不存在,我们将其初始值设置为0。
if 'rows' not in st.session_state: st.session_state['rows'] = 0
然后,我们定义一个increase_rows函数,在点击按钮时增加st.session_state[‘rows’]的值。
def increase_rows(): st.session_state['rows'] += 1
我们创建一个"Add person"按钮,并将它与increase_rows函数进行关联。
st.button('Add person', on_click=increase_rows)
接下来,我们使用一个循环来根据st.session_state[‘rows’]的值动态地调用display_input_row函数。
for i in range(st.session_state['rows']): display_input_row(i)
最后,我们展示添加结果的部分。在一个循环中,我们根据st.session_state中的键和索引来获取相应的小部件的值,并将其展示在页面上。
st.subheader('People') for i in range(st.session_state['rows']): st.write( f'Person {i+1}:', st.session_state[f'first_{i}'], st.session_state[f'middle_{i}'], st.session_state[f'last_{i}'] )
通过点击"Add person"按钮,我们可以动态地添加小部件,并在页面上显示。在循环中,每个小部件都有一个唯一的键,因此我们可以轻松地获取和展示它们的值。
3.6 使用按钮处理耗时或写入文件的过程 🔄💾⏱️💡
介绍如何使用按钮来处理耗时或写入文件的过程,并将结果保存起来,以便在不必要重新执行的情况下继续访问。这对于保存到磁盘或写入数据库的过程尤其有帮助。
在本示例中,我们有一个expensive_process函数,它依赖于两个参数:option和add。函数执行相应的过程,并返回一个结果。值得注意的是,更改option会改变输出结果,而更改add只是提供了一个参数。
import streamlit as st import pandas as pd import time def expensive_process(option, add): with st.spinner('Processing...'): time.sleep(5) df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6], 'C':[7, 8, 9]}) + add return (df, add)
我们创建了两个列(cols)来显示输入选项和添加数值的小部件。使用selectbox和number_input分别接收用户的输入。在代码中,我们使用了st.columns以便将小部件在页面上水平排列。
cols = st.columns(2) option = cols[0].selectbox('Select a number', options=['1', '2', '3']) add = cols[1].number_input('Add a number', min_value=0, max_value=10)
接下来,我们检查st.session_state中是否存在名为’processed’的键。如果不存在,我们将其初始化为空字典。
if 'processed' not in st.session_state: st.session_state.processed = {}
当用户点击"Process"按钮时,我们执行expensive_process函数,并将结果保存在st.session_state.processed中。
if st.button('Process'): result = expensive_process(option, add) st.session_state.processed[option] = result
最后,我们检查option是否在st.session_state.processed中,如果是的话,我们展示处理结果并打印出数据框。
if option in st.session_state.processed: st.write(f'Option {option} processed with add {add}') st.write(st.session_state.processed[option][0])
通过点击"Process"按钮,我们可以处理耗时的过程并将结果保存下来。如果用户改变了option,我们会重新运行相应的过程并更新结果。
需要注意的是,保存在st.session_state中的结果仅对当前用户的当前会话可见。如果使用st.cache_data代替,结果将对所有用户和所有会话可见。此外,如果要更新已保存的结果,必须清除该函数的所有保存结果。
4 常见的按钮反模式 🚫⚠️
在使用按钮时,以下是一些常见的错误做法,需要格外注意。
4.1 按钮嵌套在按钮内部
在下面的示例中,我们可以看到按钮2被嵌套在按钮1的内部。这种嵌套将导致按钮2永远不会被执行。因为当按钮1被点击时,按钮2的代码块将永远不会执行。
import streamlit as st if st.button('Button 1'): st.write('Button 1 was clicked') if st.button('Button 2'): # This will never be executed. st.write('Button 2 was clicked')
4.2 将其他小部件嵌套在按钮内部
在下面的示例中,我们可以看到当用户点击"Sign up"按钮时,会显示一个用于输入姓名的文本框。然而,当用户输入姓名后,欢迎消息不会被执行。这是因为欢迎消息的代码块被嵌套在"Sign up"按钮的代码块内部,而不是与之并列。
import streamlit as st if st.button('Sign up'): name = st.text_input('Name') if name: # This will never be executed. st.success(f'Welcome {name}')
4.3 在按钮内部嵌套处理过程,但未保存到会话状态中
在下面的示例中,我们可以看到"Get data"按钮被点击时,我们会读取一个CSV文件,并在屏幕上展示结果。然而,当用户点击"Save"按钮时,将会遇到一个错误。这是因为我们在"Save"按钮的代码块内部尝试将数据保存为CSV文件,但是没有将数据保存到会话状态(session state)中,所以在"Save"按钮点击后,数据丢失了。
import streamlit as st import pandas as pd file = st.file_uploader("Upload a file", type="csv") if st.button('Get data'): df = pd.read_csv(file) # This display will go away with the user's next action. st.write(df) if st.button('Save'): # This will always error. df.to_csv('data.csv')
5 结语
感谢您阅读本篇博客!我们希望这篇博客对您理解如何使用按钮处理耗时或写入文件的过程有所帮助。如果您有任何问题或需要进一步的帮助,请随时留言。如果您觉得这篇博客对您有用,请点赞并关注我们的博客,以获取更多有用的信息和教程。谢谢您的支持!🙏❤️📚