所以我有一个工具栏,在单个屏幕上运行良好,但我需要两个屏幕。一个主屏幕和一个设置屏幕。我希望使用ScreenManager应该很容易完成。
当我运行此代码时,出现以下错误: 属性错误:"超级"对象没有属性">getattr" 我做错了什么?
from kivymd.app import MDApp
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.uix.menu import MDDropdownMenu
from kivy.metrics import dp
kv = """
ScreenManager:
MainScreen:
SetupScreen:
<MainScreen>:
name: 'main'
MDToolbar:
id: tool1
title:'My Demo App'
pos_hint:{'top':1}
right_action_items : [["dots-vertical", lambda x: app.menu.open()]]
<SetupScreen>:
name: 'setup'
"""
class MainScreen(Screen):
pass
class SetupScreen(Screen):
pass
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MainScreen(name='main'))
sm.add_widget(SetupScreen(name='setup'))
class DemoApp(MDApp):
def build(self):
screen = Builder.load_file('test.kv')
menu_items = [
{
"text": f"Option {opt}",
"viewclass": "OneLineListItem",
"height": dp(40),
"on_release": lambda x=f"Option {opt}": self.menu_callback(x),
} for opt in range(4)
]
menu = MDDropdownMenu(
caller=sm.ids.tool1,
items=menu_items,
width_mult=3
)
return screen
def menu_callback(self, text_item):
print(text_item)
DemoApp().run()
我在许多帖子中不断看到同样的错误。当您的build()
方法返回来自Builder.load_file()
或Builder.load_string()
的结果时,您的根小部件(以及整个GUI)将在kv
中定义。所以台词:
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MainScreen(name='main'))
sm.add_widget(SetupScreen(name='setup'))
正在创建 GUI 的另一个实例,但未使用该实例,并且对该sm
的任何引用都不会影响 GUI 中实际存在的ScreenManager
(通过kv
构建的实例)。因此,您可以从完全消除这些行开始。
然后,要解决实际问题,您需要将MDDropdownMenu
的结构更改为以下内容:
self.menu = MDDropdownMenu(
# caller=sm.ids.tool1,
caller=screen.get_screen('main').ids.tool1,
items=menu_items,
width_mult=3
)
使用self.menu
而不仅仅是menu
保存对menu
的引用。否则,将创建menu
,然后将其丢弃。由于sm
不是 GUI 的一部分,因此必须使用对实际 GUI 的引用。该行:
caller=screen.get_screen('main').ids.tool1,
使用Builder
返回的ScreenMananger
(screen
)。然后使用get_screen()
,它得到main
Screen
(因为那是包含tool1
id
的那个)。最后使用该id
来获取对MDToolbar
的引用。