#python #kivy #kivy-language
Вопрос:
Моя цель-выпадающий список, аналогичный тем, которые можно увидеть в Проводнике Windows:
Я экспериментирую DropDown
со следующим кодом:
main.py
import kivy
kivy.require('2.0.0')
from kivy.app import App
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.dropdown import DropDown
from kivy.uix.textinput import TextInput
from kivy.properties import ObjectProperty
class CustomDropDown(TextInput):
droplist = ObjectProperty(None)
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
self.droplist.open(self)
return super().on_touch_down(touch)
class MainApp(AnchorLayout):
pass
class MyApp(App):
def build(self):
return MainApp()
if __name__ == '__main__':
MyApp().run()
мой.кв
<MainApp>:
CustomDropDown:
<CustomDropDown>
text: 'Select an option..'
size_hint_y: None
height: 30
droplist: options
DropDown:
id: options
Label:
text: 'Option 1'
Label:
text: 'Option 2'
Label:
text: 'Option 3'
Я получаю следующую ошибку в строке self.droplist.open(self)
:
Cannot add <kivy.uix.dropdown.DropDown object at 0x00000223791F39E0> to window, it already has a parent <__main__.CustomDropDown object at 0x00000223791BA580>
I think this should be working, and after some time troubleshooting I still can’t figure out why it doesn’t. Does anyone spot my error?
—UPDATE 9/12/2021 3:30PM—
Thank you @inclement for the suggestion, thanks to your response I was able to move forward. However, I now have a follow-up question:
Чтобы реализовать это предложение, я DropDown
подклассировал и Label
и отменил методы on_select
и on_touch_down
, соответственно. Мне также пришлось переопределить __init__
метод DropDown
в моем подклассе, чтобы я мог получить доступ к TextInput
окну и обновить его содержимое с on_select
помощью . Это кажется неудобным и добавляет много кода, не упускаю ли я чего-то, что уменьшило бы объем и сложность такого рода кода?
обновлено main.py
import kivy
kivy.require('2.0.0')
from kivy.app import App
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.dropdown import DropDown
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
class CustomDropDown(TextInput):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.dropdown = DropDownList(self)
for item in ['Option 1', 'Option 2', 'Option 3']:
lbl = DropDownItem(text=item, size_hint_y=None, height=30)
self.dropdown.add_widget(lbl)
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
self.dropdown.open(self)
return super().on_touch_down(touch)
class DropDownList(DropDown):
def __init__(self, user_choice, **kwargs):
super().__init__(**kwargs)
self.user_choice = user_choice
def on_select(self, data):
setattr(self.user_choice, 'text', data)
class DropDownItem(Label):
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
dropdown = self.parent.parent
dropdown.select(self.text)
return super().on_touch_down(touch)
class MainApp(AnchorLayout):
pass
class MyApp(App):
def build(self):
return MainApp()
if __name__ == '__main__':
MyApp().run()
Обновил свой.kv
<MainApp>:
DropDownTextInput:
<DropDownTextInput>
text: 'Select an option..'
size_hint_y: None
height: 30
Еще раз спасибо!
Ответ №1:
Раскрывающиеся списки предназначены для открытия путем вызова их open
метода, который добавляет их в дерево виджетов таким образом, чтобы они отображались поверх всего и в правильном положении, но вы сами добавили их в дерево виджетов, поместив в свое правило kv. Вот почему у него уже есть родитель.
Вы не должны объявлять его дочерним CustomDropDown
, вместо этого создайте новый экземпляр и вызовите open
его метод.
Комментарии:
1. Ага! Это помогло мне отвлечься, большое вам спасибо! Однако код стал немного сложнее, возможно, вы увидите мое обновление к сообщению с моей рабочей реализацией