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

如何在Flet中切换视图?出现主线程错误问题

Flet框架视图切换报错解决方案

问题现象

在使用Flet开发应用时,定义了main和main2两个页面函数,尝试从main视图切换到main2视图时触发错误:

signal only works in main thread of the main interpreter

错误原因

原代码中在main函数末尾直接调用flet.app(target=main2),这是错误用法:

  • flet.app()是应用的启动入口,仅能在主线程调用一次
  • 在已运行的页面函数中再次调用会创建新应用实例,且处于非主线程,导致信号处理报错

正确实现视图切换的方式

方法1:清空页面并重构组件(适合简单场景)

直接清空当前页面所有组件,再调用目标页面的构建逻辑:

import flet
from flet import Checkbox, ElevatedButton, Row, Text, TextField, Column
from flet import AppBar, Icon, IconButton, Page, PopupMenuButton, PopupMenuItem, colors, icons

def build_main(page):
    def add_clicked(e):
        page.add(Checkbox(label=new_task.value))
    
    # 构建main页面内容
    new_task = TextField(hint_text="需要做什么?", width=300)
    page.add(Row([new_task, ElevatedButton("添加", on_click=add_clicked)]))
    t = Text(
        value="这是文本控件示例",
        size=30,
        color="white",
        bgcolor="pink",
        weight="bold",
        italic=True,
    )
    page.add(t)
    # 添加切换按钮
    switch_btn = ElevatedButton("切换到main2页面", on_click=lambda e: switch_to_main2(page))
    page.add(switch_btn)
    page.scroll='always'
    page.update()

def build_main2(page):
    def check_item_clicked(e):
        e.control.checked = not e.control.checked
        page.update()
    
    # 构建main2页面内容
    page.appbar = AppBar(
        leading=Icon(icons.PALETTE),
        leading_width=40,
        title=Text("AppBar示例"),
        center_title=False,
        bgcolor=colors.SURFACE_VARIANT,
        actions=[
            IconButton(icons.WB_SUNNY_OUTLINED),
            IconButton(icons.FILTER_3),
            PopupMenuButton(
                items=[
                    PopupMenuItem(text="选项1"),
                    PopupMenuItem(),  # 分隔线
                    PopupMenuItem(
                        text="可勾选选项", checked=False, on_click=check_item_clicked
                    ),
                ]
            ),
        ],
    )
    page.add(Text("页面内容!"))
    # 添加返回按钮
    back_btn = ElevatedButton("返回main页面", on_click=lambda e: switch_to_main(page))
    page.add(back_btn)
    page.update()

def switch_to_main2(page):
    page.clear()  # 清空当前页面所有组件
    build_main2(page)

def switch_to_main(page):
    page.clear()
    build_main(page)

def main(page):
    build_main(page)

flet.app(target=main)

方法2:使用Flet路由系统(推荐多页面应用)

利用Flet的View和路由功能,实现规范的页面导航:

import flet
from flet import Checkbox, ElevatedButton, Row, Text, TextField, Column
from flet import AppBar, Icon, IconButton, Page, PopupMenuButton, PopupMenuItem, colors, icons, View, RouteChangeEvent, ViewPopEvent

def main(page: Page):
    page.title = "Flet多页面示例"

    def route_change(e: RouteChangeEvent):
        page.views.clear()
        # 根据当前路由加载对应页面
        if e.route == "/":
            page.views.append(
                View(
                    "/",
                    [
                        TextField(hint_text="需要做什么?", width=300),
                        ElevatedButton("添加", on_click=lambda _: page.add(Checkbox(label=new_task.value))),
                        Text(
                            value="这是文本控件示例",
                            size=30,
                            color="white",
                            bgcolor="pink",
                            weight="bold",
                            italic=True,
                        ),
                        ElevatedButton("切换到main2页面", on_click=lambda _: page.go("/main2"))
                    ],
                )
            )
        elif e.route == "/main2":
            page.views.append(
                View(
                    "/main2",
                    [
                        AppBar(
                            leading=Icon(icons.PALETTE),
                            leading_width=40,
                            title=Text("AppBar示例"),
                            center_title=False,
                            bgcolor=colors.SURFACE_VARIANT,
                            actions=[
                                IconButton(icons.WB_SUNNY_OUTLINED),
                                IconButton(icons.FILTER_3),
                                PopupMenuButton(
                                    items=[
                                        PopupMenuItem(text="选项1"),
                                        PopupMenuItem(),
                                        PopupMenuItem(
                                            text="可勾选选项", checked=False, on_click=lambda e: (setattr(e.control, "checked", not e.control.checked), page.update())
                                        ),
                                    ]
                                ),
                            ],
                        ),
                        Text("页面内容!"),
                        ElevatedButton("返回main页面", on_click=lambda _: page.go("/"))
                    ],
                )
            )
        page.update()

    def view_pop(e: ViewPopEvent):
        page.views.pop()
        top_view = page.views[-1]
        page.go(top_view.route)

    page.on_route_change = route_change
    page.on_view_pop = view_pop
    page.go(page.route)

flet.app(target=main)

原始错误代码

import flet
from flet import Checkbox, ElevatedButton, Row,Text, TextField,sleep,Column
from flet import (
    AppBar,
    Icon,
    IconButton,
    Page,
    PopupMenuButton,
    PopupMenuItem,
    Text,
    colors,
    icons,
)

def main(page):
    def add_clicked(e):
        page.add(Checkbox(label=new_task.value))

    new_task = TextField(hint_text="Whats needs to be done?", width=300)
    page.add(Row([new_task, ElevatedButton("Add", on_click=add_clicked)]))
    t = Text(
    value="This is a Text control sample",
    size=30,
    color="white",
    bgcolor="pink",
    weight="bold",
    italic=True,)
    page.add(t)
    btn = ElevatedButton("Click me!")
    page.add(btn)
    page.scroll='always'
    page.update()
    first_name = TextField()
    last_name = TextField()
    page.add(first_name, last_name)
    sleep(2)
    first_name.disabled = True
    last_name.disabled = True
    page.update()
    first_name = TextField()
    last_name = TextField()
    c = Column(controls=[
        first_name,
        last_name
        ])
    c.disabled = True
    page.add(c)
    flet.app(target=main2)  # 错误调用:在此处启动新应用实例

def main2(page: Page):
    def check_item_clicked(e):
        e.control.checked = not e.control.checked
        page.update()

    page.appbar = AppBar(
        leading=Icon(icons.PALETTE),
        leading_width=40,
        title=Text("AppBar Example"),
        center_title=False,
        bgcolor=colors.SURFACE_VARIANT,
        actions=[
            IconButton(icons.WB_SUNNY_OUTLINED),
            IconButton(icons.FILTER_3),
            PopupMenuButton(
                items=[
                    PopupMenuItem(text="Item 1"),
                    PopupMenuItem(),  # divider
                    PopupMenuItem(
                        text="Checked item", checked=False, on_click=check_item_clicked
                    ),
                ]
            ),
        ],
    )
    page.add(Text("Body!"))

flet.app(target=main)

内容的提问来源于stack exchange,提问作者Abhay Gaur

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 20:06:22