【问题标题】:Kivy: size of layout doesn't update on app startKivy:布局大小不会在应用启动时更新
【发布时间】:2020-08-28 19:33:48
【问题描述】:

我对 kivy 和 python 很陌生,这里的第一个问题......所以,如果复选框为空,我想隐藏布局,以控制大小和不透明度属性。如果您使用复选框,它会按预期工作,但是当应用程序运行时,会有空白空间。我尝试使用构造函数和 schedule_once 函数将 size 更改为 [0,0],看起来 size 属性发生了变化,但屏幕截图中仍然有一个空白区域。

附: 我有一个假设,这个问题与 kv 文件有关,因为我试图为这个问题创建一个简约的例子,而且......工作正常,只使用 main.kv 和 main.py。

import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.clock import Clock
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager

kivy.require('1.11.0')

kv = """
#:import utils kivy.utils

<ValuesGridLayout@GridLayout>:
    cols: 1
    row_default_height: 30
    size_hint_y: None
    height: self.minimum_height
    spacing: 3

<MainPanelLabel@Label>:
    text_size: self.size
    valign: "middle"
    padding_x: 5
    text: "Some content"

<MainPanel>:
    kinetic_container: kinetic_container
    thread_container: thread_container
    padding: 20, 20, 20, 0
    BoxLayout:
        orientation: 'vertical'
        BoxLayout:
            ScrollView:
                GridLayout:
                    padding: [0, 10]
                    cols: 1
                    spacing: 30
                    size_hint_y: None
                    height: self.minimum_height

                    BoxLayout:
                        CheckBox:
                            size_hint: (None, None)
                            size: [20,20]
                            on_active:
                                root.toggleParameters(self.active, root.kinetic_container)

                        MainPanelLabel:
                            text: "Kinetic values:"
                            color: utils.get_color_from_hex('#f6711b')
                            font_size: '20sp'

                    ValuesGridLayout:
                        id: kinetic_container
                        visible: False
                        size: [500, 200] if self.visible else [0, 0]
                        opacity: 1 if self.visible else 0
                        disabled: not self.visible

                        MainPanelLabel
                        MainPanelLabel
                        MainPanelLabel
                        MainPanelLabel
                        MainPanelLabel
                        MainPanelLabel

                    BoxLayout:
                        CheckBox:
                            padding: 20
                            size_hint: (None, None)
                            size: [20,20]
                            on_active:
                                root.toggleParameters(self.active, root.thread_container)

                        MainPanelLabel:
                            text: "Thread values:"
                            color: utils.get_color_from_hex('#f6711b')
                            font_size: '20sp'

                    ValuesGridLayout:
                        id: thread_container
                        visible: False
                        size: [500, 200] if self.visible else [0, 0]
                        opacity: 1 if self.visible else 0
                        disabled: not self.visible

                        MainPanelLabel
                        MainPanelLabel
                        MainPanelLabel
                        MainPanelLabel
                        MainPanelLabel

<MainFrame>:
    id: screen_manager
    Screen:
        name: "Initial"
        MainPanel

"""


class MainPanel(BoxLayout):
    def __init__(self, **kwargs):
        super(MainPanel, self).__init__(**kwargs)
        Clock.schedule_once(lambda dt: self.initializeSize(), 0)

    def toggleParameters(self, instance, object):
        if instance:
            object.visible = True
        else:
            object.visible = False

    def initializeSize(self):
        self.kinetic_container.size = [0, 0]
        self.thread_container.size = [0, 0]


class MainFrame(ScreenManager):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)


class SomeApp(App):
    def build(self):
        return MainFrame()


if __name__ == "__main__":
    Builder.load_string(kv)
    SomeApp().run()

提前致谢!

【问题讨论】:

  • 我查看了源代码,您正在使用混合制表符/空格格式,这可能会导致问题。因此,它也无法从 UI 中读取。考虑将代码也采用这种格式,这将有助于您不必记住 4 个文件:github.com/kivy/kivy/wiki/…
  • @JurajFiala 感谢您的更正、指导和时间,我已经更新了代码。
  • 如果问题仍然存在,请尝试制作一个 MCVE:stackoverflow.com/help/minimal-reproducible-example。它甚至可以帮助您解决过程中的问题。
  • 不幸的是,问题仍然存在:c

标签: python checkbox kivy toggle kivy-language


【解决方案1】:

我不确定 究竟是什么导致了错误的行为,但这是罪魁祸首。

<ValuesGridLayout@GridLayout>:
    size_hint_y: None
    height: self.minimum_height
    ...

在这里您将高度设置为self.minimum_height。但是当您使用小部件时,您会覆盖它:

ValuesGridLayout:
    id: kinetic_container
    size: [500, 200] if self.visible else [0, 0]
    ...

(注意:设置宽度实际上并没有做任何事情,因为size_hint_x 仍然是 1。)

推测:属性仅在值不同时才调度事件。当我尝试调试它时,在应用程序启动时首先调用height 的类定义,然后是实例定义,然后再次调用类定义。如果您使用 self.minimum_height 而不是 200,它会起作用,所以看起来由更改分派的事件在初始小部件设置期间触发了某些东西。

解决方案

您可以将所有属性移动到类规则中:

<ValuesGridLayout@GridLayout>:
    visible: False
    size_hint_y: None
    height: self.minimum_height if self.visible else 0
    opacity: 1 if self.visible else 0
    disabled: not self.visible
    cols: 1
    row_default_height: 30
    spacing: 3

现在你只需要

ValuesGridLayout:
    id: kinetic_container
    MainPanelLabel
    ...

ValuesGridLayout:
    id: thread_container
    MainPanelLabel
    ...

就是这样。

额外提示:

  • size, padding (ReferenceListProperty's) 使用元组,所以你可以只做size: 200, 500
  • 你不需要root.kinetic_container,只需kinetic_container就可以了,id的范围见docs
  • toggleParameters() 是不必要的,你可以这样做 on_active: kinetic_container.visible = self.active
  • 不要定义一个空的__init__(),而是这样做
    class MainFrame(ScreenManager):
        pass
    

黑客愉快!

【讨论】:

  • @NobleFox,如果这个答案有帮助,如果您将其标记为已接受,我将不胜感激。 :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-03
  • 2013-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多