выпадающее меню kivy в FloatLayout и GridLayout не отображается - PullRequest
0 голосов
/ 27 мая 2020

Привет, ребята, пытаюсь создать приложение с кнопкой раскрывающегося списка, но похоже, что это не работает (полное приложение имеет GridLayout с 7 строками, а этот FloatLayout в примере - одна из строк). Я пробовал использовать GridLayout, BoxLayout, и FloatLayout и по-прежнему не отображается в приложении. Есть идеи, что здесь не так?

.py файл

class WindowManager(ScreenManager, Screen):
    TestMe = ObjectProperty(None)

text_lists = ['hi', 'nice one', 'another one']


class TestMe(Screen, FloatLayout):
    global text_lists
    main_button = ObjectProperty(None)
    selected_list = 'SELECTED'
    top_layout = ObjectProperty(None)
    top_layout = GridLayout(cols=4)

    def __init__(self, **kwargs):
        super(TestMe, self).__init__(**kwargs)
        self.dropdown = DropDown()
        self.create_drop_down()
        self.create_go_button()

    def create_drop_down(self):
        for list_name in text_lists:
            # When adding widgets, we need to specify the height manually
            # (disabling the size_hint_y) so the dropdown can calculate
            # the area it needs.

            btn = Button(text= list_name, size_hint_y=None, height=88, width=400, background_color=(41/255, 21/255, 228/255, 1))

            # for each button, attach a callback that will call the select() method
            # on the dropdown. We'll pass the text of the button as the data of the
            # selection.
            btn.bind(on_release=lambda btn: self.dropdown.select(btn.text),
                     on_press=lambda btn: self.select_list(btn.text))

            # then add the button inside the dropdown
            self.dropdown.add_widget(btn)

        # create a big main button
        self.main_button = Button(text='Choose A List', size_hint=(None, None), height=88, width=400, background_color=(41/255, 21/255, 228/255, 1))

        # show the dropdown menu when the main button is released
        # note: all the bind() calls pass the instance of the caller (here, the
        # mainbutton instance) as the first argument of the callback (here,
        # dropdown.open.).
        self.main_button.bind(on_release=self.dropdown.open)

        # one last thing, listen for the selection in the dropdown list and
        # assign the data to the button text.
        self.dropdown.bind(on_select=lambda instance, x: setattr(self.main_button, 'text', x))
        self.top_layout.add_widget(self.main_button)

    def create_go_button(self):
        go_btn = Button(text="Go!", size_hint=(None, None), height=88, width=400, background_color=(41/255, 21/255, 228/255, 1))
        self.top_layout.add_widget(go_btn)

    def select_list(self, selected):
        self.selected_list = selected

class MyTest(App):
    def build(self):
        return kv


if __name__ == '__main__':
    kv = Builder.load_file('test_kv.kv')

    MyTest().run()

файл test_kv.kv

WindowManager:
    TestMe:

<TestMe>:
name: "testy"
id: testy
top_layout: top_layout
FloatLayout:
    Label:
        text: 'Test Screen'
        font: 'Aharoni'
        font_size: 24
        pos_hint: {"left": 0.45, "y": 0.45}
    GridLayout:
        pos_hint: {"top": 0.9}
        size_hint: 1, 0.8
        rows: 2
        spacing: 10
        padding: 10
        GridLayout:
            id: top_layout
            cols: 4
            Button:
                text: "Fun!"
            Label:
                text: "This is a test"
        Button:
            text: "Run!"

enter image description here

Ответы [ 2 ]

0 голосов
/ 29 мая 2020

Проблема в том, что вы вызываете create_drop_down() и create_go_button() в методе __init__() класса TestMe. Поскольку вы также определяете правило <TestMe>: в своем kv, возникает конфликт. Согласно несколько неясной документации , правило kv применяется после запуска __init__(). Это означает, что любой Widgets, добавленный к TestMe в его __init__(), будет перезаписан Widegets, указанным в правиле kv. Возможные решения - добавить всех дочерних элементов TestMe либо в метод __init__(), либо в kv, либо переместить добавление Widgets из метода __init__(). Вот модифицированная версия вашего кода, которая использует последний подход:

class WindowManager(ScreenManager, Screen):
    TestMe = ObjectProperty(None)

text_lists = ['hi', 'nice one', 'another one']


class TestMe(Screen, FloatLayout):
    global text_lists
    main_button = ObjectProperty(None)
    selected_list = 'SELECTED'
    top_layout = ObjectProperty(None)
    #top_layout = GridLayout(cols=4)

    def __init__(self, **kwargs):
        super(TestMe, self).__init__(**kwargs)
        self.dropdown = DropDown()
        Clock.schedule_once(self.create_drop_down)
        Clock.schedule_once(self.create_go_button)
        # self.create_drop_down()
        # self.create_go_button()

    def create_drop_down(self, *args):
        for list_name in text_lists:
            # When adding widgets, we need to specify the height manually
            # (disabling the size_hint_y) so the dropdown can calculate
            # the area it needs.

            btn = Button(text= list_name, size_hint_y=None, height=88, width=400, background_color=(41/255, 21/255, 228/255, 1))

            # for each button, attach a callback that will call the select() method
            # on the dropdown. We'll pass the text of the button as the data of the
            # selection.
            btn.bind(on_release=lambda btn: self.dropdown.select(btn.text),
                     on_press=lambda btn: self.select_list(btn.text))

            # then add the button inside the dropdown
            self.dropdown.add_widget(btn)

        # create a big main button
        # self.main_button = Button(text='Choose A List', size_hint=(None, None), height=88, width=400, background_color=(41/255, 21/255, 228/255, 1))
        self.main_button = Button(text='Choose A List', background_color=(41/255, 21/255, 228/255, 1))

        # show the dropdown menu when the main button is released
        # note: all the bind() calls pass the instance of the caller (here, the
        # mainbutton instance) as the first argument of the callback (here,
        # dropdown.open.).
        self.main_button.bind(on_release=self.dropdown.open)

        # one last thing, listen for the selection in the dropdown list and
        # assign the data to the button text.
        self.dropdown.bind(on_select=lambda instance, x: setattr(self.main_button, 'text', x))
        self.top_layout.add_widget(self.main_button)

    def create_go_button(self, *args):
        # go_btn = Button(text="Go!", size_hint=(None, None), height=88, width=400, background_color=(41/255, 21/255, 228/255, 1))
        go_btn = Button(text="Go!", background_color=(41/255, 21/255, 228/255, 1))
        self.top_layout.add_widget(go_btn)

    def select_list(self, selected):
        self.selected_list = selected

class MyTest(App):
    def build(self):
        return kv

Я изменил код для вызова методов create с использованием Clock.schedule_once(), так что это происходит после правила kv применяется. Я также удалил аргументы size_hint и size из Buttons, созданного, чтобы разрешить GridLayout их размер. Я также закомментировал ненужный код.

0 голосов
/ 28 мая 2020

Большая основная кнопка появляется, когда я запускаю ваш код (пришлось добавить класс App), и работает, как ожидалось. Но Button появляется в нижнем левом углу с вашим light.png Image. Попробуйте немного сдвинуть его, чтобы он не перекрывал Image. Примерно так:

    self.main_button = Button(text='Choose A List', size_hint=(None, None), height=88, width=140,
                              background_color=(41/255, 21/255, 228/255, 1), pos_hint={'center_x':0.5, 'y':0.4})

Я также сделал его немного шире, чтобы он содержал текст Choose A List.

...