You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Streamlit下载按钮点击触发重运行,下载延迟问题求助

问题原因

你的问题核心是对Streamlit的运行机制理解有误:Streamlit是基于重运行的框架,任何组件交互(比如按钮点击)都会触发整个脚本从头重新执行一遍。

原代码里,你用st.button('Download QR Code')控制st.download_button的渲染——第一次点击这个按钮时,脚本重运行,此时st.button()返回True,才会渲染出download_button;第二次点击新出现的download_button才会触发下载。这就是需要点击两次的根本原因。

解决方案:直接使用st.download_button

根本不需要额外的触发按钮,st.download_button本身就是可直接点击触发下载的组件,把它直接放在二维码生成后的分支里即可:

import streamlit as st
import qrcode
from io import BytesIO
from PIL import Image


def generate_qr_code(link):  # Generate QR Code
    qr = qrcode.QRCode(
        version=1,
        error_correction=qrcode.constants.ERROR_CORRECT_L,
        box_size=10,
        border=2,
    )
    qr.add_data(link)
    qr.make(fit=True)
    img = qr.make_image(fill_color="black", back_color="white")
    return img


def download_qr_code(img):  # Convert PIL image to bytes
    img_bytes = BytesIO()
    img.save(img_bytes, format='PNG')
    img_bytes.seek(0)
    return img_bytes


st.title("QR Code Generator")
link = st.text_input("Enter a link:")

if link:
    qr_img = generate_qr_code(link)
    # 生成一次字节数据,避免重复转换
    qr_bytes = download_qr_code(qr_img)
    st.image(qr_bytes, caption='Generated QR Code', width=300)
    
    # 直接显示下载按钮,点击即可触发下载
    st.download_button(
        label="Download QR Code",
        data=qr_bytes,
        file_name='qr_code.png',
        mime='image/png'
    )
优化:用st.session_state缓存生成结果(可选)

如果想避免每次页面重运行时重复生成二维码和字节数据,可以用st.session_state缓存结果,只有当链接变化时才重新生成:

import streamlit as st
import qrcode
from io import BytesIO
from PIL import Image


def generate_qr_code(link):  # Generate QR Code
    qr = qrcode.QRCode(
        version=1,
        error_correction=qrcode.constants.ERROR_CORRECT_L,
        box_size=10,
        border=2,
    )
    qr.add_data(link)
    qr.make(fit=True)
    img = qr.make_image(fill_color="black", back_color="white")
    return img


def download_qr_code(img):  # Convert PIL image to bytes
    img_bytes = BytesIO()
    img.save(img_bytes, format='PNG')
    img_bytes.seek(0)
    return img_bytes


st.title("QR Code Generator")
link = st.text_input("Enter a link:")

# 初始化session_state变量
if "last_link" not in st.session_state:
    st.session_state.last_link = ""
if "qr_bytes" not in st.session_state:
    st.session_state.qr_bytes = None

if link:
    # 只有当链接变化时,才重新生成二维码和字节数据
    if link != st.session_state.last_link:
        qr_img = generate_qr_code(link)
        st.session_state.qr_bytes = download_qr_code(qr_img)
        st.session_state.last_link = link
    
    # 直接使用缓存的字节数据
    st.image(st.session_state.qr_bytes, caption='Generated QR Code', width=300)
    
    st.download_button(
        label="Download QR Code",
        data=st.session_state.qr_bytes,
        file_name='qr_code.png',
        mime='image/png'
    )
关键知识点解释
  1. Streamlit重运行机制:任何用户交互(按钮点击、输入框输入等)都会触发整个脚本从头执行,所有组件都是在每次重运行时重新渲染的。
  2. st.download_button的特性:这个组件本身集成了“显示按钮+触发下载”的功能,点击它时会直接向浏览器发送下载数据,不会触发页面重运行(这是少数几个不会触发重运行的组件之一)。
  3. st.session_state的用法:用来在多次重运行之间存储变量,避免重复计算或状态丢失。这里用它缓存二维码的字节数据,只有当输入的链接变化时才重新生成。

内容的提问来源于stack exchange,提问作者Ali Malek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 17:25:28