Kivy Accordion: предупреждение о нехватке места

#python #python-3.x #layout #kivy #accordion

#python #python-3.x #макет #kivy #аккордеон

Вопрос:

Я пытаюсь создать меню на основе аккордеона, используя Kivy и Python 3.7 на дисплее 1366×768 (на случай, если это что-то изменит). Код, похоже, работает просто отлично, поскольку я получаю желаемый результат. Тем не менее, я получаю предупреждение о том, что в аккордеоне недостаточно места для всех дочерних элементов (я полагаю), и макет будет прерван, но это не так: все нарисовано с большим количеством места. Хотя это не критическая проблема, поскольку все показывает, как ожидалось, я либо упускаю что-то очевидное, либо имею неправильное представление о том, как kivy генерирует элементы экрана. Итак, если бы вы могли прояснить это (и, надеюсь, избавиться от уродливого предупреждения), я бы очень оценил это!

Ниже приведена сокращенная версия кода, все на чистом python (я бы хотел оставить его таким, это не сложная программа). Я просто создаю внешнее BoxLayout, а внутри размещаю внутреннее GridLayout с аккордеонами кнопкой внизу. Обратите внимание, что я настроил kivy на запуск в виде развернутого окна, настройка для этого включена в код.

Сначала я подумал, что это может быть связано с порядком, в котором kivy обрабатывает элементы или что-то в этом роде: он может сначала проверить метки и кнопку, принимая значение size_hint по умолчанию = (1, 1), и подумать, что в нем нет места, но затем сможет нарисовать их благодаря пользовательскому size_hint . Однако, изменив это на (1, 1), я получил то же предупреждение, хотя все еще рисовал все с запасом места (хотя и не очень много). Однако предупреждение было немного изменено, поскольку оно показывало больше предупреждений с более жесткими ограничениями.

 from kivy.uix.boxlayout import BoxLayout
from kivy.uix.accordion import Accordion, AccordionItem
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.app import App

from kivy.config import Config


class TestApp(App):
    def build(self):
        layout = BoxLayout(orientation="vertical")

        inner_layout = GridLayout(cols=3)
        inner_layout.add_widget(Label(text="Section 1", size_hint=(1, 0.09), font_size='20dp'))
        inner_layout.add_widget(Label(text="Section 2", size_hint=(1, 0.09), font_size='20dp'))
        inner_layout.add_widget(Label(text="Section 3", size_hint=(1, 0.09), font_size='20dp'))

        accord1 = Accordion(orientation="vertical")
        accord1.add_widget(AccordionItem(title="Item 1"))
        accord1.add_widget(AccordionItem(title="Item 2"))

        accord2 = Accordion(orientation="vertical")
        accord2.add_widget(AccordionItem(title="Item 1"))

        accord3 = Accordion(orientation="vertical")
        accord3.add_widget(AccordionItem(title="Item 1"))
        accord3.add_widget(AccordionItem(title="Item 2"))
        accord3.add_widget(AccordionItem(title="Item 3"))

        inner_layout.add_widget(accord1)
        inner_layout.add_widget(accord2)
        inner_layout.add_widget(accord3)

        layout.add_widget(inner_layout)

        continue_btn = Button(text="START", size_hint=(1, 0.07))
        layout.add_widget(continue_btn)

        return layout


if __name__ == "__main__":
    # Three lines to ensure non-fullscreen, maximized window on launch
    Config.set('graphics', 'fullscreen', 0)
    Config.set('graphics', 'borderless', 0)
    Config.set('graphics', 'window_state', 'maximized')

    Config.write()

    TestApp().run()
  

Это предупреждение, которое я получаю с показанным кодом:

 [WARNING] [Accordion   ] not enough space for displaying all children
[WARNING] [Accordion   ] need 132px, got 91px
[WARNING] [Accordion   ] layout aborted.
  

Хотя это те, которые являются результатом изменения всех значений size_hint на значения по умолчанию (1, 1):

 [WARNING] [Accordion   ] not enough space for displaying all children
[WARNING] [Accordion   ] need 88px, got 50px
[WARNING] [Accordion   ] layout aborted.
[WARNING] [Accordion   ] not enough space for displaying all children
[WARNING] [Accordion   ] need 132px, got 50px
[WARNING] [Accordion   ] layout aborted.
  

Ответ №1:

Причина, по которой вы получаете это предупреждение, заключается в том, что Accordion виджет запускает свой код компоновки до того, как будет установлен его фактический размер (обычно для Accordion ). Обратите внимание, что в сообщении говорится need 132px . Это потому, что минимальный размер по умолчанию для каждого элемента равен 44, а у вашего accord3 есть 3 дочерних элемента (3 раза по 44 равно 132). Там также говорится got 91px . Это потому, что начальный размер родительского элемента GridLayout равен 100 на 100 (как и для всех виджетов), и 0,09 от этого (или 9 пикселей) занимает Section 3 Label , оставляя 91 пиксель для Accordion . Поскольку 91 меньше 132, он решает, что недостаточно места. Исправлено, но вскоре после этого снова вызывается код компоновки с правильными значениями, и все в порядке. Было бы неплохо, если бы авторы этого кода могли устранить эти бессмысленные предупреждения.

Итак, вы можете избежать этих предупреждений, не добавляя свои Accordion виджеты в макет до тех пор, пока GridLayout не будет определен его реальный размер. для этого вы можете использовать Clock.schedule_once() . Вот модификация вашего TestApp использования этого подхода:

 class TestApp(App):
    def build(self):
        layout = BoxLayout(orientation="vertical")

        self.inner_layout = GridLayout(cols=3)
        self.inner_layout.add_widget(Label(text="Section 1", size_hint=(1, 0.09), font_size='20dp'))
        self.inner_layout.add_widget(Label(text="Section 2", size_hint=(1, 0.09), font_size='20dp'))
        self.inner_layout.add_widget(Label(text="Section 3", size_hint=(1, 0.09), font_size='20dp'))

        layout.add_widget(self.inner_layout)

        continue_btn = Button(text="START", size_hint=(1, 0.07))
        layout.add_widget(continue_btn)

        Clock.schedule_once(self.add_accordions)

        return layout

    def add_accordions(self, dt):

        accord1 = Accordion(orientation="vertical")
        accord1.add_widget(AccordionItem(title="Item 1"))
        accord1.add_widget(AccordionItem(title="Item 2"))

        accord2 = Accordion(orientation="vertical")
        accord2.add_widget(AccordionItem(title="Item 1"))

        accord3 = Accordion(orientation="vertical")
        accord3.add_widget(AccordionItem(title="Item 1"))
        accord3.add_widget(AccordionItem(title="Item 2"))
        accord3.add_widget(AccordionItem(title="Item 3"))

        self.inner_layout.add_widget(accord1)
        self.inner_layout.add_widget(accord2)
        self.inner_layout.add_widget(accord3)
  

Комментарии:

1. Большое вам спасибо! Это полностью отвечает на вопрос. Я не буду заморачиваться решением clock, поскольку чувствую, что создание части интерфейса позже, просто чтобы избежать бессмысленных предупреждений, будет более вредным, чем сами предупреждения. Жаль, что эти предупреждения все равно есть, как и при любом ложноположительном срабатывании. Еще раз спасибо!