【问题标题】:Overlapping of custom Widget in ScrollView GridLayout in KivyKivy 中 ScrollView GridLayout 中自定义 Widget 的重叠
【发布时间】:2020-03-21 15:12:39
【问题描述】:

这是我想在我的最终项目中实现的试用代码。

Python 代码:

import kivy
kivy.require('1.0.6') 
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder

class Wid(BoxLayout):

    def settxt(self,i):
        lab = self.ids['lab']
        but = self.ids['but']
        lab.text = "Label Number {}".format(i)
        but.text = "Button Number {}".format(i)


class Win1(Screen):
    i=0
    def addw(self):
        box1 = self.ids['box1']
        self.i = self.i +1
        w = Wid()
        w.settxt(self.i)
        box1.add_widget(w)

    def switch(self):
        sm.current="win2"


class Win2(Screen):
    def switch(self):
        sm.current="win1"

class WindowManager(ScreenManager):
    pass

kv = Builder.load_file("test.kv")
sm = WindowManager()

screens = [Win1(name="win1"), Win2(name="win2")]
for screen in screens:
    sm.add_widget(screen)

sm.current = "win1"

class Test(App):

    def build(self):
        return sm

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

基维代码:

<Wid>:
    lab:lab
    but:but
    BoxLayout:
        height: self.minimum_height
        size: root.size
        Label:
            id: lab

        Button:
            id: but


<Win1>
    name:"win1"
    box1:box1
    BoxLayout:
        height: self.minimum_height
        orientation: "vertical"
        BoxLayout:
            size_hint: 1,0.2
            Button:
                text:"window 2"
                on_release:
                    root.switch()

            Button:
                text:"add wid"
                on_release:
                    root.addw()

        ScrollView:
            GridLayout:
                id:box1
                orientation: "vertical"
                spacing: 2
                size_hint_y: None
                height: self.minimum_height  
                row_default_height: 60
                cols:1

<Win2>
    name: "win2"

    BoxLayout:
        id: bl

        height: bl.minimum_height
        size_hint_y: None
        Button:
            text:"window 2"
            on_release:
                root.switch()

按下开关后,我希望我的自定义小部件能够进入滚动视图中的网格布局,一个在另一个之下。但相反,每个新小部件都出现在布局的最后一个单元格中,并与前一个单元格重叠,空单元格继续在它们上方形成。 不知道哪里出错了。

