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
相关产品推荐
相关产品推荐

