FloatLayout 和 GridLayout 中的 kivy 下拉菜单不显示
kivy dropdown menu in FloatLayout and GridLayout doesnt show up
大家好,尝试创建一个带有下拉按钮的应用程序,但它似乎不起作用(完整的应用程序具有 GridLayout 和 7 行,示例中的这个 FloatLayout 是其中一行)我已经尝试过使用 GridLayout, BoxLayout 和 FloatLayout 仍然没有出现在应用程序中。知道这里出了什么问题吗?
.py 文件
class WindowManager(ScreenManager, Screen):
TestMe = ObjectProperty(None)
text_lists = ['hi', 'nice one', 'another one']
class TestMe(Screen, FloatLayout):
global text_lists
main_button = ObjectProperty(None)
selected_list = 'SELECTED'
top_layout = ObjectProperty(None)
top_layout = GridLayout(cols=4)
def __init__(self, **kwargs):
super(TestMe, self).__init__(**kwargs)
self.dropdown = DropDown()
self.create_drop_down()
self.create_go_button()
def create_drop_down(self):
for list_name in text_lists:
# When adding widgets, we need to specify the height manually
# (disabling the size_hint_y) so the dropdown can calculate
# the area it needs.
btn = Button(text= list_name, size_hint_y=None, height=88, width=400, background_color=(41/255, 21/255, 228/255, 1))
# for each button, attach a callback that will call the select() method
# on the dropdown. We'll pass the text of the button as the data of the
# selection.
btn.bind(on_release=lambda btn: self.dropdown.select(btn.text),
on_press=lambda btn: self.select_list(btn.text))
# then add the button inside the dropdown
self.dropdown.add_widget(btn)
# create a big main button
self.main_button = Button(text='Choose A List', size_hint=(None, None), height=88, width=400, background_color=(41/255, 21/255, 228/255, 1))
# show the dropdown menu when the main button is released
# note: all the bind() calls pass the instance of the caller (here, the
# mainbutton instance) as the first argument of the callback (here,
# dropdown.open.).
self.main_button.bind(on_release=self.dropdown.open)
# one last thing, listen for the selection in the dropdown list and
# assign the data to the button text.
self.dropdown.bind(on_select=lambda instance, x: setattr(self.main_button, 'text', x))
self.top_layout.add_widget(self.main_button)
def create_go_button(self):
go_btn = Button(text="Go!", size_hint=(None, None), height=88, width=400, background_color=(41/255, 21/255, 228/255, 1))
self.top_layout.add_widget(go_btn)
def select_list(self, selected):
self.selected_list = selected
class MyTest(App):
def build(self):
return kv
if __name__ == '__main__':
kv = Builder.load_file('test_kv.kv')
MyTest().run()
test_kv.kv 文件
WindowManager:
TestMe:
<TestMe>:
name: "testy"
id: testy
top_layout: top_layout
FloatLayout:
Label:
text: 'Test Screen'
font: 'Aharoni'
font_size: 24
pos_hint: {"left": 0.45, "y": 0.45}
GridLayout:
pos_hint: {"top": 0.9}
size_hint: 1, 0.8
rows: 2
spacing: 10
padding: 10
GridLayout:
id: top_layout
cols: 4
Button:
text: "Fun!"
Label:
text: "This is a test"
Button:
text: "Run!"
当我 运行 你的代码(必须添加一个 App
class)时,大主按钮出现,并且按预期工作。但是 Button
和你的 light.png
Image
一起出现在左下角。尝试稍微移动它,使其不与 Image
重叠。像这样:
self.main_button = Button(text='Choose A List', size_hint=(None, None), height=88, width=140,
background_color=(41/255, 21/255, 228/255, 1), pos_hint={'center_x':0.5, 'y':0.4})
我还把 Choose A List
文本加宽了一点。
问题是您在 TestMe
class 的 __init__()
方法中调用了 create_drop_down()
和 create_go_button()
。由于您还在 kv
中定义了 <TestMe>:
规则,因此存在冲突。根据有点不清楚的documentation,kv
规则是在__init__()
是运行之后应用的。这意味着在其 __init__()
中添加到 TestMe
的任何 Widgets
将被 kv
规则中指定的 Widegets
覆盖。可能的解决方案是在 __init__()
方法或 kv
方法中添加 TestMe
的所有子项,或者将 Widgets
的添加移出 [=13] =] 方法。这是您的代码的修改版本,采用后一种方法:
class WindowManager(ScreenManager, Screen):
TestMe = ObjectProperty(None)
text_lists = ['hi', 'nice one', 'another one']
class TestMe(Screen, FloatLayout):
global text_lists
main_button = ObjectProperty(None)
selected_list = 'SELECTED'
top_layout = ObjectProperty(None)
#top_layout = GridLayout(cols=4)
def __init__(self, **kwargs):
super(TestMe, self).__init__(**kwargs)
self.dropdown = DropDown()
Clock.schedule_once(self.create_drop_down)
Clock.schedule_once(self.create_go_button)
# self.create_drop_down()
# self.create_go_button()
def create_drop_down(self, *args):
for list_name in text_lists:
# When adding widgets, we need to specify the height manually
# (disabling the size_hint_y) so the dropdown can calculate
# the area it needs.
btn = Button(text= list_name, size_hint_y=None, height=88, width=400, background_color=(41/255, 21/255, 228/255, 1))
# for each button, attach a callback that will call the select() method
# on the dropdown. We'll pass the text of the button as the data of the
# selection.
btn.bind(on_release=lambda btn: self.dropdown.select(btn.text),
on_press=lambda btn: self.select_list(btn.text))
# then add the button inside the dropdown
self.dropdown.add_widget(btn)
# create a big main button
# self.main_button = Button(text='Choose A List', size_hint=(None, None), height=88, width=400, background_color=(41/255, 21/255, 228/255, 1))
self.main_button = Button(text='Choose A List', background_color=(41/255, 21/255, 228/255, 1))
# show the dropdown menu when the main button is released
# note: all the bind() calls pass the instance of the caller (here, the
# mainbutton instance) as the first argument of the callback (here,
# dropdown.open.).
self.main_button.bind(on_release=self.dropdown.open)
# one last thing, listen for the selection in the dropdown list and
# assign the data to the button text.
self.dropdown.bind(on_select=lambda instance, x: setattr(self.main_button, 'text', x))
self.top_layout.add_widget(self.main_button)
def create_go_button(self, *args):
# go_btn = Button(text="Go!", size_hint=(None, None), height=88, width=400, background_color=(41/255, 21/255, 228/255, 1))
go_btn = Button(text="Go!", background_color=(41/255, 21/255, 228/255, 1))
self.top_layout.add_widget(go_btn)
def select_list(self, selected):
self.selected_list = selected
class MyTest(App):
def build(self):
return kv
我已修改代码以使用 Clock.schedule_once()
调用 create
方法,以便在应用 kv
规则后发生。
我还删除了 size_hint
和 size
参数到 Buttons
创建以允许 GridLayout
调整它们的大小。我还注释掉了一些不必要的代码。
大家好,尝试创建一个带有下拉按钮的应用程序,但它似乎不起作用(完整的应用程序具有 GridLayout 和 7 行,示例中的这个 FloatLayout 是其中一行)我已经尝试过使用 GridLayout, BoxLayout 和 FloatLayout 仍然没有出现在应用程序中。知道这里出了什么问题吗?
.py 文件
class WindowManager(ScreenManager, Screen):
TestMe = ObjectProperty(None)
text_lists = ['hi', 'nice one', 'another one']
class TestMe(Screen, FloatLayout):
global text_lists
main_button = ObjectProperty(None)
selected_list = 'SELECTED'
top_layout = ObjectProperty(None)
top_layout = GridLayout(cols=4)
def __init__(self, **kwargs):
super(TestMe, self).__init__(**kwargs)
self.dropdown = DropDown()
self.create_drop_down()
self.create_go_button()
def create_drop_down(self):
for list_name in text_lists:
# When adding widgets, we need to specify the height manually
# (disabling the size_hint_y) so the dropdown can calculate
# the area it needs.
btn = Button(text= list_name, size_hint_y=None, height=88, width=400, background_color=(41/255, 21/255, 228/255, 1))
# for each button, attach a callback that will call the select() method
# on the dropdown. We'll pass the text of the button as the data of the
# selection.
btn.bind(on_release=lambda btn: self.dropdown.select(btn.text),
on_press=lambda btn: self.select_list(btn.text))
# then add the button inside the dropdown
self.dropdown.add_widget(btn)
# create a big main button
self.main_button = Button(text='Choose A List', size_hint=(None, None), height=88, width=400, background_color=(41/255, 21/255, 228/255, 1))
# show the dropdown menu when the main button is released
# note: all the bind() calls pass the instance of the caller (here, the
# mainbutton instance) as the first argument of the callback (here,
# dropdown.open.).
self.main_button.bind(on_release=self.dropdown.open)
# one last thing, listen for the selection in the dropdown list and
# assign the data to the button text.
self.dropdown.bind(on_select=lambda instance, x: setattr(self.main_button, 'text', x))
self.top_layout.add_widget(self.main_button)
def create_go_button(self):
go_btn = Button(text="Go!", size_hint=(None, None), height=88, width=400, background_color=(41/255, 21/255, 228/255, 1))
self.top_layout.add_widget(go_btn)
def select_list(self, selected):
self.selected_list = selected
class MyTest(App):
def build(self):
return kv
if __name__ == '__main__':
kv = Builder.load_file('test_kv.kv')
MyTest().run()
test_kv.kv 文件
WindowManager:
TestMe:
<TestMe>:
name: "testy"
id: testy
top_layout: top_layout
FloatLayout:
Label:
text: 'Test Screen'
font: 'Aharoni'
font_size: 24
pos_hint: {"left": 0.45, "y": 0.45}
GridLayout:
pos_hint: {"top": 0.9}
size_hint: 1, 0.8
rows: 2
spacing: 10
padding: 10
GridLayout:
id: top_layout
cols: 4
Button:
text: "Fun!"
Label:
text: "This is a test"
Button:
text: "Run!"
当我 运行 你的代码(必须添加一个 App
class)时,大主按钮出现,并且按预期工作。但是 Button
和你的 light.png
Image
一起出现在左下角。尝试稍微移动它,使其不与 Image
重叠。像这样:
self.main_button = Button(text='Choose A List', size_hint=(None, None), height=88, width=140,
background_color=(41/255, 21/255, 228/255, 1), pos_hint={'center_x':0.5, 'y':0.4})
我还把 Choose A List
文本加宽了一点。
问题是您在 TestMe
class 的 __init__()
方法中调用了 create_drop_down()
和 create_go_button()
。由于您还在 kv
中定义了 <TestMe>:
规则,因此存在冲突。根据有点不清楚的documentation,kv
规则是在__init__()
是运行之后应用的。这意味着在其 __init__()
中添加到 TestMe
的任何 Widgets
将被 kv
规则中指定的 Widegets
覆盖。可能的解决方案是在 __init__()
方法或 kv
方法中添加 TestMe
的所有子项,或者将 Widgets
的添加移出 [=13] =] 方法。这是您的代码的修改版本,采用后一种方法:
class WindowManager(ScreenManager, Screen):
TestMe = ObjectProperty(None)
text_lists = ['hi', 'nice one', 'another one']
class TestMe(Screen, FloatLayout):
global text_lists
main_button = ObjectProperty(None)
selected_list = 'SELECTED'
top_layout = ObjectProperty(None)
#top_layout = GridLayout(cols=4)
def __init__(self, **kwargs):
super(TestMe, self).__init__(**kwargs)
self.dropdown = DropDown()
Clock.schedule_once(self.create_drop_down)
Clock.schedule_once(self.create_go_button)
# self.create_drop_down()
# self.create_go_button()
def create_drop_down(self, *args):
for list_name in text_lists:
# When adding widgets, we need to specify the height manually
# (disabling the size_hint_y) so the dropdown can calculate
# the area it needs.
btn = Button(text= list_name, size_hint_y=None, height=88, width=400, background_color=(41/255, 21/255, 228/255, 1))
# for each button, attach a callback that will call the select() method
# on the dropdown. We'll pass the text of the button as the data of the
# selection.
btn.bind(on_release=lambda btn: self.dropdown.select(btn.text),
on_press=lambda btn: self.select_list(btn.text))
# then add the button inside the dropdown
self.dropdown.add_widget(btn)
# create a big main button
# self.main_button = Button(text='Choose A List', size_hint=(None, None), height=88, width=400, background_color=(41/255, 21/255, 228/255, 1))
self.main_button = Button(text='Choose A List', background_color=(41/255, 21/255, 228/255, 1))
# show the dropdown menu when the main button is released
# note: all the bind() calls pass the instance of the caller (here, the
# mainbutton instance) as the first argument of the callback (here,
# dropdown.open.).
self.main_button.bind(on_release=self.dropdown.open)
# one last thing, listen for the selection in the dropdown list and
# assign the data to the button text.
self.dropdown.bind(on_select=lambda instance, x: setattr(self.main_button, 'text', x))
self.top_layout.add_widget(self.main_button)
def create_go_button(self, *args):
# go_btn = Button(text="Go!", size_hint=(None, None), height=88, width=400, background_color=(41/255, 21/255, 228/255, 1))
go_btn = Button(text="Go!", background_color=(41/255, 21/255, 228/255, 1))
self.top_layout.add_widget(go_btn)
def select_list(self, selected):
self.selected_list = selected
class MyTest(App):
def build(self):
return kv
我已修改代码以使用 Clock.schedule_once()
调用 create
方法,以便在应用 kv
规则后发生。
我还删除了 size_hint
和 size
参数到 Buttons
创建以允许 GridLayout
调整它们的大小。我还注释掉了一些不必要的代码。