Kivy中ScrollView GridLayout中自定义Widget的重叠

Overlapping of custom Widget in ScrollView GridLayout in Kivy

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

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

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

<win2>
    name: "win2"
    size_hint_y: None
    height: bl.minimum_height
    BoxLayout:
        id: bl
        Button:
            text:"window 2"
            on_release:
                root.switch()

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

此外,class 名称以大写字母开头,kv 在某些情况下需要这样做。例如,win2 应该是 Win2.

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

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

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

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