Выпадающие меню в kivy с добавлением других кнопок

я сделал вот так:

<cont>:
    Button:
        id: a
        text: 'hi'
        size_hint: (0.3, 0.1)
        pos_hint: {'top': 1, 'right': 1}
        on_press: app.dropdown.open()

но выдало вот такую ошибку:

 TypeError: open() missing 1 required positional argument: 'widget'

добавил виджет, получилось вот так:

<cont>:
    Button:
        id: a
        text: 'hi'
        size_hint: (0.3, 0.1)
        pos_hint: {'top': 1, 'right': 1}
        on_press: app.dropdown.open(app.dropdown)

но теперь выдало вот такую ошибку:

 kivy.uix.dropdown.DropDownException: Cannot open a dropdown list on a hidden widget

Там не его самого передавать надо, а под каким элементом он должен появиться.

https://kivy.org/doc/stable/api-kivy.uix.dropdown.html#kivy.uix.dropdown.DropDown.open

Open the dropdown list and attach it to a specific widget. Depending on the position of the widget within the window and the height of the dropdown, the dropdown might be above or below that widget.

Например, чтобы это была эта кнопка:

app.dropdown.open(self)

спасибо, это помогло, но теперь появилась новая проблема: я хочу чтобы при нажатие на одну из кнопок выпадающего списка изменялся текст кнопки hi на текст кнопки, которая была нажата
я пытался вот так:

Button:
        text: 'perimetr'
        size_hint_y:  None
        height:  44
        on_press: app.per()

это одна из кнопок списка, вот функция ‘per’:

    def per(self):
        
        self.text = 'perimetr'

‘self.text’ это текст кнопки

Так внутри app self это не кнопка.

Например, так:

on_press: self.text = 'perimetr'

у меня self.text это текст в основном классе:

class app(App):
    
    text = ''

    def build(self):
        self.dropdown = CustomDropDown()


        return cont()

но сделал и так как ты сказал:

on_press: app.text = 'perimetr'

не помогло

Так а кнопка как узнает, что ей надо брать текст из app.text?)

Надо тогда сделать свойство и привязать к нему как тут

кнопка у которой должен измениться текст вот, там указано на app.text:

<cont>:
    Button:
        id: a
        text: app.text
        size_hint: (0.3, 0.1)
        pos_hint: {'top': 1, 'right': 1}
        on_release: app.dropdown.open(self)

:arrow_down:

app.dropdown.open(self)
а как открыть выпадающее меню под каким-нибудь другим элементом? вот это не помогает:

on_release: app.dropdownkv.open(root.ids.what)

Это что? :thinking:

Параметром же вроде и передается элемент, под которым откроется.

я пытался вот так:

app.dropdownkv.open(root.ids.what.pos)

root.ids.what
это id кнопки под которой нужно открыть меню(эта не та кнопка на которую надо нажать что бы меню открылось)

Так там сам виджет нужен, а не id.

app.dropdownkv.open(app.some_other_widget)

а как назвать нужный виджет если он находится в kv файле и кнопок несколько

https://kivy.org/doc/stable/guide/lang.html#referencing-widgets

Добавить id кнопке и просто использовать его как переменную.

app.dropdownkv.open(some_other_widget)

вот кнопка под которой нужно открыть меню:

Button:

        text: app.text2
        size_hint: (0.5, 0.1)
        pos_hint: {'top': 1, 'right': 1}
        on_release: app.dropdown2.open(self)
        id: what

вот при нажатии на которую нужно открыть меню:

Button:
        text: 'kvadrat'
        size_hint_y:  None
        height:  44
        on_press: app.kvad()
        on_release: app.dropdownkv.open(root.ids.what)

вот здесь писал я написал id кнопки под которой нужно открыть, это не помогает

если так запустить и нажать на кнопку kvadrat , то выдаст эту ошибку:

'super' object has no attribute '__getattr__'

Так я ж говорю

app.dropdownkv.open(what)

Если они внутри одного виджета в kv.

An id is limited in scope to the rule it is declared in, so in the code above s_but can not be accessed outside the <MySecondWidget> rule.

кнопка what в другом контейнере, вот полный kv файл:

