使用 Kivy 切换屏幕:AttributeError: 'NoneType' object has no attribute 'transition'
Posted
技术标签:
【中文标题】使用 Kivy 切换屏幕:AttributeError: \'NoneType\' object has no attribute \'transition\'【英文标题】:Switching screens using Kivy: AttributeError: 'NoneType' object has no attribute 'transition'使用 Kivy 切换屏幕:AttributeError: 'NoneType' object has no attribute 'transition' 【发布时间】:2020-07-27 09:20:55 【问题描述】:我在尝试使用 python 中的 kivy 库从另一个类中调用定义在一个类中的“屏幕切换”函数时遇到了 AttributionError
。
我的代码结构如下:
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.app import App
def init_grid(width, height, mines):
global grid_field
global flagged
# Initiate the gird field with empty grids
grid_field = [[ClassA() for i in range(width)] for j in range(height)]
flagged = 0
...
class Main(App):
def build(self):
sm = ScreenManager()
current = Current(name="current")
screenA = ScreenA(name="screenA")
screenB = ScreenB(name="screenB")
...
...
sm.add_widget(current)
sm.add_widget(screenA)
sm.add_widget(screenB)
...
...
sm.current = "current"
return sm
...
class ClassA():
# a class my code is at when the error arises,
# which is not the starting "current" screen class
# but a different class that serves a certain purpose to my program
def __init__(self, **kwargs):
...
...
self.button = Button()
self.button.bind(on_touch_down=self.method)
def method(self, instance, touch):
if (a condition):
ScreenA().change_to_B()
...
...
class ScreenA(Screen):
def __init__(self, **kwargs):
Screen.__init__(self, **kwargs)
...
...
init_grid(10, 10, 10)
def change_to_B(self):
self.manager.transition.direction = "left"
self.manager.current = "screenB"
...
class ScreenB(Screen):
def __init__(self, **kwargs):
Screen.__init__(self, **kwargs)
...
...
if __name__ == '__main__':
Main().run()
错误信息是:
in change_to_B
self.manager.transition.direction = "left"
AttributeError: 'NoneType' object has no attribute 'transition'
在上面的代码中,我在ScreenA
类中定义了屏幕切换函数change_to_B
,并在ClassA
类中调用了这个函数。我在我创建的ScreenA
和ScreenB
两个类中都继承了Screen
父类。但奇怪的是,错误消息似乎表明对象screenA
是NoneType
对象,这不应该是这种情况,因为我在通过继承Screen
父级创建类时声明它是屏幕对象类。
谁能指出我错过了什么错误?提前谢谢!!!
编辑:
我想我需要弄清楚我的代码。所以我基本上是在尝试写扫雷游戏,ClassA
是扫雷游戏板组成的网格,它有一个Button
属性来实现点击功能method
(如上代码所示) .在点击函数method
中,我试图调用类ScreenA
中定义的屏幕切换函数change_to_B()
,这是在ScreenManager的build方法中声明的屏幕对象(我认为)。
代码流程为:Current(name="current")(与本题无关) --> ScreenA(name="screenA"),其中ClassA()
是在全局列表变量中创建的函数 init_grid()
--> ClassA(),点击 UI 调用绑定到 ClassA()
对象的 Button
属性的函数。
ClassA
对象在函数init_grid
中创建,其中创建了一个全局变量grid_field
以将ClassA
对象存储在一个二维列表中。
【问题讨论】:
【参考方案1】:常见错误 - 每个屏幕使用多个对象,因此您将一个对象添加到 ScreenManager
并且该对象具有属性 manager
。但是然后你在这里创建另一个ScreenA
类的对象:
def __init__(self, **kwargs):
...
...
ScreenA().change_to_B()
屏幕管理器对该对象一无所知。所以你应该记住的是你将objects
添加到屏幕管理器,而不是classes
。
您没有提供整个代码,所以我不知道您在哪里定义 ClassA
类的对象,但您应该从 build
方法传递对象以使其工作。像这样的:
class ScreenA(Screen):
def __init__(self, **kwargs):
Screen.__init__(self, **kwargs)
...
...
# here we pass the object of the ScreenA class (which is self) to init grid to be able to pass it to ClassA
init_grid(10, 10, 10, self)
# add object to arguments
def init_grid(width, height, mines, screenA):
global grid_field
global flagged
# pass the object to ClassA
grid_field = [[ClassA(screenA) for i in range(width)] for j in range(height)]
class classA():
# don't forget to add object to arguments
def __init__(self, screenA, **kwargs):
...
...
self.screenA = screenA
def method(self, instance, touch):
if (a condition):
self.screenA.change_to_B()
或者使用全局变量:
current = Current(name="current")
screenA = ScreenA(name="screenA")
screenB = ScreenB(name="screenB")
class Main(App):
def build(self):
sm = ScreenManager()
global current
global screenA
global screenB
...
...
sm.add_widget(current)
sm.add_widget(screenA)
sm.add_widget(screenB)
...
...
sm.current = "current"
return sm
class ClassA():
def method(self, instance, touch):
global screenA
if (a condition):
screenA.change_to_B()
【讨论】:
您好,谢谢您的回答。但是我可以仔细检查一下是class classA()
还是class ClassA()
?也很抱歉我上面的代码模棱两可,但调用屏幕切换函数的行在单击时绑定到ClassA
的Button
属性的另一个方法下,而不是__init__()
。我尝试在 ScreenManager
的 build()
函数中添加 classA 对象,但它给了我 NameError "screenA is not defined"...
@DanielQiao 告诉我你在哪里创建ClassA
的对象,这样我就可以编辑我的答案了
您好,很抱歉给您带来麻烦,但我已经包含了创建 ClassA()
对象的函数以及调用该函数的位置(在 ScreenA
中),以及我的代码的工作流程。跨度>
@DanielQiao 我已经编辑了我的答案,检查那里的代码。因此,我们将 ScreenA 类的对象从该类传递给 init_grid
方法,然后从那里我们将其传递给 ClassA。有点奇怪,但在你的情况下,它会是这样的。或者您可以使用其他方式并使用全局变量。我认为这会更简单。
甜蜜!它成功地解决了我的问题,并且全局变量方法更加直接和干净!非常感谢!!!!!!以上是关于使用 Kivy 切换屏幕:AttributeError: 'NoneType' object has no attribute 'transition'的主要内容,如果未能解决你的问题,请参考以下文章