2017-06-20 71 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() 
相關問題