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

如何在两个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'
解决方案

核心问题分析

  1. 调用Questionnaire1App().get_cla会创建全新的Questionnaire1App实例,不是用户操作过的那个,无法获取之前的输入数据。
  2. get_cla是函数对象,没有cla属性,直接访问函数内部变量不符合Python作用域规则。

修改步骤

  1. 在Questionnaire1App的get_cla方法中,将生成的列表保存为实例属性self.cla,方便后续访问:
    def get_cla(self, obj1):
        self.cla = ["", "", ""] # 保存为实例属性
        return self.cla
    
  2. 修改next方法,使用当前实例的stop()停止应用,再将self.cla作为参数传给Questionnaire2App:
    def next(self, obj):
        self.stop() # 停止当前实例,无需新建
        Questionnaire2App(class_list=self.cla).run()
    
  3. 给Questionnaire2App添加初始化方法,接收传入的列表:
    class Questionnaire2App(App):
        def __init__(self, class_list, **kwargs):
            self.class_list = class_list
            super().__init__(**kwargs)
    
  4. 在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 20:14:57