Streamlit_Calendar事件更新与日历重渲染问题求助
解决方案:Streamlit Calendar 事件更新与重渲染问题修复
问题根源分析
你的代码存在几个关键错误导致事件无法更新和日历重渲染:
- 错误地将
st.session_state["events"]当作字典访问(st.session_state["events"]["events"]),但初始的events是列表类型,而非嵌套字典。 - 手动创建重复日历组件的做法多余,Streamlit会根据会话状态变化自动重渲染组件,无需额外实例化。
- 新事件的资源键使用
resource而非原有事件的resourceId,导致组件无法正确识别该字段。 - 颜色值的
capitalize()处理无意义,十六进制颜色不需要格式转换。
修正后的完整代码
import streamlit as st from streamlit_calendar import calendar # 页面配置 st.set_page_config(page_title="Demo for Streamlit Calendar", page_icon="📆") # 初始化事件列表 if "events" not in st.session_state: st.session_state["events"] = [ { "title": "Event 1", "color": "#FF6C6C", "start": "2024-06-03", "end": "2024-06-05", "resourceId": "a", }, { "title": "Event 2", "color": "#FFBD45", "start": "2024-06-01", "end": "2024-06-10", "resourceId": "b", }, ] # 日历模式选择 mode = st.selectbox( "Calendar Mode:", ("daygrid", "timegrid", "timeline", "list"), ) # 日历配置 calendar_options = { "editable": True, "navLinks": True, "selectable": True, "headerToolbar": { "left": "today prev,next", "center": "title", "right": "", }, "initialDate": "2024-06-01", } # 根据模式设置初始视图 view_mapping = { "daygrid": "dayGridMonth", "timegrid": "timeGridWeek", "timeline": "timelineMonth", "list": "listMonth" } calendar_options["initialView"] = view_mapping[mode] if mode in ["daygrid", "timeline"]: calendar_options["resourceGroupField"] = "building" # 渲染日历组件 calendar_instance = calendar( events=st.session_state["events"], options=calendar_options, custom_css=""" .fc-event-past { opacity: 0.8; } .fc-event-time { font-style: italic; } .fc-event-title { font-weight: 700; } .fc-toolbar-title { font-size: 2rem; } """, key=f"calendar_{mode}" ) # 处理日历内部的事件修改(拖拽、编辑等) if "eventsSet" in calendar_instance: st.session_state["events"] = calendar_instance["eventsSet"] # 侧边栏事件管理 st.sidebar.header("Event Management") event_title = st.sidebar.text_input("Event Title") event_start_date = st.sidebar.date_input("Start Date", value=None) event_end_date = st.sidebar.date_input("End Date", value=None) event_color = st.sidebar.color_picker("Event Color", "#FF6C6C") # 添加事件按钮逻辑 if st.sidebar.button("Add Event"): if event_title and event_start_date and event_end_date: new_event = { "title": event_title, "start": str(event_start_date), "end": str(event_end_date), "color": event_color, "resourceId": "c" # 统一使用resourceId字段 } st.session_state["events"].append(new_event) # 触发页面重渲染(Streamlit会自动处理,此处可添加提示) st.sidebar.success("事件已添加!") # 可选:显示当前事件列表用于调试 # st.write("当前事件列表:", st.session_state["events"])
关键修改说明
- 修正事件列表访问方式:直接使用
st.session_state["events"].append(new_event)添加新事件,因为初始的events是列表类型。 - 移除重复日历实例:删除手动创建
updated_calendar_instance的代码,Streamlit会在会话状态更新后自动重新渲染日历组件。 - 统一资源字段:将新事件的
resource改为resourceId,与原有事件字段保持一致,确保组件正确识别。 - 简化视图配置:使用字典映射替代冗余的条件判断,让代码更简洁。
- 添加成功提示:按钮点击后显示成功信息,提升用户体验。
额外说明
- 日历组件的
key设置为f"calendar_{mode}",确保切换模式时组件能正确重新初始化。 - 保留了日历内部事件修改的处理逻辑(
eventsSet),支持拖拽、编辑等操作后的事件同步。
内容的提问来源于stack exchange,提问作者vrishabh gupta
相关产品推荐
相关产品推荐

