Kivy DropDown不显示及类方法外调用open报错问题咨询
两个Kivy DropDown问题的原因与修复方案
问题1:点击主按钮后下拉列表未显示
你的代码里下拉列表其实已经被触发了,但Dropdown内部的按钮没有设置合适的尺寸,导致你看不到它们。默认情况下,Kivy的Buttonsize_hint_y是1,这意味着每个按钮会占满Dropdown的整个高度——两个按钮叠加后,第二个会被完全挤出可视区域,第一个也可能因为Dropdown默认高度不够显示不全。
另外,全局定义Dropdown和按钮不是最佳实践,但这不是直接导致不显示的核心原因。
修复方法很简单,给Dropdown里的按钮设置固定高度,同时把Dropdown的创建逻辑放到类内部避免全局变量:
import kivy from kivy.app import App from kivy.uix.dropdown import DropDown from kivy.uix.button import Button from kivy.uix.floatlayout import FloatLayout class MainButton(Button): def __init__(self, **kwargs): super().__init__(**kwargs) # 在类内部创建Dropdown,避免全局变量带来的生命周期问题 self.dropdown = DropDown() # 给下拉按钮设置固定高度,确保能全部显示 btn1 = Button(text="attack", size_hint_y=None, height=44) btn2 = Button(text="item", size_hint_y=None, height=44) self.dropdown.add_widget(btn1) self.dropdown.add_widget(btn2) def on_release(self): super().on_release() print("something") self.dropdown.open(self) class Layout(FloatLayout): pass class theApp(App): def build(self): layout = Layout() btn = MainButton(text="Hello") btn.pos_hint = {'x': 0.5, 'y': 0.5} btn.size_hint = (0.25, 0.25) layout.add_widget(btn) return layout app = theApp() app.run()
调整后每个按钮都有固定高度,Dropdown会自动适配总高度,点击主按钮就能看到完整的下拉列表了。
问题2:在build方法中调用DropDown.open()报错Cannot open a dropdown list on a hidden widget
这个错误的核心原因是:在build方法执行时,你的按钮还没有被渲染到窗口中,处于“隐藏”状态。Kivy要求调用Dropdown.open()时,目标Widget必须已经完成布局并显示在屏幕上。
当你在build里刚把btn添加到layout,此时layout还没有被返回给应用,Widget树还没完成初始化,btn还不是“可见”的,自然无法打开下拉列表。
修复方法是用Clock.schedule_once延迟执行dropdown.open(),等到Widget渲染完成后再调用:
import kivy from kivy.app import App from kivy.uix.dropdown import DropDown from kivy.uix.button import Button from kivy.uix.floatlayout import FloatLayout from kivy.clock import Clock class theApp(App): def build(self): layout = FloatLayout() self.btn = Button(text="Hello") self.btn.pos_hint = {'x': 0.5, 'y': 0.5} self.btn.size_hint = (0.25, 0.25) layout.add_widget(self.btn) self.dropdown = DropDown() btn1 = Button(text="attack", size_hint_y=None, height=44) btn2 = Button(text="item", size_hint_y=None, height=44) self.dropdown.add_widget(btn1) self.dropdown.add_widget(btn2) # 延迟一帧执行,确保Widget已经完成渲染 Clock.schedule_once(self.open_dropdown, 0) return layout def open_dropdown(self, dt): self.dropdown.open(self.btn) app = theApp() app.run()
Clock.schedule_once(func, 0)会让open_dropdown方法在当前帧渲染完成后立即执行,此时btn已经处于可见状态,就不会再报错了。
内容的提问来源于stack exchange,提问作者Arief
相关产品推荐
相关产品推荐

