Kivy从GridLayout添加和删除小部件给出了弱参考问题

时间:2018-03-22 17:05:03

标签: python kivy weak-references

我正在尝试使用Python-Kivy从GridLayout动态添加和删除小部件,我遇到了弱引用的问题。当初始化包含GridLayout的Screen时,我在GridLayout中放置一个Label,其中包含通知用户容器没有项目的文本(从技术上讲,它在那里有Label,所以它不一定是空的)。然后我有一个Button,允许用户将单独的GridLayout小部件添加到包含Label,TextInput和CheckBox的GridLayout,以及允许用户删除他们创建的那些单独GridLayout小部件的Button。如果删除了所有这些小部件(由用户动态添加),则将原始Label添加回GridLayout。

当我尝试在Python中构造这个逻辑以与Kivy配对时,我遇到了一个问题,原始Label似乎永远不会从堆栈中完全删除。

我的印象是self.ids.widget_list.remove_widget(self.ids.empty)会删除ID为empty的Label小部件,但事实并非如此。很明显,当我调用print(self.ids)时,小部件仍然存在:

{'widget_list': <WeakProxy to <kivy.uix.gridlayout.GridLayout object at 0x0451F030>>, 'empty': <WeakProxy to <kivy.uix.gridlayout.GridLayout object at 0x0451F9D0>>}

非常感谢任何帮助。

修改

每次调用for i in self.layouts: print(i.children)方法时检查remove(),表明对添加的小部件的引用永远不会被完全删除。这可能是我的问题所在,但不确定如何解决它。

的Python

import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.scrollview import ScrollView
from kivy.uix.label import Label
from kivy.uix.checkbox import CheckBox
from kivy.uix.popup import Popup
from kivy.uix.screenmanager import ScreenManager, Screen

#Load kv file
Builder.load_file('test.kv')

#First Screen
class Screen1(Screen):

    layouts = []

    def remove(self):

        for i in self.layouts:
            if i.children[0].active:
                self.ids.widget_list.remove_widget(i)

        if len(self.layouts)==0:
            layout = GridLayout(rows=1, id=empty)
            layout.add_widget(Label(text='Nothing Here'))
            self.ids.widget_list.add_widget(layout)
        else:
            self.update_hints()

    def add(self):

        if len(self.ids.widget_list.children)<5:

            print(self.ids)
            self.ids.widget_list.remove_widget(self.ids.empty)
            print(self.ids)
            layout = GridLayout(cols=3)
            layout.add_widget(Label(text='Test ' + str(len(self.ids.widget_list.children)+1)))
            layout.add_widget(TextInput())
            layout.add_widget(CheckBox())
            self.ids.widget_list.add_widget(layout)

            self.layouts.append(layout)
            self.update_hints()

        else:

            layout = GridLayout(cols=1)
            layout.add_widget(Label(text='Only five allowed at once.\nRemove at least one to add another.'))
            button = Button(text='Acknowledge'); layout.add_widget(button)
            popup = Popup(content=layout, title='Limit Reached', size_hint=(.5,.5), auto_dismiss=False)
            button.bind(on_release=popup.dismiss)
            popup.open()

    def update_hints(self):

        for i in self.layouts:
            i.children[1].hint_text = 'Ex. ' + str(round(100/len(self.ids.widget_list.children),2)) + '%'

#Initialize Screens and Start App
class MyScreenManager(ScreenManager):

    pass

#Main application
class SampleApp(App):

    def build(self):
        self.sm = MyScreenManager()
        return self.sm

if __name__ == '__main__':
    SampleApp().run()

KV

<MyScreenManager>:

    Screen1:
        name: 'screen1'

