如何将 KivyMD 菜单调用者更改为 ScreenManager 屏幕中的小部件
How to change a KivyMD Menu caller to a Widget in a ScreenManager Screen
所以,我正在开发一个简单的 kivy 应用程序,并且在发布时我有三个按钮 (MDRaisedButton's
) which each open the same KivyMD Menu (MDDropdownMenu
)。
其中两个按钮位于不同的 ScreenManager
屏幕中。
另一个按钮是在GridLayout
里的Screen
外面
ScreenManager
.
当我使用 ScreenManager
内部的按钮打开菜单时,菜单出现在 ScreenManager
外部的按钮上,无论我按哪个按钮.
那么,如果我的 ScreenManager
屏幕上显示的是按钮的位置,我该如何更改来电者或菜单的位置?
我点击 ScreenManager
屏幕内的按钮:
菜单出现在错误的按钮上:
代码:
from kivymd.app import MDApp
from kivymd.uix.menu import MDDropdownMenu
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager
from kivy.uix.screenmanager import Screen
Screens = ["First", "Second"]
KV = '''
Screen:
screen_man:screen_man
button_outside:button_outside
GridLayout:
rows: 2
cols: 1
MDRaisedButton:
id: button_outside
text: "Outside Screen Manager"
pos_hint: {"center_x": .1, "center_y": .9}
on_release: app.threeD_menu.open()
ScreenManager:
id:screen_man
FirstScreen:
SecondScreen:
<FirstScreen>:
name:"First"
screen_man1:screen_man1
MDRaisedButton:
id: screen_man1
text: "Inside Screen Manager1"
pos_hint: {"center_x": 0.5, "center_y": 0.5}
on_release: app.threeD_menu.open()
MDLabel:
text: "Screen Manager1"
font_size: "40dp"
pos_hint: {"center_x": .9, "center_y": 0.9}
<SecondScreen>:
name:"Second"
screen_man2:screen_man2
MDRaisedButton:
id: screen_man2
text: "Inside Screen Manager2"
pos_hint: {"center_x": 0.5, "center_y": .5}
on_release: app.threeD_menu.open()
MDLabel:
text: "Screen Manager2"
font_size: "40dp"
pos_hint: {"center_x": .9, "center_y": 0.9}
'''
class FirstScreen(Screen):
pass
class SecondScreen(Screen):
pass
class WindowManager(ScreenManager):
pass
class ExampleApp(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.title = 'Example'
self.screen = Builder.load_string(KV)
threeD_items = [
{
"text": f"{i}",
"viewclass": "OneLineListItem",
"on_release": lambda x=f"{i}": self.threeD_refresh(x),
} for i in Screens
]
self.threeD_menu = MDDropdownMenu(
caller=self.screen.button_outside,
items=threeD_items,
width_mult=4,
)
def build(self):
sm = ScreenManager()
sm.add_widget(self.screen)
return sm
def threeD_refresh(self, operation):
self.threeD_menu.dismiss()
self.screen.screen_man.current = operation
ExampleApp().run()
有人可以帮忙吗?我已经搜索了 docs 和 Google,但到目前为止一无所获。
查看 MDRaisedButton on_release 事件处理程序代码中的以下行。
on_release: app.threeD_menu.open()
菜单不知道是谁打开的。这里的关键是将 caller 传递给打开菜单的任何函数,因此 MDDropdownMenu 具有调用者的上下文。
使用以下代码定义一个名为 launch_menu 的新函数:
def launch_menu(self, my_caller):
self.threeD_menu.caller=my_caller
self.threeD_menu.open()
然后,更改事件处理程序以调用此函数,而不仅仅是菜单打开函数:
MDRaisedButton:
id: button_outside
text: "Outside Screen Manager"
pos_hint: {"center_x": .1, "center_y": .9}
on_release: app.launch_menu(self)
现在,当您的事件处理程序被调用时,它会传递给调用它的菜单对象,菜单对象可以从那里启动。
完整代码:
from kivymd.app import MDApp
from kivymd.uix.menu import MDDropdownMenu
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager
from kivy.uix.screenmanager import Screen
Screens = ["First", "Second"]
KV = '''
Screen:
screen_man:screen_man
button_outside:button_outside
GridLayout:
rows: 2
cols: 1
MDRaisedButton:
id: button_outside
text: "Outside Screen Manager"
pos_hint: {"center_x": .1, "center_y": .9}
on_release: app.launch_menu(self)
ScreenManager:
id:screen_man
FirstScreen:
SecondScreen:
<FirstScreen>:
name:"First"
id:"first_screen"
screen_man1:screen_man1
MDRaisedButton:
id: screen_man1
text: "Inside Screen Manager1"
pos_hint: {"center_x": 0.5, "center_y": 0.5}
on_release: app.launch_menu(self)
MDLabel:
text: "Screen Manager1"
font_size: "40dp"
pos_hint: {"center_x": .9, "center_y": 0.9}
<SecondScreen>:
name:"Second"
screen_man2:screen_man2
MDRaisedButton:
id: screen_man2
text: "Inside Screen Manager2"
pos_hint: {"center_x": 0.5, "center_y": .5}
on_release: app.launch_menu(self)
MDLabel:
text: "Screen Manager2"
font_size: "40dp"
pos_hint: {"center_x": .9, "center_y": 0.9}
'''
class FirstScreen(Screen):
pass
class SecondScreen(Screen):
pass
class WindowManager(ScreenManager):
pass
class ExampleApp(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.title = 'Example'
self.screen = Builder.load_string(KV)
threeD_items = [
{
"text": f"{i}",
"viewclass": "OneLineListItem",
"on_release": lambda x=f"{i}": self.threeD_refresh(x),
} for i in Screens
]
self.threeD_menu = MDDropdownMenu(
caller=self.screen.button_outside,
items=threeD_items,
width_mult=4,
)
def build(self):
sm = ScreenManager()
sm.add_widget(self.screen)
return sm
def threeD_refresh(self, operation):
self.threeD_menu.dismiss()
self.screen.screen_man.current = operation
def launch_menu(self, my_caller):
self.threeD_menu.caller=my_caller
self.threeD_menu.open()
ExampleApp().run()
所以,我正在开发一个简单的 kivy 应用程序,并且在发布时我有三个按钮 (MDRaisedButton's
) which each open the same KivyMD Menu (MDDropdownMenu
)。
其中两个按钮位于不同的
ScreenManager
屏幕中。另一个按钮是在
GridLayout
里的Screen
外面ScreenManager
.
当我使用 ScreenManager
内部的按钮打开菜单时,菜单出现在 ScreenManager
外部的按钮上,无论我按哪个按钮.
那么,如果我的 ScreenManager
屏幕上显示的是按钮的位置,我该如何更改来电者或菜单的位置?
我点击 ScreenManager
屏幕内的按钮:
菜单出现在错误的按钮上:
代码:
from kivymd.app import MDApp
from kivymd.uix.menu import MDDropdownMenu
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager
from kivy.uix.screenmanager import Screen
Screens = ["First", "Second"]
KV = '''
Screen:
screen_man:screen_man
button_outside:button_outside
GridLayout:
rows: 2
cols: 1
MDRaisedButton:
id: button_outside
text: "Outside Screen Manager"
pos_hint: {"center_x": .1, "center_y": .9}
on_release: app.threeD_menu.open()
ScreenManager:
id:screen_man
FirstScreen:
SecondScreen:
<FirstScreen>:
name:"First"
screen_man1:screen_man1
MDRaisedButton:
id: screen_man1
text: "Inside Screen Manager1"
pos_hint: {"center_x": 0.5, "center_y": 0.5}
on_release: app.threeD_menu.open()
MDLabel:
text: "Screen Manager1"
font_size: "40dp"
pos_hint: {"center_x": .9, "center_y": 0.9}
<SecondScreen>:
name:"Second"
screen_man2:screen_man2
MDRaisedButton:
id: screen_man2
text: "Inside Screen Manager2"
pos_hint: {"center_x": 0.5, "center_y": .5}
on_release: app.threeD_menu.open()
MDLabel:
text: "Screen Manager2"
font_size: "40dp"
pos_hint: {"center_x": .9, "center_y": 0.9}
'''
class FirstScreen(Screen):
pass
class SecondScreen(Screen):
pass
class WindowManager(ScreenManager):
pass
class ExampleApp(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.title = 'Example'
self.screen = Builder.load_string(KV)
threeD_items = [
{
"text": f"{i}",
"viewclass": "OneLineListItem",
"on_release": lambda x=f"{i}": self.threeD_refresh(x),
} for i in Screens
]
self.threeD_menu = MDDropdownMenu(
caller=self.screen.button_outside,
items=threeD_items,
width_mult=4,
)
def build(self):
sm = ScreenManager()
sm.add_widget(self.screen)
return sm
def threeD_refresh(self, operation):
self.threeD_menu.dismiss()
self.screen.screen_man.current = operation
ExampleApp().run()
有人可以帮忙吗?我已经搜索了 docs 和 Google,但到目前为止一无所获。
查看 MDRaisedButton on_release 事件处理程序代码中的以下行。
on_release: app.threeD_menu.open()
菜单不知道是谁打开的。这里的关键是将 caller 传递给打开菜单的任何函数,因此 MDDropdownMenu 具有调用者的上下文。
使用以下代码定义一个名为 launch_menu 的新函数:
def launch_menu(self, my_caller):
self.threeD_menu.caller=my_caller
self.threeD_menu.open()
然后,更改事件处理程序以调用此函数,而不仅仅是菜单打开函数:
MDRaisedButton:
id: button_outside
text: "Outside Screen Manager"
pos_hint: {"center_x": .1, "center_y": .9}
on_release: app.launch_menu(self)
现在,当您的事件处理程序被调用时,它会传递给调用它的菜单对象,菜单对象可以从那里启动。
完整代码:
from kivymd.app import MDApp
from kivymd.uix.menu import MDDropdownMenu
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager
from kivy.uix.screenmanager import Screen
Screens = ["First", "Second"]
KV = '''
Screen:
screen_man:screen_man
button_outside:button_outside
GridLayout:
rows: 2
cols: 1
MDRaisedButton:
id: button_outside
text: "Outside Screen Manager"
pos_hint: {"center_x": .1, "center_y": .9}
on_release: app.launch_menu(self)
ScreenManager:
id:screen_man
FirstScreen:
SecondScreen:
<FirstScreen>:
name:"First"
id:"first_screen"
screen_man1:screen_man1
MDRaisedButton:
id: screen_man1
text: "Inside Screen Manager1"
pos_hint: {"center_x": 0.5, "center_y": 0.5}
on_release: app.launch_menu(self)
MDLabel:
text: "Screen Manager1"
font_size: "40dp"
pos_hint: {"center_x": .9, "center_y": 0.9}
<SecondScreen>:
name:"Second"
screen_man2:screen_man2
MDRaisedButton:
id: screen_man2
text: "Inside Screen Manager2"
pos_hint: {"center_x": 0.5, "center_y": .5}
on_release: app.launch_menu(self)
MDLabel:
text: "Screen Manager2"
font_size: "40dp"
pos_hint: {"center_x": .9, "center_y": 0.9}
'''
class FirstScreen(Screen):
pass
class SecondScreen(Screen):
pass
class WindowManager(ScreenManager):
pass
class ExampleApp(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.title = 'Example'
self.screen = Builder.load_string(KV)
threeD_items = [
{
"text": f"{i}",
"viewclass": "OneLineListItem",
"on_release": lambda x=f"{i}": self.threeD_refresh(x),
} for i in Screens
]
self.threeD_menu = MDDropdownMenu(
caller=self.screen.button_outside,
items=threeD_items,
width_mult=4,
)
def build(self):
sm = ScreenManager()
sm.add_widget(self.screen)
return sm
def threeD_refresh(self, operation):
self.threeD_menu.dismiss()
self.screen.screen_man.current = operation
def launch_menu(self, my_caller):
self.threeD_menu.caller=my_caller
self.threeD_menu.open()
ExampleApp().run()