Kivy Popup Динамическая Высота - PullRequest
0 голосов
/ 05 ноября 2018

Я хочу сделать всплывающее окно на стороне Python, которое имеет динамическую высоту.

Пока у меня это есть в классе __init__. В файле kv есть еще один виджет, который называется popup on_release. Во всяком случае, я обнаружил, что это производит всплывающее окно с очень шатким форматированием:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import Screen, ScreenManager

kv = '''

ScreenManagement:
    id: 'manager'
    BrokenPopup:
        name: 'broken'
        manager: 'manager'

<BrokenPopup>:
    BoxLayout:
        Button:
            text: 'Test'
            on_release: root.p.open()

'''

class ScreenManagement(ScreenManager):
    pass

class BrokenPopup(Screen):

    def __init__(self, **kwargs):
        super(BrokenPopup,self).__init__(**kwargs)

        self.p = Popup(auto_dismiss=False, size_hint_x=.6, size_hint_y=None, title='A popup')
        self.g = GridLayout(cols=1, spacing=10)
        self.g.add_widget(Button(text='Test1', size_hint_y=None, height=32))
        self.g.add_widget(Button(text='Test2', size_hint_y=None, height=32))
        self.g.bind(minimum_height=self.g.setter('height'))
        self.p.add_widget(self.g)
        self.p.bind(height=self.g.setter('height')) #<- this does not work to change the popup height!

class TheApp(App):

    def build(self):
        return Builder.load_string(kv)

TheApp().run()

Размер всплывающего окна устанавливается для размещения только одного виджета, оставляя вторую кнопку (и все остальные, которые могут быть включены), чтобы она выходила за пределы границы всплывающего окна.

Как мне изменить код, чтобы все виджеты вписывались в рамки всплывающего окна? Я пытаюсь сделать это, динамически устанавливая высоту всплывающего окна, однако это не оказывается эффективным.

Ответы [ 2 ]

0 голосов
/ 09 ноября 2018

Я нашел решение для моей первоначальной проблемы, на которое повлиял ответ Джона Андерсона. Ниже я расскажу, как я пришел к этому решению.

1) Вот фото моей оригинальной задачи; Мне нужно было динамически установить высоту всплывающего окна на основе назначенных ему виджетов. Прежде чем найти приведенное ниже решение, мое всплывающее окно выглядело так с кодом в OP:

Original popup with a height error.

Как видите, виджеты выходят за границы всплывающего окна.

2) Я нашел что-то интересное, просматривая всплывающий виджет с помощью инструмента инспектора.

python '/path/to/your/file.py' -m inspector

Используя control-e, я могу щелкать виджеты и проверять их атрибуты. Я нажимал на всплывающую кнопку и переключался между родительскими виджетами, пока не нашел всплывающий виджет.

enter image description here

Как видно на фотографии, у всплывающего виджета есть один дочерний элемент: макет сетки. Вот дети этой сетки:

enter image description here

Интересно, что сетка содержит:

  • Одна этикетка высотой 33

  • Одна строка высотой 4

  • Макет коробки, в котором содержится содержимое всплывающего окна

  • 2 единицы расстояния между этими тремя виджетами

  • 12 единиц заполнения по всем направлениям; Итак, 24 дополнительных единицы для учета высоты

3) В моем решении я жестко написал высоту по умолчанию для метки, виджета строки и все значения по умолчанию для всплывающих окон и отступов. Затем я перебираю детей в макете блока и добавляю их высоты. Я также добавляю 10 к этим дочерним высотам, так как разметка сетки, которая содержит все эти виджеты, использует интервал 10.


Решение:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import Screen, ScreenManager

kv = '''

ScreenManagement:
    id: 'manager'
    BrokenPopup:
        name: 'broken'
        manager: 'manager'

<BrokenPopup>:
    BoxLayout:
        Button:
            text: 'Test'
            on_release: root.p.open()

'''

class ScreenManagement(ScreenManager):
    pass

class BrokenPopup(Screen):

    def __init__(self, **kwargs):
        super(BrokenPopup,self).__init__(**kwargs)

        self.p = Popup(auto_dismiss=False, size_hint_x=.6, size_hint_y=None, title='A popup')
        self.g = GridLayout(cols=1, spacing=10, padding=[0,10,0,-5])
        self.g.bind(minimum_height=self.fix_popup_height) # <- here's the magic
        self.g.add_widget(Button(text='Test1', size_hint_y=None, height=32))
        self.g.add_widget(Button(text='Test2', size_hint_y=None, height=32))
        self.p.add_widget(self.g)


    def fix_popup_height(self, grid, *args):
        # a generalized function that, when bound to minimum_height for a grid with popup widgets,
        # this will set the height of the popup
        height = 0
        height += 33    # for popup label
        height += 4     # for popup line widget
        height += 24    # for popup padding
        height += 2     # for spacing between main popup widgets
        for child in grid.children:
            height += child.height + 10 # adds 10 for the spacing between each child
        grid.parent.parent.parent.height = height # sets popup height
        pass


class TheApp(App):

    def build(self):
        return Builder.load_string(kv)

TheApp().run()

Заметные изменения по сравнению с ОП:

  • Привязать minimum_height контейнера виджетов к функции fix_popup_height(); это будет срабатывать при каждом добавлении виджета во всплывающее окно.

  • Объявите fix_popup_height() в классе экрана.

Вот исправленное всплывающее окно:

enter image description here

0 голосов
/ 06 ноября 2018

Я изменил ваш код, чтобы сделать то, что я думаю, что вы хотите. По сути, он добавляет minimum_height из GridLayout, который добавляется к вашему Popup, к вычисленной высоте title и разделительной планке. Первый Button в GridLayout теперь добавляет еще Button к GridLayout для тестирования.

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import Screen, ScreenManager

kv = '''

ScreenManagement:
    id: 'manager'
    BrokenPopup:
        name: 'broken'
        manager: 'manager'

<BrokenPopup>:
    BoxLayout:
        Button:
            text: 'Test'
            on_release: root.p.open()

'''


class ScreenManagement(ScreenManager):
    pass


class BrokenPopup(Screen):

    def __init__(self, **kwargs):
        super(BrokenPopup,self).__init__(**kwargs)

        self.popup_title_height = None
        self.p = Popup(auto_dismiss=False, size_hint_x=.6, size_hint_y=None, title='A popup')
        self.g = GridLayout(cols=1, spacing=10)
        self.g.bind(minimum_height=self.fix_size)
        self.g.add_widget(Button(text='Test1', size_hint_y=None, height=32, on_release=self.add_one))
        self.g.add_widget(Button(text='Test2', size_hint_y=None, height=32))
        self.p.add_widget(self.g)


    def add_one(self, *args):
        self.g.add_widget(Button(text='Another', size_hint_y=None, height=32))


    def get_popup_title_height(self):
        height = 0
        popupGrid = self.p.children[0]
        height += popupGrid.padding[1] + popupGrid.padding[3]
        for child in popupGrid.children:
            if isinstance(child, BoxLayout):
                continue
            else:
                height += child.height + popupGrid.spacing[1]
        self.popup_title_height = height


    def fix_size(self, *args):
        if self.popup_title_height is None:
            self.get_popup_title_height()
        self.p.height = self.g.minimum_height + self.popup_title_height


class TheApp(App):

    def build(self):
        return Builder.load_string(kv)

TheApp().run()

Я немного обманул, посмотрев код для Popup и файл style.kv, чтобы увидеть, как отображается Popup. Так что, если что-то из этого будет изменено, это может не сработать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...