如何在Kivy中隐藏ActionButton?
我正在尝试根据当前屏幕的情况来修改一个操作按钮的可见性(使用屏幕管理器)。我找不到一个简单的可见性属性或者类似的东西来切换可见性(无论是对于操作按钮还是一般的小部件)。
2013年的一篇帖子建议改变按钮的纹理,但我不想依赖这种方法来完成这么简单的任务,况且我应用的背景会是变化的。
另一篇帖子建议根据需要移除小部件再重新添加。尽管这样做有点复杂,我还是对我的情况(操作栏和操作按钮)进行了修改,所以我清除了操作视图中的小部件,然后尝试添加操作按钮。我尝试存储一个弱引用和self成员,但都出现了以下错误:
WidgetException: Cannot add <kivy.uix.actionbar.ActionButton object at 0x7fcd3fe22ce8>, it already has a parent <kivy.uix.actionbar.ActionView object at 0x7fcd3fe22870>
任何建议都非常感谢。我正在使用开发版本,但在1.8版本中也没有成功。
编辑 我尝试了以下代码:
<AppActionBar>:
ActionView:
id: av
ActionButton:
id: btn_next
text: 'Next screen'
icon: 'data/icons/next_dark.png'
important: True
on_release: app.go_next()
这个函数是在场景加载后运行的:
def _initialize(self):
self.next = self.ids.btn_next.__self__ # same result if I don't use .__self__
这段代码引发了上面提到的异常:
self.ids.av.clear_widgets()
self.ids.av.add_widget(self.next)
这是完整的异常追踪信息:
self._mainloop()
File "/usr/local/lib/python2.7/dist-packages/kivy/core/window/window_pygame.py", line 266, in _mainloop
EventLoop.idle()
File "/usr/local/lib/python2.7/dist-packages/kivy/base.py", line 330, in idle
Clock.tick_draw()
File "/usr/local/lib/python2.7/dist-packages/kivy/clock.py", line 429, in tick_draw
self._process_events_before_frame()
File "/usr/local/lib/python2.7/dist-packages/kivy/clock.py", line 562, in _process_events_before_frame
if event.tick(self._last_tick) is False:
File "/usr/local/lib/python2.7/dist-packages/kivy/clock.py", line 309, in tick
ret = callback(self._dt)
File "/usr/local/lib/python2.7/dist-packages/kivy/uix/boxlayout.py", line 174, in do_layout
c.width = w
File "properties.pyx", line 345, in kivy.properties.Property.__set__ (kivy/properties.c:3589)
File "properties.pyx", line 377, in kivy.properties.Property.set (kivy/properties.c:4064)
File "properties.pyx", line 431, in kivy.properties.Property.dispatch (kivy/properties.c:4657)
File "/usr/local/lib/python2.7/dist-packages/kivy/uix/actionbar.py", line 552, in on_width
self._layout_all()
File "/usr/local/lib/python2.7/dist-packages/kivy/uix/actionbar.py", line 441, in _layout_all
super_add(child)
File "/usr/local/lib/python2.7/dist-packages/kivy/uix/boxlayout.py", line 212, in add_widget
return super(BoxLayout, self).add_widget(widget, index)
File "/usr/local/lib/python2.7/dist-packages/kivy/uix/layout.py", line 78, in add_widget
return super(Layout, self).add_widget(widget, index)
File "/usr/local/lib/python2.7/dist-packages/kivy/uix/widget.py", line 466, in add_widget
% (widget, parent))
WidgetException: Cannot add <kivy.uix.actionbar.ActionButton object at 0x7fecb5d6ed50>, it already has a parent <kivy.uix.actionbar.ActionView object at 0x7fecb5d6e8d8>
4 个回答
你可以试着把size_hint设置为0。我这样做是为了隐藏一个嵌套在BoxLayout里的布局,这个方法效果很好。还有一种方法是把这个小部件从它的父级中移除。不过如果你打算再把它加回来,就需要重新创建它。比如:
widget = Widget()
parent.add_widget(widget)
parent.remove_widget(widget)
# Create the widget again
widget = Widget()
parent.add_widget(widget)
我还在学习kivy,结果发现,居然没有直接的属性或方法可以做到这一点。相反,你需要把这个小部件从它的父级中移除,或者把它的颜色透明度设置为0(这只在你只有一种颜色的情况下有效)。
更新:
错误信息显示,当调用 self.ids.av.add_widget(self.next)
时,self.next
仍然有一个父级。因为这个调用之前有一个 self.ids.av.clear_widgets()
,所以 self.next
仍然在小部件树中的唯一可能是它实际上并不是 self.ids.av
的子级。也许它是 av
使用的默认布局的子级,而布局不会立即被垃圾回收。试试
print 'next in av.children:', self.next in self.ids.av.children
print 'parent of next:', self.next.parent
# self.ids.av.clear_widgets()
# self.ids.av.add_widget(self.next)
parent = self.next.parent
parent.remove_widget(self.next)
parent.add_widget(self.next)
有一种比简单地添加或删除小部件更好的隐藏方法。你只需要把它的位置设置为一个屏幕外的坐标就可以了:
# save the old y-coordinate of MyWidget.pos
root.saved_y = MyWidget.y
# Now move the widget offscreen (recall that pos is just an alias for (x, y))
MyWidget.y = 5000
(我已经测试过这个方法,它是有效的。)
从父级中移除小部件并不是一个好主意,特别是如果你的目的是让它们隐藏起来。当你把某个东西从Kivy的结构中移除时,它会被垃圾回收器处理掉。你可以尝试保留对它的引用,但从概念上讲,隐藏和移除是不同的。
对我来说,最好的解决办法是使用不透明度属性。这有点像可见性属性,但更强大,因为它可以接受渐变(和动画)。
需要注意的是,你必须考虑到小部件仍然存在。它只是不可见而已。在某些情况下,你可能想尝试将opacity
和disabled
属性结合使用。
Button:
opacity: 0
disabled: True # To make sure it doesn't capture events accidentally