Я нашел решение для моей первоначальной проблемы, на которое повлиял ответ Джона Андерсона. Ниже я расскажу, как я пришел к этому решению.
1) Вот фото моей оригинальной задачи; Мне нужно было динамически установить высоту всплывающего окна на основе назначенных ему виджетов. Прежде чем найти приведенное ниже решение, мое всплывающее окно выглядело так с кодом в OP:
Как видите, виджеты выходят за границы всплывающего окна.
2) Я нашел что-то интересное, просматривая всплывающий виджет с помощью инструмента инспектора.
python '/path/to/your/file.py' -m inspector
Используя control-e, я могу щелкать виджеты и проверять их атрибуты. Я нажимал на всплывающую кнопку и переключался между родительскими виджетами, пока не нашел всплывающий виджет.
Как видно на фотографии, у всплывающего виджета есть один дочерний элемент: макет сетки. Вот дети этой сетки:
Интересно, что сетка содержит:
Одна этикетка высотой 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()
Заметные изменения по сравнению с ОП:
Вот исправленное всплывающее окно: