我的应用程序中有一个按钮,我想在用户单击它时对其进行样式设置。问题是,因为 Streamlit 不允许我们向我们创建的对象发出类,所以我需要找到一种方法来以稳健且与版本无关的方式指定确切的按钮。 这就是按钮在 Streamlit 中的样子:
<div class="row-widget stButton" style="width: 64px;"><button kind="primary" class="css-4eonon edgvbvh1">📆</button></div>
我想到的唯一解决方案是使用一组唯一的元素来定义行。这有点像黑客,但效果很好,并且是一种解决方案,直到 Streamlit 社区提出更好的方法。
在此示例中,我将有一行 4 列,这对于我的侧边栏来说是唯一的。
col1, col2, col3, col4 = st.sidebar.columns([1, 1, 1, 1])
按钮:
with col1:
st.button("📆", on_click=style_button_row, kwargs={
'clicked_button_ix': 1, 'n_buttons': 4
})
with col2:
st.button("👌", on_click=style_button_row, kwargs={
'clicked_button_ix': 2, 'n_buttons': 4
})
with col3:
st.button("◀", on_click=style_button_row, kwargs={
'clicked_button_ix': 3, 'n_buttons': 4
})
with col4:
st.button("🚧", on_click=style_button_row, kwargs={
'clicked_button_ix': 4, 'n_buttons': 4
})
样式方式灵感来自CSS可以检测元素拥有的子元素数量吗?:
div[data-testid*="stHorizontalBlock"] > div:nth-child(%(nth_child)s):nth-last-child(%(nth_last_child)s) button
造型功能:
def style_button_row(clicked_button_ix, n_buttons):
def get_button_indices(button_ix):
return {
'nth_child': button_ix,
'nth_last_child': n_buttons - button_ix + 1
}
clicked_style = """
div[data-testid*="stHorizontalBlock"] > div:nth-child(%(nth_child)s):nth-last-child(%(nth_last_child)s) button {
border-color: rgb(255, 75, 75);
color: rgb(255, 75, 75);
box-shadow: rgba(255, 75, 75, 0.5) 0px 0px 0px 0.2rem;
outline: currentcolor none medium;
}
"""
unclicked_style = """
div[data-testid*="stHorizontalBlock"] > div:nth-child(%(nth_child)s):nth-last-child(%(nth_last_child)s) button {
pointer-events: none;
cursor: not-allowed;
opacity: 0.65;
filter: alpha(opacity=65);
-webkit-box-shadow: none;
box-shadow: none;
}
"""
style = ""
for ix in range(n_buttons):
ix += 1
if ix == clicked_button_ix:
style += clicked_style % get_button_indices(ix)
else:
style += unclicked_style % get_button_indices(ix)
st.markdown(f"<style>{style}</style>", unsafe_allow_html=True)
这是使用 CSS 的另一种方法:
import streamlit as st
st.markdown(
"""
<style>
.element-container:has(style){
display: none;
}
.element-container:has(#primary) {
display: none;
}
.element-container:has(#secondary) {
display: none;
}
.element-container:has(#primary) + div button {
background-color: #4CAF50; /* Green background */
border: none; /* Remove borders */
color: white; /* White text */
padding: 15px 32px; /* Add some padding */
text-align: center; /* Center text */
text-decoration: none; /* Remove underline */
display: inline-block; /* Make the button inline block */
font-size: 16px; /* Increase font size */
margin: 4px 2px; /* Add some margin */
transition-duration: 0.4s; /* Transition effect */
cursor: pointer; /* Pointer cursor on hover */
}
.element-container:has(#primary) + div button:hover {
background-color: white; /* White background on hover */
color: black; /* Black text on hover */
border: 2px solid #4CAF50; /* Green border on hover */
}
.element-container:has(#secondary) + div button {
background-color: #800080; /* Purple background */;
border: none; /* Remove borders */
color: white; /* White text */
padding: 15px 32px; /* Add some padding */
text-align: center; /* Center text */
text-decoration: none; /* Remove underline */
display: inline-block; /* Make the button inline block */
font-size: 16px; /* Increase font size */
margin: 4px 2px; /* Add some margin */
transition-duration: 0.4s; /* Transition effect */
cursor: pointer; /* Pointer cursor on hover */
}
.element-container:has(#secondary) + div button:hover {
background-color: white; /* White background on hover */
color: black; /* Black text on hover */
border: 2px solid #800080; /* Purple border on hover */
}
</st
</style>
""",
unsafe_allow_html=True,
)
def styler(id_="primary"):
st.markdown(f'<span id="{id_}"></span>', unsafe_allow_html=True)
# place this right before the button
styler("primary")
if st.button("button1"):
st.write("button 1 clicked!")
styler("secondary")
if st.button("button2"):
st.write("button 2 clicked!")
这是受到这篇文章的启发。