python - 从 Kivy 中动态填充的下拉列表中选择性地删除子小部件
问题描述
我创建了一个动态下拉列表,它创建了我在文本输入字段中指定的按钮。按钮正在按预期动态填充,但我想有选择地从下拉列表中删除某些按钮(子小部件),而不是同时清除所有子小部件。kv 文件有两个默认定义的按钮。当我使用该clear_widgets()
功能时,它会删除所有子小部件。以下是代码。
Python
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.properties import NumericProperty, StringProperty
from kivy.uix.dropdown import DropDown
class CustomTextInput(TextInput):
# Numeric property defined for use in both Python and Kivy (binding)
max_characters = NumericProperty(0)
# Override the default behaviour of the insert_text method
def insert_text(self, substring, from_undo=False):
if len(self.text)==self.max_characters and self.max_characters>0:
substring=""
TextInput.insert_text(self, substring, from_undo)
class ImageLabel(BoxLayout):
source = StringProperty('atlas://data/images/defaulttheme/audio-volume-high')
text = StringProperty('default text')
class ImageLabelButton(ButtonBehavior, ImageLabel):
pass
class ImageLabelButtonTop(ButtonBehavior, ImageLabel):
pass
class DropDownScreen(Screen):
def add_dd_values(self):
dd_input = App.get_running_app().root.get_screen('dropdown_screen').ids.textinput_num.text
print("TextInputBox: ", dd_input, "\n")
print("Length: ",len(dd_input))
print("Data Type: ", type(dd_input))
# Check if the text input box is empty and assign a default string of '0' so that int conversion and numerical operations do not fail with an error.
if dd_input == '':
dd_input="0"
print(int(dd_input)+1)
# Reset dropdown list. Clear all existing child widgets of dropdown including the original 2 buttons defined inside the kv file.
App.get_running_app().root.get_screen('dropdown_screen').ids.dropdown.clear_widgets()
for x in range(int(dd_input)):
if x%2==0:
print(x,"is an even number")
App.get_running_app().root.get_screen('dropdown_screen').ids.dropdown.add_widget(ImageLabelButton(source="twitter-48.png",text="Twitter"))
else:
print(x,"is an odd number")
App.get_running_app().root.get_screen('dropdown_screen').ids.dropdown.add_widget(ImageLabelButton(source="linkedin-2-48.png",text="LinkedIn"))
class MyScreenManager(ScreenManager):
pass
class DropApp(App):
def build(self):
# Initialize root widget
# Screen Manager instance
sm = MyScreenManager()
# DropDown Screen Instance
dds = DropDownScreen()
sm.add_widget(dds)
return sm
if __name__ == '__main__':
# Run application
DropApp().run()
基维
<DropDownScreen>:
name: 'dropdown_screen'
canvas.before:
Color:
rgba: 255/255, 255/255, 255/255, 1
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
orientation: 'vertical'
BoxLayout:
orientation: 'horizontal'
Label:
text: 'No. of drop-down buttons:'
markup: True
color: 0, 0, 0, 1
CustomTextInput:
id: textinput_num
max_characters: 2
multiline: False
input_filter: 'int'
BoxLayout:
ImageLabelButtonTop: # conflict in the on_release defined for ImageLabelButton and this instance.
id: parent_button
source: 'expand-arrow-48.png'
text: 'Expand Drop-Down'
on_release:
root.add_dd_values()
dropdown.open(self)
print("self in ImageLabelButtonTop points to ", self, "\n")
on_parent: dropdown.dismiss()
size_hint_y: None
height: '48dp'
DropDown:
id: dropdown
on_select:
# parent_button.text = str(args[1]) # args is a reserved keyword which returns only two values: object alias (0) and data (1).
parent_button.text = args[1][0]
parent_button.source = args[1][1]
print("Invoked inside dropdown")
print(args, app.root, root, self, "\n") # root - Screen, self - DropDown object
ImageLabelButton:
source: 'twitter-48.png'
text: 'Twitter'
ImageLabelButton:
source: 'linkedin-2-48.png'
text: 'LinkedIn'
BoxLayout:
Label:
text: 'Test dynamic drop-down'
markup: True
color: 0, 0, 0, 1
<ImageLabel>:
orientation: 'horizontal'
size_hint_y: None
height: '48dp'
spacing: 1
Image:
keep_ratio: True
source: root.source # root - ImageLabel
Label:
markup: True
text: root.text # root - ImageLabel
color: 0, 0, 0, 1
<ImageLabelButton>:
on_release:
# Tuple returned in dropdown.select() method to pass two values bundled as one.
app.root.get_screen('dropdown_screen').ids.dropdown.select((self.text, self.source))
print("Invoked inside ImageLabelButton rule")
print(app.root, root, self, "\n") # app.root - Screen, root - ImageLabelButton object, self - ImageLabelButton object
<CustomTextInput>:
use_bubble: True
use_handles: True
如果我注释掉下面这行,下拉列表会在每次点击时不断累积添加按钮,这是可以理解的。
App.get_running_app().root.get_screen('dropdown_screen').ids.dropdown.clear_widgets()
我想要实现的是:
- kv 文件应默认加载 2 个按钮,如 kv 文件中所定义
- 我在文本输入字段中指定了一个数字。例如:4
- 下拉菜单总共应该有 2 + 4 = 6 个按钮
- 如果我定义一个新按钮来删除 4 个新按钮,则只应删除最后 4 个子小部件。原来的 2 个按钮应该在下拉列表中保持不变。
我想,如果我将动态创建的子小部件的引用存储在列表或字典中,然后通过单独的删除按钮删除它们,它可能会起作用。但我不确定如何在 Python 函数中对其进行编码。
有人可以帮忙吗?
谢谢
解决方案
您是否尝试过使用remove_widget
而不是clear_widgets
?例如:
dropdown = App.get_running_app().root.get_screen('dropdown_screen').ids.dropdown
children_to_remove = []
for child in dropdown.children:
if child.some_indicator == True:
children_to_remove.append(child)
for child in children_to_remove:
dropdown.remove(child)
(您不能dropdown.remove(child)
在第一个 for 循环中进行调用,因为它会在迭代时改变 dropdown.children 数组)
推荐阅读
- sharepoint - 将 Sharepoint 导出为 Excel 表单
- python - dict() 函数在 colab 和 jupyter notebook 之间的行为不同
- javascript - 纯js中的动画优化
- html - 如何使用 GitHub Pages 上的 Jekyll 使用 Bootstrap 4 的“site\docs\4.4\examples”文件夹内容?
- arrays - C语言数组中的字符出现
- python - 在多个列表中,我如何找到并返回包含我想要的值的列表?
- javascript - 使用 prisma,如何从嵌套写入中访问新创建的记录(先更新,然后在其中创建)
- python - Tkinter计算器如何在开始新计算时清除过去的答案
- python - Django 管理站点未显示模型的默认权限
- javascript - Javascript外部不起作用,但当内联工作时