<cont>:
    Button:
        id: a
        text: app.text
        size_hint: (0.5, 0.1)
        pos_hint: {'top': 1, 'left': 0.1}
        on_release: app.dropdown.open(self)


    Button:

        text: app.text2
        size_hint: (0.5, 0.1)
        pos_hint: {'top': 1, 'right': 1}
        on_release: app.dropdown2.open(self)
        id: what

    TextInput:

        size_hint: 0.5,0.07
        pos_hint: {'top': 0.9, 'left': 0.1}
        hint_text: 'a'
        on_text: app.a1()
        input_filter: 'float'
        id: inputa





    Label:
        text: app.text3
        pos_hint: {'top': 0.83, 'center_x': 0.5}
        size_hint: 0.5,1

    Button:
        text: 'solve'
        size_hint: (1, 0.2)
        pos_hint: {'top': 0.83, 'center_x': 0.5}
        on_press: app.solve()

<dropkvad>:
    TextInput:
        size_hint_y:  None
        height:  44
        on_text: app.b1()
        hint_text: 'b'
        input_filter: 'float'
        id: inputb

<drop1>:
    Button:
        text: 'perimetr'
        size_hint_y:  None
        height:  44
        on_press: app.per()
        on_release: root.select('perimetr')


    Button:
        text: 'ploshad'
        size_hint_y:  None
        height:  44
        on_press: app.plo()
        on_release: root.select('ploshad')



<drop2>:
    Button:
        text: 'kvadrat'
        size_hint_y:  None
        height:  44
        on_press: app.kvad()
        on_release: app.dropdownkv.open(what)

    Button:
        text: 'pramoygolnik'
        size_hint_y:  None
        height:  44
        on_press: app.pram ()
        on_release: root.select('pramoygolnikr')


А как они создаются в приложении?

Так нельзя обращаться потому что каждый “контейнер” (точнее они называются Rule) это не конкретный экземпляр, а как класс, шаблон, экземпляры которого могут быть созданы где угодно сколько угодно раз.

Например, так:

<cont>:
    drop2:
        id: w1
    drop2:
        id: w2

Как вариант можно просто не плодить лишние контейнеры если они не нужны и просто в cont всё перенести.

Или добавить в cont в kv как в примере выше, и тогда если cont это корень приложения (создается и возвращается в build), то можно app.dropdownkv.open(app.root.ids.w1.what)

Похожий пример: https://stackoverflow.com/a/46408702/964478

сделал ка ты сказал:

<cont>:
    Button:
        id: a
        text: app.text
        size_hint: (0.5, 0.1)
        pos_hint: {'top': 1, 'left': 0.1}
        on_release: app.dropdown.open(self)


    Button:

        text: app.text2
        size_hint: (0.5, 0.1)
        pos_hint: {'top': 1, 'right': 1}
        on_release: app.dropdown2.open(self)
        id: what

    TextInput:

        size_hint: 0.5,0.07
        pos_hint: {'top': 0.9, 'left': 0.1}
        hint_text: 'a'
        on_text: app.a1()
        input_filter: 'float'
        id: inputa





    Label:
        text: app.text3
        pos_hint: {'top': 0.83, 'center_x': 0.5}
        size_hint: 0.5,1

    Button:
        text: 'solve'
        size_hint: (1, 0.2)
        pos_hint: {'top': 0.83, 'center_x': 0.5}
        on_press: app.solve()

    drop2:
        Button:
            text: 'kvadrat'
            size_hint_y:  None
            height:  44
            on_press: app.kvad()
            on_release: app.dropdownkv.open(what)

        Button:
            text: 'pramoygolnik'
            size_hint_y:  None
            height:  44
            on_press: app.pram ()
            on_release: root.select('pramoygolnikr')


<dropkvad>:
    TextInput:
        size_hint_y:  None
        height:  44
        on_text: app.b1()
        hint_text: 'b'
        input_filter: 'float'
        id: inputb

<drop1>:
    Button:
        text: 'perimetr'
        size_hint_y:  None
        height:  44
        on_press: app.per()
        on_release: root.select('perimetr')


    Button:
        text: 'ploshad'
        size_hint_y:  None
        height:  44
        on_press: app.plo()
        on_release: root.select('ploshad')

и при запуске получается вот так:

хотя должно быть так:

и открываться так:

но теперь при нажатии на кнопку kvadrat появляется поле ввода, но исчезает при нажатии на другую область экрана

А как drop2 раньше добавлялся?
Вообще надо layout’ы, pos_hint и т.п. использовать, чтобы указать где что должно быть.

это нужно если оставить

если переносить, то можно просто сами кнопки.