【问题讨论】:

    标签: python widget kivy scrollview overlap


    【解决方案1】:

    在这里,我将 kv 移到了一个单独的文件中,并动态创建了屏幕。 要点:我在 on_start 中动态添加屏幕,这是在构建完成之后。我在 kv 中创建 ScreenManager,并使用 id 添加屏幕。在 kv 代码中,我将 ScreenManger 放在 BoxLayout 中。这是个人喜好。我这样做是为了在访问对象时根小部件不是屏幕管理器。因此在 switch() 方法中,寻址使用分配的 id,而不是依赖于 root 小部件作为屏幕管理器。

    FWIW:如果切换代码仅用于更改屏幕,我会将这些单行移至 KV。

    import kivy
    
    kivy.require('1.0.6')
    from kivy.app import App
    from kivy.lang import Builder
    from kivy.uix.boxlayout import BoxLayout
    from kivy.uix.screenmanager import Screen
    
    
    class Wid(BoxLayout):  # Change to layout
        def settxt(self, i):
            lab = self.ids['lab']
            but = self.ids['but']
            lab.text = "Label Number {}".format(i)
            but.text = "Button Number {}".format(i)
    
    
    class Win1(Screen):
        i = 0
    
        def addw(self):
            box1 = self.ids['box1']
            self.i = self.i + 1
            w = Wid()
            w.settxt(self.i)
            box1.add_widget(w)
    
        @staticmethod
        def switch():
            app = App.get_running_app()
            app.root.ids.sm.current = "win2"
    
    
    class Win2(Screen):
        @staticmethod
        def switch():
            app = App.get_running_app()
            app.root.ids.sm.current = "win1"
    
    
    class WidgetQ1App(App):
        def build(self):
            return Builder.load_file('widgetq.kv')
    
        def on_start(self):
            screens = [Win1(name="win1"), Win2(name="win2")]
            sm = self.root.ids.sm
            for screen in screens:
                sm.add_widget(screen)
    
    
    WidgetQ1App().run()
    

    还有KV代码:

    <Wid>:               # Put widgets in a layout, not a widget.
        lab:lab
        but:but
        BoxLayout:
            size: root.size
            Label:
                id: lab
    
            Button:
                id: but
    
    
    <Win1>
        # name:"win1"
        box1:box1
        BoxLayout:
            orientation: "vertical"
            BoxLayout:
                size_hint: 1,0.2
                Button:
                    text:"window 2"
                    on_release:
                        root.switch()
    
                Button:
                    text:"add wid"
                    on_release:
                        root.addw()
    
            ScrollView:
                GridLayout:
                    id:box1
                    orientation: "vertical"
                    spacing: 2
                    size_hint_y: None
                    height: self.minimum_height
                    row_default_height: 60
                    cols:1
    
    <Win2>:
        # name: "win2"
        BoxLayout:
            Button:
                text:"window 2"
                on_release:
                    root.switch()
    BoxLayout:
        ScreenManager:
            id: sm
    

    【讨论】:

    • 谢谢,现在代码可以正常工作了。但是我仍然不知道我的代码是如何错误的,或者动态屏幕有什么帮助。当使用同时使用 on_pre_enter() 的屏幕时,此方法是否有效?
    • 原始代码中最大的问题是使用了类 Wid(Widget)。您将对象放入 Widget 中,而不是放入布局中。我在 Python 中创建了屏幕以匹配您在原始代码中所做的。您可以将 on_pre_enter= 添加到屏幕构造函数中,就像您对屏幕名称所做的那样。放入kv中的画面定义。您可以将屏幕的实例移动到 kv。
    【解决方案2】:
    <win2>
        name: "win2"
        size_hint_y: None
        height: bl.minimum_height
        BoxLayout:
            id: bl
            Button:
                text:"window 2"
                on_release:
                    root.switch()
    

    您的自定义小部件没有定义高度,请尝试更改为上述内容。

    另外,以大写字母开头你的类名,在某些情况下 kv 需要这个。例如,win2 应该是 Win2

    【讨论】:

    • 感谢您的建议,我已对类名和高度进行了必要的更改。不过,这些小部件是重叠的。
    • 已更新,当我尝试不带 * size:size.root* 的代码时,BoxLayout 中有我的自定义小部件的双重实例化。
    • 根据您更新的代码,您还没有完成我解释的修复。
    • 请尝试运行更新代码,出现双重实例化问题。
    【解决方案3】:

    这里有很多问题,请参阅 cmets。我看到的最大问题是将项目放入小部件中。将小部件放在布局中,而不是其他小部件。

    import kivy
    kivy.require('1.0.6')
    from kivy.app import App
    from kivy.uix.boxlayout import BoxLayout
    from kivy.uix.screenmanager import Screen
    from kivy.lang import Builder
    
    kv = """
    <Wid>:               # Put widgets in a layout, not a widget.
        lab:lab
        but:but
        BoxLayout:
            size: root.size
            Label:
                id: lab
    
            Button:
                id: but
    
    
    <Win1>
        # name:"win1"
        box1:box1
        BoxLayout:
            orientation: "vertical"
            BoxLayout:
                size_hint: 1,0.2
                Button:
                    text:"window 2"
                    on_release:
                        root.switch()
    
                Button:
                    text:"add wid"
                    on_release:
                        root.addw()
    
            ScrollView:
                GridLayout:
                    id:box1
                    orientation: "vertical"
                    spacing: 2
                    size_hint_y: None
                    height: self.minimum_height  
                    row_default_height: 60
                    cols:1
    
    <Win2>:
        # name: "win2"
        BoxLayout:
            Button:
                text:"window 2"
                on_release:
                    root.switch()
    ScreenManager:
        id: sm
        Win1:
            name: 'win1'
        Win2:
            name: 'win2'
    
    """
    
    
    class Wid(BoxLayout):       # Change to layout
        def settxt(self,i):
            lab = self.ids['lab']
            but = self.ids['but']
            lab.text = "Label Number {}".format(i)
            but.text = "Button Number {}".format(i)
    
    
    class Win1(Screen):
        i = 0
    
        def addw(self):
            box1 = self.ids['box1']
            self.i = self.i + 1
            w = Wid()
            w.settxt(self.i)
            box1.add_widget(w)
    
        @staticmethod
        def switch():
            app = App.get_running_app()
            app.root.current = "win2"
    
    
    class Win2(Screen):
        @staticmethod
        def switch():
            app = App.get_running_app()
            app.root.current = "win1"
    
    # class WindowManager(ScreenManager):
    #     pass
    
    # kv = Builder.load_file("test.kv")
    # sm = WindowManager()
    #
    # screens = [win1(name="win1"), win2(name="win2")]
    # for screen in screens:
    #     sm.add_widget(screen)
    #
    # sm.current = "win1"
    
    
    class WidgetQApp(App):
        def build(self):
            return Builder.load_string(kv)
    
    
    WidgetQApp().run()
    

    【讨论】:

    • 您的代码可以完美运行,我希望我的代码应该可以运行。现在,我已经做出了您在 cmets 中指示的更改,现在没有重叠,但在我的小部件中有一个空白框布局的额外实例化。请尝试运行我的代码亲自查看。
    • 发布您的更新代码。您想对我发布的代码进行哪些更改?
    • 我已经更新了问题本身的代码。实际上,我正在测试自定义小部件,以便稍后在我的实际项目中使用。实际项目使用字符串加载器方法很大,所以我想使用单独的 .kv 文件方法。
    • 我已经回复了另一个答案。
    猜你喜欢
    • 1970-01-01
    • 2014-12-28
    • 1970-01-01
    • 1970-01-01
    • 2021-01-29
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多