Kivy在GridLayout中添加和删除小部件会产生弱参考问题



我正在尝试使用 Python-Kit 从 GridLayout 中动态添加和删除小部件,并且遇到了引用较弱的问题。初始化包含 GridLayout 的屏幕时,我在 GridLayout 中放置一个 Label,其中包含通知用户容器没有项的文本(从技术上讲,它有 Label,因此不一定是空的)。然后,我有一个按钮,允许用户将包含标签,文本输入和复选框的单个GridLayout小部件添加到GridLayout,以及一个允许用户删除他们创建的单个GridLayout小部件的按钮。如果删除了所有这些小组件(由用户动态添加),则会将原始标签添加回 GridLayout。

当我尝试在 Python 中构建此逻辑以与 Kivy 配对时,我遇到了一个问题,即原始标签似乎从未从堆栈中完全删除。

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

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

任何帮助都非常感谢。

编辑

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

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()

千伏

<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()

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

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()

千伏

<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()

最新更新