如何在Kivy中隐藏一个ActionButton?

6
我试图根据当前屏幕(使用屏幕管理器)修改ActionButton的可见性。我无法找到一个Visible属性或类似于此的东西,可以简单地切换可见性(对于ActionButton或一般小部件都没有)。2013年的一篇文章建议更改按钮的纹理,但我不想依靠这样的技巧来完成如此简单的任务,而且我的应用程序背景将是可变的。另一篇文章建议根据需要删除小部件并再次添加它。尽管它不必要地复杂,但我修改后适用于我的情况(ActionBar和ActionButton),所以我清除了ActionView中的小部件,然后尝试添加ActionButton。我尝试存储弱引用和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>

你能发一些你尝试过的代码吗? - paarth batra
当然,我添加了一个简短的例子。 - papirrin
1
@papirin - 如果您能发布完整的示例代码,我可能可以帮助您。一个可运行的代码...我也遇到了一些按钮的问题,并解决了它。可能我们需要通过使用try catch或其他一些东西进行微调(其他一些东西比try catch更整洁):) - paarth batra
@paarthbatra 非常感谢您查看此问题。我最终发现问题实际上是ActionView处理其子项的错误,但该功能仍在开发中。当ActionBar稳定下来后,我会再次查看。 - papirrin
你也可以通过设置透明度来隐藏按钮,self.next.opacity = 0,并且通过self.next.opacity = 1来显示它,虽然这可能不完全是您想要的,因为它只会使其变得透明。 - martin
4个回答

11
从父级小部件中移除小部件并不是一个好主意,如果目的是为了隐藏它们。当从Kivy树结构中删除某些东西时,它将被垃圾收集器捡起。你可以尝试保留对它的引用,但在概念上,“隐藏”与“删除”是不同的。
对我来说最好的解决方案是使用不透明度属性。它有点像可见属性的原理,但更强大,因为它接受渐变(和动画)。
“注意”的是,你必须考虑到Widget仍然存在。它只是不可见的。在某些情况下,你可能需要尝试将opacity与disabled属性结合使用。
Button:
    opacity: 0
    disabled: True # To make sure it doesn't capture events accidentally

请您能否提供一个例子? - DaNNuN
1
按钮: id:button1 文本:'' 不透明度:0 大小:(0,0) - DaNNuN
我举个例子,如果你调整大小为0,0,你可能不需要透明度。 如果size 不起作用,应该首先尝试 size_hint - toto_tico
嗨 Tico,就我的情况而言,我希望我的按钮出现并增长,因此使用动画来增加和缩小不透明度和大小。 - DaNNuN
这对我来说并不完全有效。即使禁用,按钮仍然无法将事件(在我的情况下是触摸事件)传递给其下面的小部件。 - iliis

5

隐藏小部件的更好方法是设置其位置,包括屏幕外的坐标,而不是添加或删除它们:

# 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

(我已经测试了这个解决方案,它可行。)

1
如果您的小部件是GridLayout的子级,则它将无法正常工作。 - Zuku

1
我仍在学习kivy,但出乎意料的是,似乎没有属性或成员函数可以做到这一点。相反,您必须从其父级中删除小部件,或将其颜色alpha设置为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)

我发布的代码可以删除小部件,但问题在于当我再次尝试添加它时会出现错误。 - papirrin

0

你可以尝试将size_hint设置为0。我曾经这样做来隐藏一个嵌套在BoxLayout中的布局,它完美地工作了。另一种方法是从其父级中删除小部件。但如果您计划重新添加它,则需要再次实例化它。例如:

widget = Widget()
parent.add_widget(widget)
parent.remove_widget(widget)
# Create the widget again
widget = Widget()
parent.add_widget(widget)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接