如何在两个Kivy GUI类之间传递函数生成的列表?
问题描述
有Python基础,刚接触Kivy框架,开发问卷应用时遇到数据传递问题:想把Questionnaire1App类中get_cla函数生成的列表,在Questionnaire2App类中使用。尝试通过Questionnaire1App().get_cla调用函数并获取内部的cla列表,触发AttributeError,提示'function' object has no attribute 'cla'。
原代码如下:
from kivy.uix.spinner import Spinner from kivy.app import App from kivy.uix.gridlayout import GridLayout from kivy.uix.label import Label from kivy.uix.textinput import TextInput from kivy.uix.button import Button from kivy.uix.scrollview import ScrollView from kivy.core.window import Window class Questionnaire1App(App): def build(self): #window layout self.layout = GridLayout(cols = 1, spacing = 10, size_hint_y = None, padding = (200,50)) self.layout.bind(minimum_height = self.layout.setter("height")) Window.clearcolor = (1,1,1,1) #title self.ttl = Label(text = "title", height = 50, font_size = 24, color = "black") self.layout.add_widget(self.ttl) #question + textinput self.teach_ask = Label(text = "question?", size_hint_y = None, height = 30, color = "black") self.layout.add_widget(self.teach_ask) self.teach_in = TextInput(size_hint_y = None, height = 30) self.layout.add_widget(self.teach_in) #question + spinner self.area_ask = Label(text = "question?", size_hint_y = None, height = 30, color = "black") self.layout.add_widget(self.area_ask) self.area = Spinner(text = "Select item", values = ("1", "2", "3"), size_hint_y = None, height = 30) self.layout.add_widget(self.area) #question + spinner self.ncea_ask = Label(text = "question?", size_hint_y = None, height = 30, color = "black") self.layout.add_widget(self.ncea_ask) self.ncea = Spinner(text = "Select item", values = ("1", "2"), size_hint_y = None, height = 30) self.layout.add_widget(self.ncea) #question + spinner self.usas_ask = Label(text = "question", size_hint_y = None, height = 30, color = "black") self.layout.add_widget(self.usas_ask) self.usas = Spinner(text = "Select item", values = ("1", "2"), size_hint_y = None, height = 30) self.layout.add_widget(self.usas) #next button self.click = Button(text = "Next", size_hint_y = None, height = 30, on_release = self.next, on_press = self.get_cla) #trying to somehow run the get_cla function before next_function self.layout.add_widget(self.click) #scrolling feature self.root = ScrollView(size_hint = (1, None), size = (Window.width, Window.height)) self.root.add_widget(self.layout) return self.root def next(self, obj): Questionnaire1App().stop() Window.close() Questionnaire2App().run() def get_cla(self, obj1): cla = ["", "", ""] #list of strings, can be up to 21 items return cla class Questionnaire2App(App): def build(self): #window layout self.layout = GridLayout(cols = 1, spacing = 10, size_hint_y = None, padding = (200,50)) self.layout.bind(minimum_height = self.layout.setter("height")) Window.clearcolor = (1,1,1,1) #question + spinner self.class_ask = Label(text = "question?", size_hint_y = None, height = 30, color = "black") self.layout.add_widget(self.class_ask) clas = Questionnaire1App().get_cla #trying to somehow call the list cla from get_cla function in Questionnaire1App but wouldn't work c = clas.cla #give error below self.cla = Spinner(text = "Select item", values = (c[0], c[1], c[2]), size_hint_y = None, height = 30) self.layout.add_widget(self.cla) #scrolling feature self.root = ScrollView(size_hint = (1, None), size = (Window.width, Window.height)) self.root.add_widget(self.layout) return self.root if __name__ == '__main__': Questionnaire1App().run()
报错信息:
Exception has occurred: AttributeError 'function' object has no attribute 'cla' File "C:\...\try.py", line 169, in build c = clas.cla File "C:\...\try.py", line 138, in next Questionnaire2App().run() File "C:\...\try.py", line 183, in <module> Questionnaire1App().run() AttributeError: 'function' object has no attribute 'cla'
解决方案
核心问题分析
- 调用
Questionnaire1App().get_cla会创建全新的Questionnaire1App实例,不是用户操作过的那个,无法获取之前的输入数据。 get_cla是函数对象,没有cla属性,直接访问函数内部变量不符合Python作用域规则。
修改步骤
- 在
Questionnaire1App的get_cla方法中,将生成的列表保存为实例属性self.cla,方便后续访问:def get_cla(self, obj1): self.cla = ["", "", ""] # 保存为实例属性 return self.cla - 修改
next方法,使用当前实例的stop()停止应用,再将self.cla作为参数传给Questionnaire2App:def next(self, obj): self.stop() # 停止当前实例,无需新建 Questionnaire2App(class_list=self.cla).run() - 给
Questionnaire2App添加初始化方法,接收传入的列表:class Questionnaire2App(App): def __init__(self, class_list, **kwargs): self.class_list = class_list super().__init__(**kwargs) - 在
Questionnaire2App的build方法中,直接使用self.class_list渲染Spinner:def build(self): # ... 其他代码不变 ... self.cla = Spinner(text = "Select item", values = tuple(self.class_list), # 转成tuple符合Spinner的values要求 size_hint_y = None, height = 30) # ... 其他代码不变 ...
修改后的完整代码
from kivy.uix.spinner import Spinner from kivy.app import App from kivy.uix.gridlayout import GridLayout from kivy.uix.label import Label from kivy.uix.textinput import TextInput from kivy.uix.button import Button from kivy.uix.scrollview import ScrollView from kivy.core.window import Window class Questionnaire1App(App): def build(self): #window layout self.layout = GridLayout(cols = 1, spacing = 10, size_hint_y = None, padding = (200,50)) self.layout.bind(minimum_height = self.layout.setter("height")) Window.clearcolor = (1,1,1,1) #title self.ttl = Label(text = "title", height = 50, font_size = 24, color = "black") self.layout.add_widget(self.ttl) #question + textinput self.teach_ask = Label(text = "question?", size_hint_y = None, height = 30, color = "black") self.layout.add_widget(self.teach_ask) self.teach_in = TextInput(size_hint_y = None, height = 30) self.layout.add_widget(self.teach_in) #question + spinner self.area_ask = Label(text = "question?", size_hint_y = None, height = 30, color = "black") self.layout.add_widget(self.area_ask) self.area = Spinner(text = "Select item", values = ("1", "2", "3"), size_hint_y = None, height = 30) self.layout.add_widget(self.area) #question + spinner self.ncea_ask = Label(text = "question?", size_hint_y = None, height = 30, color = "black") self.layout.add_widget(self.ncea_ask) self.ncea = Spinner(text = "Select item", values = ("1", "2"), size_hint_y = None, height = 30) self.layout.add_widget(self.ncea) #question + spinner self.usas_ask = Label(text = "question", size_hint_y = None, height = 30, color = "black") self.layout.add_widget(self.usas_ask) self.usas = Spinner(text = "Select item", values = ("1", "2"), size_hint_y = None, height = 30) self.layout.add_widget(self.usas) #next button self.click = Button(text = "Next", size_hint_y = None, height = 30, on_release = self.next, on_press = self.get_cla) self.layout.add_widget(self.click) #scrolling feature self.root = ScrollView(size_hint = (1, None), size = (Window.width, Window.height)) self.root.add_widget(self.layout) return self.root def next(self, obj): self.stop() Questionnaire2App(class_list=self.cla).run() def get_cla(self, obj1): # 可结合用户输入生成真实列表,比如self.teach_in.text、self.area.text等 self.cla = ["Option1", "Option2", "Option3"] # 示例数据 return self.cla class Questionnaire2App(App): def __init__(self, class_list, **kwargs): self.class_list = class_list super().__init__(**kwargs) def build(self): #window layout self.layout = GridLayout(cols = 1, spacing = 10, size_hint_y = None, padding = (200,50)) self.layout.bind(minimum_height = self.layout.setter("height")) Window.clearcolor = (1,1,1,1) #question + spinner self.class_ask = Label(text = "question?", size_hint_y = None, height = 30, color = "black") self.layout.add_widget(self.class_ask) self.cla = Spinner(text = "Select item", values = tuple(self.class_list), size_hint_y = None, height = 30) self.layout.add_widget(self.cla) #scrolling feature self.root = ScrollView(size_hint = (1, None), size = (Window.width, Window.height)) self.root.add_widget(self.layout) return self.root if __name__ == '__main__': Questionnaire1App().run()
额外提示
- 实际开发中,
get_cla方法可结合用户在Questionnaire1App中的输入(如self.teach_in.text、self.area.text)生成真实列表。 - 无需调用
Window.close(),self.stop()已能正确关闭当前应用窗口。
内容的提问来源于stack exchange,提问作者lt59
相关产品推荐
相关产品推荐

