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

Kivy Python中ErrorPopup多次触发后无法关闭的问题求助

问题:ErrorPopup第二次触发后无法关闭

我实现了一个错误发生时弹出的ErrorPopup,点击“Try Again”按钮可关闭弹窗。首次触发错误时功能正常,但第二次触发错误后,该弹窗无法关闭,求解决方法。


原Python代码

class MyPopup(Popup):
    filechooser= ObjectProperty(None)

class ErrorPopup(Popup):
    filechooser= ObjectProperty(None)


class Main(FloatLayout):
    audio_check= ObjectProperty(None)
    video_check= ObjectProperty(None)
    spinner_id= ObjectProperty(None)
    yt_link=ObjectProperty(None)
    name=ObjectProperty(None)
    error_label=ObjectProperty(None)
    def submit_text(self):
        self.error_popup=MyApp()
        if self.audio_check.active and self.video_check.active:
            try:
                YouTube(self.yt_link.text).streams.filter(res=self.spinner_id.text).first().download(path, filename=self.name.text+'.mp4')
            except:
                self.error_popup.error()
        elif self.audio_check.active and not self.video_check.active:
            try:
                YouTube(self.yt_link.text).streams.filter(only_audio=True).first().download(path, filename=self.name.text+'.mp3')
            except:
                self.error_popup.error()
        elif not self.audio_check.active and self.video_check.active:
            try:
                YouTube(self.yt_link.text).streams.filter(res=self.spinner_id.text, only_video =True).first().download(path, filename=self.name.text+'.mp4')
            except:
                self.error_popup.error()
        elif not self.audio_check.active and not self.video_check.active:
            self.error_popup.error()
    def spinner_clicked(self, value):
        self.ids.spinner_id.text= value
    


class MyApp(App):
    def build(self):
        return Main()
    def open_popup(self):
        self.popup = MyPopup()
        self.popup.open()

    def dismiss_popup(self):
        self.popup.dismiss()
        global path
        path=self.popup.filechooser.path
    
    def error(self):
        self.error_popup= ErrorPopup()
        self.error_popup.open()
    def try_again(self):
        self.error_popup.dismiss()
        print("Andrew")


            

if __name__ == '__main__':
    MyApp().run()

原Kivy代码

<MyPopup>:
    auto_dismiss: False
    title: "Select a folder"
    filechooser: filechooser
    FloatLayout:
        FileChooserIconView:
            id: filechooser
        Button:
            id:my_button
            text: 'Save'
            size_hint: (0.1, 0.1)
            pos_hint:{'x': 0, 'y': 0}
            on_release: app.dismiss_popup()

<ErrorPopup>:
    title: "Error"
    Button:
        text: "Try Again"
        on_release: app.try_again()




<Main>:
    audio_check: audio_check
    video_check: video_check
    spinner_id: spinner_id
    yt_link: yt_link
    name: name
    folder_button: folder_button
    BoxLayout:
        orientation:'vertical'
        cols: 4
        Label:
            text: "YouTube Downloader"
            halign: 'center'
            bold: True
            font_size:'50sp'
        TextInput:
            id: yt_link
            size_hint: (.5, .2)
            multiline: False
            hint_text: 'Enter the link of the Youtube video you want to download.'
            pos_hint: {"x": 0.25}
        TextInput:
            id: name
            size_hint: (.5, .2)
            multiline: False
            hint_text: 'Enter the name you want the file to have.'
            pos_hint: {"x": 0.25}
        BoxLayout:
            cols:4
            BoxLayout:
                Label:
                    text: "Audio:"
                    halign: 'center'
                    font_size:'20sp'
                CheckBox:
                    id: audio_check
            BoxLayout:
                Label:
                    text: "Video:"
                    halign: 'center'
                    font_size:'20sp'
                CheckBox:
                    id: video_check
            FloatLayout:
                Spinner:
                    id: spinner_id
                    text: "Quality"
                    values: ['144p', '240p', '360p', '480p', '720p', '1080p', '1440p', '2160p']
                    on_text: root.spinner_clicked(spinner_id.text)
                    size_hint: None, None
                    size: 130, 50
                    pos_hint: {'x': .2, 'y':.4}
            FloatLayout:
                Button:
                    id:folder_button
                    text: 'Folder'
                    on_release: app.open_popup()
                    size_hint: None, None
                    size: 130, 50
                    pos_hint: {'x':0.2,'y':.4}
        Button:
            text: "Submit"
            size_hint: (.5, .2)
            pos_hint: {"x": 0.25}
            on_release: root.submit_text()

问题根源

  • 核心错误:在Main.submit_text()方法中,每次调用都创建新的MyApp实例:self.error_popup=MyApp()。Kivy应用运行过程中只能有一个活跃的App实例,新创建的App实例与当前运行的App完全无关,导致后续error()调用操作的是新实例的弹窗,而try_again()是在原App实例上执行,无法关闭新弹窗。
  • 冗余代码:ErrorPopup类中的filechooser= ObjectProperty(None)完全无用,属于冗余定义。

修复方案

1. 修正App实例获取方式

将Main.submit_text()中的self.error_popup=MyApp()替换为获取当前运行的App实例,所有错误触发调用改为使用该实例:

# 在submit_text方法开头添加
from kivy.app import App
self.app = App.get_running_app()

