Kivy报错:'DialogContent'对象无'manager'属性的解决求助
问题描述
点击对话框的“Cancel”或“Save”按钮时触发AttributeError,提示'DialogContent'对象没有'manager'属性。原本想通过root.manager.get_screen('RoutineCreation')调用对应屏幕的close_dialog和add_task方法,结果出错。
报错堆栈
File "kivy_event.pyx", line 727, in kivy._event.EventDispatcher.dispatch File "kivy_event.pyx", line 1307, in kivy._event.EventObservers.dispatch File "kivy_event.pyx", line 1191, in kivy._event.EventObservers._dispatch File "C:\Users\alexa\PycharmProjects\TheFinalApp\venv\lib\site-packages\kivy\lang\builder.py", line 55, in custom_callback exec(__kvlang__.co_value, idmap) File "C:\Users\alexa\PycharmProjects\TheFinalApp\ardour.kv", line 91, in <module> on_release: root.manager.get_screen('RoutineCreation').add_task(task_text, date_text.text), root.manager.get_screen('RoutineCreation').close_dialog() File "kivy\weakproxy.pyx", line 32, in kivy.weakproxy.WeakProxy.__getattr__ AttributeError: 'DialogContent' object has no attribute 'manager'
相关代码
Python代码
from kivymd.app import MDApp from kivymd.uix.screen import Screen from kivymd.uix.dialog import MDDialog from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.textfield import MDTextField from kivymd.uix.button import MDRaisedButton, MDFlatButton from kivymd.uix.iconbutton import MDIconButton from kivymd.uix.picker import MDDatePicker from datetime import datetime class Ardour(MDApp): pass class RoutineCreation(Screen): routine_dialog = None def show_routine_dialog(self): if not self.routine_dialog: self.routine_list_dialog = MDDialog( title="Routine Creation", type="custom", content_cls=DialogContent(), ) self.routine_list_dialog.open() def close_dialog(self, *args): self.routine_list_dialog.dismiss() def add_task(self, task, task_date): print(task.text, task_date) task.text = '' pass class DialogContent(MDBoxLayout): def __init__(self, **kwargs): super().__init__(**kwargs) self.ids.date_text.text = str(datetime.now().strftime('%A %d %B %Y')) def show_date_picker(self): date_dialog = MDDatePicker() date_dialog.bind(on_save = self.on_save) date_dialog.open() def on_save(self, instance, value, date_range): date = value.strftime('%A %d %B %Y') self.ids.date_text.text = str(date) pass
KV文件代码
<RoutineCreation>: RectTwo: OrangeBar: OrangeBarTwo: Image: source: 'image/routinelabel.png' size: '300dp', '100dp' pos_hint: {'center_x': .5, 'center_y': .88} MDList: id: the_container Button: size_hint: None, None size: '300dp', '100dp' pos_hint: {'center_x': .5, 'center_y': .5} on_release: root.manager.get_screen('RoutineCreation').show_routine_dialog() background_color: 0, 0, 0, 0 Image: source: 'image/addplan.png' center_x: self.parent.center_x center_y: self.parent.center_y size: self.parent.size Button: size_hint: None, None size: '200dp', '50dp' pos_hint: {'center_x': .275, 'center_y': .125} background_color: 0, 0, 0, 0 on_release: app.root.current = 'MenuScreen' Image: source: 'image/finish.png' center_x: self.parent.center_x center_y: self.parent.center_y size: self.parent.size Button: size_hint: None, None size: '200dp', '50dp' pos_hint: {'center_x': .725, 'center_y': .125} background_color: 0, 0, 0, 0 on_release: app.root.current = 'ChoiceScreen' Image: source: 'image/cancel.png' center_x: self.parent.center_x center_y: self.parent.center_y size: self.parent.size <DialogContent>: orientation: 'vertical' spacing: '10dp' size_hint: 1, None height: '130dp' GridLayout: rows: 1 MDTextField: id: task_text hint_text: 'Add Routine' pos_hint: {'center_y': .4} max_text_length: 40 on_text_validate: root.get_screen('RoutineCreation').add_task(task_text, date_text.text) MDIconButton: icon: 'calendar' on_release: root.show_date_picker() padding: '10dp' MDLabel: spacing: '10dp' id: date_text BoxLayout: orientation: 'vertical' MDRaisedButton: text: 'Save' on_release: root.manager.get_screen('RoutineCreation').add_task(task_text, date_text.text), root.manager.get_screen('RoutineCreation').close_dialog() MDFlatButton: text: 'Cancel' on_release: root.manager.get_screen('RoutineCreation').close_dialog()
解决方案
错误核心原因:DialogContent是MDBoxLayout子类,不属于ScreenManager管理的屏幕组件,因此没有manager属性。以下是三种可行解决方式:
方式1:传递父屏幕引用给DialogContent
- 修改
RoutineCreation的show_routine_dialog方法,将当前屏幕实例传入DialogContent:
def show_routine_dialog(self): if not self.routine_dialog: self.routine_list_dialog = MDDialog( title="Routine Creation", type="custom", content_cls=DialogContent(parent_screen=self), ) self.routine_list_dialog.open()
- 更新
DialogContent的初始化方法,保存父屏幕引用:
class DialogContent(MDBoxLayout): def __init__(self, parent_screen=None, **kwargs): super().__init__(**kwargs) self.parent_screen = parent_screen self.ids.date_text.text = str(datetime.now().strftime('%A %d %B %Y'))
- 修改KV文件中按钮的事件绑定:
# Save按钮 on_release: root.parent_screen.add_task(task_text, date_text.text), root.parent_screen.close_dialog() # Cancel按钮 on_release: root.parent_screen.close_dialog() # 文本框回车事件 on_text_validate: root.parent_screen.add_task(task_text, date_text.text)
方式2:通过App实例直接获取ScreenManager
直接在KV文件中使用app.root(需确保App的根组件是ScreenManager)调用目标屏幕方法,无需修改Python代码:
# Save按钮 on_release: app.root.get_screen('RoutineCreation').add_task(task_text, date_text.text), app.root.get_screen('RoutineCreation').close_dialog() # Cancel按钮 on_release: app.root.get_screen('RoutineCreation').close_dialog() # 文本框回车事件 on_text_validate: app.root.get_screen('RoutineCreation').add_task(task_text, date_text.text)
方式3:将按钮逻辑绑定到对话框创建时
在RoutineCreation中创建对话框时直接定义按钮,避免跨组件引用:
- 修改
show_routine_dialog方法:
def show_routine_dialog(self): content = DialogContent() if not self.routine_dialog: self.routine_list_dialog = MDDialog( title="Routine Creation", type="custom", content_cls=content, buttons=[ MDFlatButton( text="CANCEL", on_release=lambda x: self.close_dialog() ), MDRaisedButton( text="SAVE", on_release=lambda x: (self.add_task(content.ids.task_text, content.ids.date_text.text), self.close_dialog()) ), ], ) self.routine_list_dialog.open()
- 删除KV文件中
DialogContent内部的按钮布局部分。
内容的提问来源于stack exchange,提问作者Alexander Alico
相关产品推荐
相关产品推荐

