【问题标题】:Kivy Popup Dynamic HeightKivy 弹出窗口动态高度
【发布时间】:2018-11-05 04:00:14
【问题描述】:

我希望在 python 端制作一个具有动态高度的弹出窗口。

到目前为止,我在屏幕__init__ 类中有这个。 kv 文件有另一个称为弹出 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()

弹出框大小设置为仅适合一个小部件,而使第二个按钮(以及可能包含的所有其他按钮)浮动超出弹出框边框的范围。

我应该如何更改代码以使所有小部件都适合弹出窗口的范围?我正在尝试通过动态设置弹出窗口的高度来做到这一点,但事实证明这并不有效。

【问题讨论】:

  • 不确定“不起作用”是什么意思,请更具体。但我看到的一件事是self.p 一次只能引用一个Popup,那么您目前如何尝试创建第二个Popup。请提供MCVE
  • @JohnAnderson,我已将问题更新为更具体。本质上,小部件浮动在弹出窗口的边界之外。我想设置弹出窗口的高度,使其适合其中的小部件,并且我想动态地执行此操作,以防其他小部件添加到弹出窗口中。

标签: python kivy


【解决方案1】:

我已经修改了你的代码来做我认为你想要的。基本上,它将GridLayout 中的minimum_height 添加到Popup,添加到title 和分隔条的计算高度。 GridLayout 中的第一个 Button 现在将另一个 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 的显示方式,有点作弊。因此,如果其中任何一项发生更改,这可能无法正常工作。

【讨论】:

  • 我正在通过检查器查看弹出窗口,还注意到它有三个子项(弹出标签、线条的小部件,然后是包含其内容的框布局)。我认为解决方案需要在这些孩子之间循环并增加他们的身高,所以这作为一个解决方案是有意义的。对我来说,我可能会将fix_size()get_popup_title_height() 结合起来作为我的代码。谢谢你的手!
【解决方案2】:

我找到了解决受约翰安德森回答影响的原始问题的解决方案。我将在下面提供一个演练,说明我是如何得出这个解决方案的。

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()

OP 的显着变化:

  • 将小部件容器的minimum_height绑定到fix_popup_height()函数;这将在每次将小部件添加到弹出窗口时触发。

  • 在屏幕类中声明fix_popup_height()

这是固定的弹出窗口:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-20
    • 2019-02-21
    • 1970-01-01
    • 2014-09-23
    • 1970-01-01
    • 1970-01-01
    • 2020-10-22
    • 2018-02-13
    相关资源
    最近更新 更多