【问题标题】:How do I lock the Y but not the X in a kv screen?如何在 kv 屏幕中锁定 Y 而不是 X?
【发布时间】:2020-05-10 16:55:42
【问题描述】:

我想构建一个屏幕,顶部有 6 个标签,顶部标签下方有 6 个输入,然后在输入下方生成无限数量的标签。 标签/输入的列+行应该相互对齐。

调整窗口大小时,每个的 X 应该会改变,但 Y 应该保持不变(为底部的其他标签留出空白空间)。为了更清楚,我模仿了 Excel 中的情况:

Window before resizing // Window after resizing

我尝试了网格布局(X 和 Y 总是随窗口调整大小 -> 不适用于我的想法)和浮动布局(定位所有内容(尤其是生成的标签)不可能是最好的解决方案。

不是寻找生成以下标签的逻辑。只是 .kv 中的布局。

更新:

在试验了@MisterNox 的代码后,我将它实现到我的测试项目中。当我单击“+”按钮添加行时,我遇到了两个顶行被推得更远导致第一行不可读的问题。

我的代码如下所示,应该是可重现的:

test_main.py:

import kivy
from kivy import Config
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import ObjectProperty
from kivy.graphics import Rectangle
from kivy.graphics import Color
from kivy.graphics import Line
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, TransitionBase, ShaderTransition, FadeTransition
from kivy.uix.popup import Popup
from kivy.clock import Clock
from kivy.core.window import Window
from kivy.animation import Animation
import time
import csv


Config.set('graphics', 'width', '1024')
Config.set('graphics', 'height', '768')

class WindowManager(ScreenManager):
    pass


class MyWindow(Screen):
    def __init__(self, **kwargs):
        super(MyWindow, self).__init__(**kwargs)
        Window.bind(width=self.on_window_width)

    def on_window_width(self, instance, value):
        self.ids.stock_list_layout.width = value
        for obj in self.ids.my_window.children:
            if isinstance(obj, Label):
                obj.width = value/6

    def do_something(self):
        print("HEL")
        self.ids.my_window.add_widget(Label(text="TEST", size_hint=(None, None), size=(Window.width/6, 35)))
        self.ids.my_window.add_widget(Label(text="TEST", size_hint=(None, None), size=(Window.width / 6, 35)))
        self.ids.my_window.add_widget(Label(text="TEST", size_hint=(None, None), size=(Window.width / 6, 35)))
        self.ids.my_window.add_widget(Label(text="TEST", size_hint=(None, None), size=(Window.width / 6, 35)))
        self.ids.my_window.add_widget(Label(text="TEST", size_hint=(None, None), size=(Window.width / 6, 35)))
        self.ids.my_window.add_widget(Label(text="TEST", size_hint=(None, None), size=(Window.width / 6, 35)))

class MainApp(App):
    def build(self):
        return kv



kv = Builder.load_file("testing.kv")

if __name__ == "__main__":
    MainApp().run()

testing.kv:

#:import Window kivy.core.window.Window
WindowManager:
    MyWindow:

<MyWindow>:
    GridLayout:
        id: my_window
        cols:6
        size_hint_y: None
        size_hint_x: None
        pos_hint:{"left":1,"top":1}
        width: Window.width

        Label:
            text:"LABEL"
            height: 35
            #size_hint:(0.16666,None)
        Label:
            height: 35
            #size_hint:(0.16666,None)
            text:"LABEL"
        Label:
            height: 35
            #size_hint:(0.16666,None)
            text:"LABEL"
        Label:
            height: 35
            #size_hint:(0.16666,None)
            text:"LABEL"
        Label:
            text:"LABEL"
            height: 35
            #size_hint:(0.16666,None)
        Label:
            text:"LABEL"
            height: 35
            #size_hint:(0.16666,None)

        TextInput:
            height: 35
            size_hint:(1,None)
        TextInput:
            height: 35
            size_hint:(1,None)
        TextInput:
            height: 35
            size_hint:(1,None)
        TextInput:
            height: 35
            size_hint:(1,None)
        Button:
            text:"+"
            on_release:
                root.do_something()

【问题讨论】:

    标签: python python-3.x kivy kivy-language


    【解决方案1】:

    我将为您提供一个 Gridlayout 的简短示例。 要在屏幕宽度发生变化时调整标签的宽度,您可以在 Window.width 上使用绑定方法。您仍然可以在 kv 中编写代码,只需在您的app 的 build 方法当然,这只是一个例子。

    每当窗口的宽度发生变化时,它都会调用回调方法,根据整体宽度调整标签宽度。然后你可以为标签设置一个高度。由于它现在是静态的,并且您没有设置高度绑定,因此即使它超出窗口视口,它也会保持不变。

    这是一个简短的代码 sn-ps 仅带有一些虚拟标签以向您展示该过程:

    示例:

    from kivy.app import App
    from kivy.uix.label import Label
    from kivy.uix.gridlayout import GridLayout
    from kivy.core.window import Window
    
    Window.size = 600, 400
    
    class MyApp(App):
        def build(self):
            self.columns = GridLayout(cols=5, size_hint_x=None, width=Window.width)
            for lbl in range(0,80):
                self.columns.add_widget(Label(text="Dummy", size_hint=(None, None), size=(Window.width/5, 50)))
            Window.bind(width=self.on_window_width)
    
            return self.columns
    
        def on_window_width(self, instance, value):
            self.columns.width = value
            for obj in self.columns.children:
                if isinstance(obj, Label):
                    obj.width = value/5
    
    
    MyApp().run()
    

    [更新]

    正如您要求的 kv 集成,这里与上面的示例基本相同,只是有一些 kv 集成。基本上你可以将标签/文本输入集成到 kv 字符串中,但我只是想添加很多虚拟标签,所以我在我的 python 代码中保留了这个动作。

    不同之处在于我为 Gridlayout 分配了一个 ID,以便在我的 python 代码中使用self.ids.id_name 轻松访问它。

    绑定说明

    关于绑定方法,这是一个监听分配属性变化的方法,如果发生变化,它会触发回调方法。

    以我的例子Window.bind(width=self.on_window_width):调用该方法的对象是具有您要查找的属性的对象。在我们的例子中,我们想要寻找窗口宽度的变化。这就是为什么 Window 是我们的代理对象。在括号内,您将首先命名属性,然后是发生更改时应触发的回调方法。

    回调方法需要三个属性,self(方法所属的对象)、实例(在我们的例子中是 Window)和我们在 bind 方法中监听的属性的更改值。然后你可以用这个值做任何你想做的事情。我们调整标签的宽度,让它们与窗口一起展开。希望我解释得足够好。

    from kivy.app import App
    from kivy.uix.label import Label
    from kivy.core.window import Window
    from kivy.lang.builder import Builder
    from kivy.uix.screenmanager import Screen, ScreenManager
    
    Window.size = 600, 400
    
    kv = """
    #:import Window kivy.core.window.Window
    
    <MyScreen>:
        name: 'first'
        GridLayout:
            id: columns
            cols: 5
            size_hint_x: None
            width: Window.width
    
    """
    
    class MyScreen(Screen):
        def __init__(self, **kwargs):
            super(MyScreen, self).__init__(**kwargs)
    
            for lbl in range(0,80):
                self.ids.columns.add_widget(Label(text="Dummy", size_hint=(None, None), size=(Window.width/5, 50)))
            Window.bind(width=self.on_window_width)
    
        def on_window_width(self, instance, value):
            self.ids.columns.width = value
            for obj in self.ids.columns.children:
                if isinstance(obj, Label):
                    obj.width = value/5
    
    
    class MyApp(App):
        def build(self):
            Builder.load_string(kv)
    
            WMan = ScreenManager()
            myscreen = MyScreen()
    
            WMan.add_widget(myscreen)
    
            return WMan
    
    
    MyApp().run()
    

    【讨论】:

    • 我在我的 kv 中尝试过:GridLayout: width: root.on_window_width(该方法在屏幕类中)。这似乎不起作用,因为 on_window_width 不返回宽度。另外,我不太了解您示例中的Window.bind... 步骤,您能详细说明一下吗? -> 请原谅我的困惑,我是新手 :)
    • 我添加了一个使用 kv 集成的示例,并尝试以适当的方式解释绑定方法。希望对您有所帮助。
    • 很好的例子!我对您的代码进行了一些试验,并设法将其构建到我的项目中。现在我遇到的问题是,通过“+”按钮添加 1 行(或更多)行后,第一个行相互合并。我将在我的主要帖子中提供示例代码。
    • 抱歉耽搁了,这是因为您在添加新的标签行时必须调整布局的高度。在您的 MyWindow 类中编写一个方法,例如 def adjust_height(self, widget): widget.height = widget.height + 35。 35 是因为您新添加的行的高度为 35。然后将此 self.adjust_height(self.ids.my_window) 添加到您的 do_something 方法中。还有一件事,您应该检查您的代码,因为当您更改窗口大小时它会抛出大量错误消息。
    猜你喜欢
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-09
    • 2020-03-10
    • 1970-01-01
    • 2015-12-02
    相关资源
    最近更新 更多