首页 > 解决方案 > Streamlit 在多次运行海龟绘图时崩溃

问题描述

介绍

我正在构建一个绘图应用程序,使用Streamlit库作为前端,Turtle库作为绘图引擎。

问题

当多次调用绘图时,Streamlit 崩溃并抛出以下消息:

Exception ignored in: <function Image.__del__ at 0x0000017A47EF3558>
Traceback (most recent call last):
  File "c:\users\johnsmith\anaconda3\lib\tkinter\__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Tcl_AsyncDelete: async handler deleted by the wrong thread

我希望用户能够更改输入并根据需要多次重新运行应用程序而不会崩溃。

代码

前端:

# frontend.py

import streamlit as st
from backend import *

st.title("Turtle App")
title = st.text_input("Canvas Title", value="My Canvas")
width = st.number_input("Canvas Width", value=500)
height = st.number_input("Canvas Height", value=500)
length = st.number_input("Square Length", value=200)

clicked = st.button("Paint")

if clicked:
    canvas_builder(title, width, height, length)

后端:

# backend.py

import turtle

def canvas_builder(title, canvas_width, canvas_height, square_length):
    CANVAS_COLOR = "red"
    PEN_COLOR = "black"
    scr = turtle.Screen()
    scr.screensize(canvas_width, canvas_height)
    scr.title(title)
    scr.bgcolor(CANVAS_COLOR)
    turtle.setworldcoordinates(0, 0, canvas_width, canvas_height)
    t = turtle.Turtle()
    t.color(PEN_COLOR)
    t.begin_fill()
    for i in range(4):
        t.forward(square_length)
        t.left(90)
    t.end_fill()
    turtle.done()

再生产

  1. 同一文件夹中的所有文件
  2. 在同一文件夹中的 Conda 提示符下,运行:
streamlit run ./st.py
  1. 按照shell指示在浏览器中打开应用程序
  2. 按 UI 底部的“绘画”按钮
  3. 关闭海龟窗口
  4. 再次按下“绘画”按钮
  5. 检查streamlit app的错误提示

笔记

标签: turtle-graphicspython-turtlestreamlit

解决方案


我通过在子进程中运行 turtle 解决了这个问题。新的frontend.py代码:

import multiprocessing
import streamlit as st
from backend import *

st.title("Turtle App")
title = st.text_input("Canvas Title", value="My Canvas")
width = st.number_input("Canvas Width", value=500)
height = st.number_input("Canvas Height", value=500)
length = st.number_input("Square Length", value=200)
clicked = st.button("Paint")

t = multiprocessing.Process(target=canvas_builder, args=(title, width, height, length,))

if clicked:
   t.start()
 

推荐阅读