2017-06-20 73 views
0

我在弹出(ModalView)动态改变的值显示。我在我的主窗口小部件类中使用一种方法来打开/关闭弹出窗口,并将Kivy StringProperty绑定到弹出窗口中的标签。有一个问题 - 每次弹出窗口被解散时,都会留下一些东西。列出StringProperty的所有观察者显示每个循环打开/关闭对象的数量是如何累积的。请参阅下面的示例代码。当我在Raspbian Jessie(Pixel)下的Raspberry Pi 2上运行此程序并为其分配了128M的VRAM时,大约一分钟内程序停止正常运行 - 弹出菜单开始显示黑屏。我在我的代码中做了些什么傻事?Kivy属性观察者的对象被驳回

from kivy.app import App 
from kivy.lang import Builder 
from kivy.uix.boxlayout import BoxLayout 
from kivy.uix.button import Button 
from kivy.uix.label import Label 
from kivy.uix.modalview import ModalView 
from kivy.clock import Clock 
from kivy.properties import StringProperty 
from random import randint 


Builder.load_string(''' 
#:kivy 1.9.2 

<MainWidget>: 
    BoxLayout: 
     Button: 
''') 


class MainWidget(BoxLayout): 

    value_str = StringProperty() 

    def show_popup(self, even=True): 
     if even: 
      popup = ModalView(size_hint=(None, None), auto_dismiss=False, size=(700,480)) 
      popup_label = Label(font_size = 200, text_size=self.size, halign='center', valign='center') 
      self.bind(value_str=popup_label.setter('text')) # value_str must be a Kivy StringProperty 
      popup.add_widget(popup_label) 
      self.value_str = str(randint(0,100)) 
      popup.open() 
     else: # find all instances of ModalView and dismiss them 
      for widget in App.get_running_app().root_window.children: 
       if isinstance(widget, ModalView): 
        print "observers of value_str property:" 
        observers = self.get_property_observers('value_str') 
        for observer in observers: 
         print observer 

        widget.dismiss(force=True, animation=False)  

     Clock.schedule_once(lambda dt: self.show_popup(not even), 0.25) 



class MyApp(App): 
    def build(self): 
     mw=MainWidget() 
     Clock.schedule_once(lambda dt: mw.show_popup(),0) 
     return mw 


if __name__ == '__main__': 

    MyApp().run() 
+0

您正在不断地创造ModalView的新实例。对象的数量增长,直到它填满内存。 – FJSevilla

+0

确实是我,但每次创建ModalView的实例时,我都会忽略它。这似乎并没有完全摧毁它,我是否应该更明确地删除所有对它的引用,以便它被垃圾收集?如果我没有将Kivy属性绑定到ModalView实例的Label子元素的文本字段,问题就会消失。 –

+0

我认为重新说明这样的问题可能会有所帮助。当我使用静态内容持续打开和关闭ModalView的新实例时,我不会遇到RAM填满的问题。当我这样做但是这次绑定到ModalView实例的子部件内的Kivy属性VRAM?被填满了。如何防止这一点? –

回答

0

我发现了一个解决办法,这个How to unbind a property automatically binded in Kivy language? 启发我现在从ModalView取出并将其添加到ModalView前MainWidget保持标签的孩子被驳回,那么扭转这种下一个弹出窗口。这样,属性绑定只发生一次,所以不会创建新的观察者。通过将空字符串分配给绑定属性,可以使标签不可见。

我觉得这可能是一个错误 - ModalView解雇()方法不应该离开观察者的背后,却不能与最新版本Kivy(1.10.1.dev0)测试。

下面的代码:

from kivy.app import App 
from kivy.lang import Builder 
from kivy.uix.floatlayout import FloatLayout 
from kivy.uix.button import Button 
from kivy.uix.label import Label 
from kivy.uix.modalview import ModalView 
from kivy.clock import Clock 
from kivy.properties import StringProperty 
from random import randint 

Builder.load_string(''' 
#:kivy 1.9.2 

<MyLabel>: 
    font_size: 100 
    text_size: self.size 
    halign: 'center' 
    valign: 'center' 

<MainWidget>: 
    Button: 
     background_color: 0.5, 0.5, 1, 1 
''') 


class MyLabel(Label): 
    pass 

class MainWidget(FloatLayout): 

    value_str = StringProperty() 
    popup_label = MyLabel() 


    def __init__(self, **kwargs): 
     super(MainWidget, self).__init__(**kwargs) 
     self.bind(value_str=self.popup_label.setter('text')) # value_str must be a Kivy StringProperty 
     self.add_widget(self.popup_label) 



    def show_popup(self, even=True): 
     if even: 
      popup = ModalView(size_hint=(None, None), auto_dismiss=False, size=(500,380)) 
      self.remove_widget(self.popup_label) 
      popup.add_widget(self.popup_label) 
      self.value_str = str(randint(0,100)) 
      popup.open() 

     else: # find all instances of ModalView and dismiss them 
      for widget in App.get_running_app().root_window.children: 
       if isinstance(widget, ModalView): 
        print "observers of value_str property:" 
        observers = self.get_property_observers('value_str') 
        for observer in observers: 
         print observer 
        widget.remove_widget(self.popup_label) 
        self.add_widget(self.popup_label) 
        self.value_str ='' 
        widget.dismiss(force=True, animation=False) 
     Clock.schedule_once(lambda dt: self.show_popup(not even), 0.25) 


class MyApp(App): 
    def build(self): 
     mw=MainWidget() 
     Clock.schedule_once(lambda dt: mw.show_popup(),0) 
     return mw 


if __name__ == '__main__': 

    MyApp().run() 
相关问题