# 所有self.error_popup.error()替换为
self.app.error()

2. 优化弹窗管理(可选但更健壮)

在MyApp的error()方法中添加弹窗检查,避免重复创建弹窗:

def error(self):
    # 若已有打开的错误弹窗,先关闭再创建新的
    if hasattr(self, 'error_popup') and self.error_popup.is_open:
        self.error_popup.dismiss()
    self.error_popup = ErrorPopup()
    self.error_popup.open()

3. 移除冗余属性

删除ErrorPopup类中的filechooser= ObjectProperty(None)。


完整修正后的Python代码

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.popup import Popup
from kivy.properties import ObjectProperty
from pytube import YouTube

class MyPopup(Popup):
    filechooser = ObjectProperty(None)

class ErrorPopup(Popup):
    # 移除无用的filechooser属性
    pass

class Main(FloatLayout):
    audio_check = ObjectProperty(None)
    video_check = ObjectProperty(None)
    spinner_id = ObjectProperty(None)
    yt_link = ObjectProperty(None)
    name = ObjectProperty(None)
    error_label = ObjectProperty(None)
    
    def submit_text(self):
        # 获取当前运行的App实例
        self.app = App.get_running_app()
        global path
        
        if self.audio_check.active and self.video_check.active:
            try:
                YouTube(self.yt_link.text).streams.filter(res=self.spinner_id.text).first().download(path, filename=self.name.text+'.mp4')
            except Exception as e:
                print(f"错误详情: {e}")
                self.app.error()
        elif self.audio_check.active and not self.video_check.active:
            try:
                YouTube(self.yt_link.text).streams.filter(only_audio=True).first().download(path, filename=self.name.text+'.mp3')
            except Exception as e:
                print(f"错误详情: {e}")
                self.app.error()
        elif not self.audio_check.active and self.video_check.active:
            try:
                YouTube(self.yt_link.text).streams.filter(res=self.spinner_id.text, only_video=True).first().download(path, filename=self.name.text+'.mp4')
            except Exception as e:
                print(f"错误详情: {e}")
                self.app.error()
        else:
            self.app.error()
    
    def spinner_clicked(self, value):
        self.ids.spinner_id.text = value

class MyApp(App):
    def build(self):
        return Main()
    
    def open_popup(self):
        self.popup = MyPopup()
        self.popup.open()

    def dismiss_popup(self):
        self.popup.dismiss()
        global path
        path = self.popup.filechooser.path
    
    def error(self):
        if hasattr(self, 'error_popup') and self.error_popup.is_open:
            self.error_popup.dismiss()
        self.error_popup = ErrorPopup()
        self.error_popup.open()
    
    def try_again(self):
        if hasattr(self, 'error_popup') and self.error_popup.is_open:
            self.error_popup.dismiss()
        print("Andrew")

if __name__ == '__main__':
    MyApp().run()

完整修正后的Kivy代码

<MyPopup>:
    auto_dismiss: False
    title: "Select a folder"
    filechooser: filechooser
    FloatLayout:
        FileChooserIconView:
            id: filechooser
        Button:
            id:my_button
            text: 'Save'
            size_hint: (0.1, 0.1)
            pos_hint:{'x': 0, 'y': 0}
            on_release: app.dismiss_popup()

<ErrorPopup>:
    title: "Error"
    Button:
        text: "Try Again"
        on_release: app.try_again()

<Main>:
    audio_check: audio_check
    video_check: video_check
    spinner_id: spinner_id
    yt_link: yt_link
    name: name
    folder_button: folder_button
    BoxLayout:
        orientation:'vertical'
        cols: 4
        Label:
            text: "YouTube Downloader"
            halign: 'center'
            bold: True
            font_size:'50sp'
        TextInput:
            id: yt_link
            size_hint: (.5, .2)
            multiline: False
            hint_text: 'Enter the link of the Youtube video you want to download.'
            pos_hint: {"x": 0.25}
        TextInput:
            id: name
            size_hint: (.5, .2)
            multiline: False
            hint_text: 'Enter the name you want the file to have.'
            pos_hint: {"x": 0.25}
        BoxLayout:
            cols:4
            BoxLayout:
                Label:
                    text: "Audio:"
                    halign: 'center'
                    font_size:'20sp'
                CheckBox:
                    id: audio_check
            BoxLayout:
                Label:
                    text: "Video:"
                    halign: 'center'
                    font_size:'20sp'
                CheckBox:
                    id: video_check
            FloatLayout:
                Spinner:
                    id: spinner_id
                    text: "Quality"
                    values: ['144p', '240p', '360p', '480p', '720p', '1080p', '1440p', '2160p']
                    on_text: root.spinner_clicked(spinner_id.text)
                    size_hint: None, None
                    size: 130, 50
                    pos_hint: {'x': .2, 'y':.4}
            FloatLayout:
                Button:
                    id:folder_button
                    text: 'Folder'
                    on_release: app.open_popup()
                    size_hint: None, None
                    size: 130, 50
                    pos_hint: {'x':0.2,'y':.4}
        Button:
            text: "Submit"
            size_hint: (.5, .2)
            pos_hint: {"x": 0.25}
            on_release: root.submit_text()

内容的提问来源于stack exchange,提问作者apps are the best

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 11:18:20