首页 > 解决方案 > Kivy(Python):如何根据其子项更改 BoxLayout 高度?

问题描述

我在 Kivy 中编写了一个新闻应用程序,该应用程序从网站的首页获取文章并使其在应用程序中可见。根据文章的长度,段落的大小和数量可能会有所不同。由于它使用 BS4 webscraper 来提取网站的内容,因此整个 gui 编程都是在 python 中进行的,而不是在 .kv 语言中。所以,我的问题是,我怎样才能停止Image在屏幕上保留空间(我希望标签总是在它下面)以及如何根据它的孩子来改变heightaBoxLayout的空间,以便所有人都有足够的空间,但是不要太多。

这是我的代码的简化版本,它演示了我的问题。在此示例中,a 的高度BoxLayout设置为1000dp适合大约 4 段,但如果有更多,它将变得混乱。有没有办法避免这个问题?任何帮助都会很有用。

from kivymd.app import MDApp
from kivy.uix.boxlayout import BoxLayout
from kivymd.uix.label import MDLabel
from kivy.uix.screenmanager import Screen
from kivy.uix.scrollview import ScrollView
from kivy.uix.image import AsyncImage


class RootWidget(Screen):
    def __init__(self, **kw):
        super().__init__(**kw)
        self.update()

    def update(self):
        paragraphs_text = ["Lorem ipsum dolor sit amet,", "consectetur adipiscing elit, sed do eiusmod tempor incididunt ut"
                      " labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco "
                      "laboris nisi ut aliquip ex ea commodo consequat.", "Duis aute irure dolor in reprehenderit in"
                      " voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat "
                      "non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."]

        header_text = "Lorem ipsum dolor sit amet"

        header_image_src = "images/Cariboo_Peaks.jpg"

        date_of_publishing_text = "03.05.2020"

        scroll_widget_holder = ScrollView()
        widget_holder = BoxLayout(orientation="vertical", size_hint_y=None, padding=5)

        # minimum_height doesnt work in python, only in .kv language so is there a way to get the height automatically?
        # 1000dp works fine for this amount of paragrpahs but i there was twice as many as there are now it would all
        # become to cludderd and the image would be very small
        # on the other hand, if I make this number too big the wigets are too far apart from each other
        # So how can I fix this?
        widget_holder.height = "1000dp"

        header_image = AsyncImage(source=header_image_src, size_hint=(1, 1),
                                  allow_stretch=False, keep_ratio=True)

        header_label = MDLabel(text=header_text, size_hint_y=None, font_style="H6")

        # Thats what I came up with, if there is a better way of automatically asigning the height of a widget based
        # on its contents please let me know
        header_label.height = str(len(header_label.text)) + "dp"

        # This label is supossed to be right unter the header label(see the screens below to see my go to result created
        # in photoshop)
        header_date_label = MDLabel(text=date_of_publishing_text, size_hint_y=None, font_style="Caption", height="10dp")

        widget_holder.add_widget(header_image)
        widget_holder.add_widget(header_label)
        widget_holder.add_widget(header_date_label)

        for paragraph in paragraphs_text:
            text_paragraph = MDLabel(text=paragraph, size_hint_y=None,
                                     pos_hint={"center_x": .5}, halign="justify")
            text_paragraph.height = str(len(text_paragraph.text)) + "dp"

            widget_holder.add_widget(text_paragraph)

        scroll_widget_holder.add_widget(widget_holder)
        self.add_widget(scroll_widget_holder)


class TestApp(MDApp):
    def build(self):
        return RootWidget()


if __name__ == '__main__':
    TestApp().run()

标签: pythonuser-interfacekivy

解决方案


BoxLayout您可以通过添加所有子项(包括paddingspacing)的高度来计算自己的高度。如果您在update方法期间添加子项时知道(或设置)子项的高度,则可以使用以下方法设置高度:

widget_holder.height = new_height

new_height上面计算的总和在哪里。如果您不知道孩子的身高,您可以执行以下操作:

def adjust_height(self, box, dt):
    # this does not handle padding and spacing
    new_height = 0
    for child in box.children:
        new_height += child.height
    box.height = new_height

您可以在update()方法结束时将其称为:

    Clock.schedule_once(partial(self.adjust_height, widget_holder))

推荐阅读