<Screen1>:

    BoxLayout:

        orientation: 'vertical'

        GridLayout:

            cols: 3
            padding: 20
            spacing: 20
            size_hint: 1, .1

            Label:
                text: 'List of Widgets'
                underline: True
            Label:
                text: 'Percentage'
                underline: True
            Label:
                text: 'Remove (Y/N)'
                underline: True

        ScrollView:

            size_hint: 1, .5
            do_scroll_x: False
            padding: 20
            spacing: 20

            GridLayout:

                id: widget_list
                cols: 1
                spacing: 5

                GridLayout:
                    id: empty
                    rows: 1
                    Label:
                        text: 'Nothing Here'

        GridLayout:

            cols: 3
            padding: 20
            spacing: 20
            size_hint: 1, .2

            Button:
                text: 'Add Widget'
                on_release: root.add()

            Label:
                text: ''

            Button:
                text: 'Remove Widget'
                on_release: root.remove()

1 个答案:

答案 0 :(得分:0)

好的,我似乎找到了一种更简单的实现方法,可以避免为初始Label指定任何id(同一个显示self.layouts==[]):

<强>的Python

import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.scrollview import ScrollView
from kivy.uix.label import Label
from kivy.uix.checkbox import CheckBox
from kivy.uix.popup import Popup
from kivy.uix.screenmanager import ScreenManager, Screen

#Load kv file
Builder.load_file('test.kv')

#First Screen
class Screen1(Screen):

    count = 0
    layouts = []

    def remove(self):

        for i in self.layouts:
            if i.children[0].active:
                self.ids.widget_list.remove_widget(i)

        self.layouts = [i for i in self.layouts if not i.children[0].active]

        if self.layouts!=[]:
            self.update_hints()
        else:
            layout = GridLayout(rows=1)
            layout.add_widget(Label(text='Nothing Here'))
            self.ids.widget_list.add_widget(layout)

    def add(self):

        if self.layouts==[]:
            self.ids.widget_list.clear_widgets()

        if len(self.ids.widget_list.children)<5:
            self.count+=1
            layout = GridLayout(cols=3)
            layout.add_widget(Label(text='Test ' + str(self.count)))
            layout.add_widget(TextInput())
            layout.add_widget(CheckBox())
            self.ids.widget_list.add_widget(layout)
            self.layouts.append(layout)
            self.update_hints()
        else:
            layout = GridLayout(cols=1)
            layout.add_widget(Label(text='Only five allowed at once.\nRemove at least one to add another.'))
            button = Button(text='Acknowledge'); layout.add_widget(button)
            popup = Popup(content=layout, title='Limit Reached', size_hint=(.5,.5), auto_dismiss=False)
            button.bind(on_release=popup.dismiss)
            popup.open()

    def update_hints(self):

        for i in self.layouts:
            i.children[1].hint_text = 'Ex. ' + str(round(100/len(self.ids.widget_list.children),2)) + '%'

#Initialize Screens and Start App
class MyScreenManager(ScreenManager):

    pass

#Main application
class SampleApp(App):

    def build(self):
        self.sm = MyScreenManager()
        return self.sm

if __name__ == '__main__':
    SampleApp().run()

<强> KV

<MyScreenManager>:

    Screen1:
        name: 'screen1'

<Screen1>:

    BoxLayout:

        orientation: 'vertical'

        GridLayout:

            cols: 3
            padding: 20
            spacing: 20
            size_hint: 1, .1

            Label:
                text: 'List of Widgets'
                underline: True
            Label:
                text: 'Percentage'
                underline: True
            Label:
                text: 'Remove (Y/N)'
                underline: True

        ScrollView:

            size_hint: 1, .5
            do_scroll_x: False
            padding: 20
            spacing: 20

            GridLayout:

                id: widget_list
                cols: 1
                spacing: 5

                GridLayout:
                    rows: 1
                    Label:
                        text: 'Nothing Here'

        GridLayout:

            cols: 3
            padding: 20
            spacing: 20
            size_hint: 1, .2

            Button:
                text: 'Add Widget'
                on_release: root.add()

            Label:
                text: ''

            Button:
                text: 'Remove Widget'
                on_release: root.remove()