Python/Kivy:如何放置动态标签小部件和值

3
我有两个文件test.pytest.kv
我运行test.py,然后显示show按钮。
当我点击show按钮时,会调用def abc。有人能告诉我如何在动态标签中显示数组和值(Item1=5000.Item2=1000)吗?
Item1 5000
Item2 1000

我正在使用数组
arr = ({'Item1': 5000},{'Item2': 1000})


test.py

from kivy.uix.screenmanager import Screen
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.properties import BooleanProperty, ListProperty, StringProperty, ObjectProperty, NumericProperty

Window.clearcolor = (0.5, 0.5, 0.5, 1)
Window.size = (600, 600)

class Invoice(Screen):
    def __init__(self, **kwargs):
        super(Invoice, self).__init__(**kwargs)

    def abc(self):
        #fetching from database
        arr = ({'Item1': 5000},{'Item2': 1000})
        print(arr)

class Test(App):

    def build(self):
        self.root = Builder.load_file('test.kv')
        return self.root


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

test.kv

<Button@Button>:
    font_size: 15
    font_name: 'Verdana'
    size_hint_y:None
    height: 30

<Label@Label>:
    font_size: 15
    font_name: 'Verdana'
    size_hint_y:None
    height: 30

Invoice:
    BoxLayout:
        orientation: "vertical"
        padding : 15, 15

        BoxLayout:
            orientation: "vertical"
            padding : 5, 5
            size_hint: .6, None
            pos_hint: {'x': .18,}


            BoxLayout:
                orientation: "horizontal"
                padding : 5, 5
                spacing: 10, 10
                size: 800, 40
                size_hint: 1, None

                Button:
                    text: "Show"
                    size_hint_x: .05
                    spacing_x: 30
                    on_press:root.abc()

        BoxLayout:
            orientation: "horizontal"
            size_hint: 1, 1

            BoxLayout:
                orientation: "vertical"
                size_hint: .5, 1
                padding : 0, 15
                spacing: 10, 10
                size: 500, 30

                Button:
                    text: "Invoice"
                    text_size: self.size
                    halign: 'center'
                    valign: 'middle'

                GridLayout:
                    cols: 2
                    #orientation: "horizontal"
                    padding : 5, 0
                    spacing: 10, 0
                    #size: 500, 30
                    size_hint: 1, 1
                    pos: self.pos
                    size: self.size

                    Label:
                        size_hint_x: .35
                        text: "Item1"
                        text_size: self.size
                        halign: 'left'
                        valign: 'middle'
                        canvas.before:
                            Color:
                                rgb: .6, .6, .6
                            Rectangle:
                                pos: self.pos
                                size: self.size

                    Label:
                        size_hint_x: .15
                        text: "5000"
                        text_size: self.size
                        halign: 'right'
                        valign: 'middle'
                        canvas.before:
                            Color:
                                rgb: .6, .6, .6
                            Rectangle:
                                pos: self.pos
                                size: self.size
2个回答

5

在你的abc()方法中,你可以创建标签并将它们添加到你的布局中。为了做到这一点,我对你的代码进行了一些更改。我给你的GridLayout添加了一个id属性,并将你的自定义标签类更改为MyLabel并将其添加到py文件中,以便我可以在Python中创建它们。这是修改后的Python文件:

from kivy.uix.label import Label
from kivy.uix.screenmanager import Screen
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window

Window.clearcolor = (0.5, 0.5, 0.5, 1)
Window.size = (600, 600)

class MyLabel(Label):
    pass

class Invoice(Screen):
    def __init__(self, **kwargs):
        super(Invoice, self).__init__(**kwargs)

    def abc(self):
        #fetching from database
        arr = ({'Item1': 5000},{'Item2': 1000})
        layout = self.ids['invoices']
        for invoice in arr:
            for key,val in invoice.items():
                lab1 = MyLabel(text=str(key),size_hint_x=.35, halign='left' )
                lab2 = MyLabel(text=str(val),size_hint_x=.15, halign='right' )
                layout.add_widget(lab1)
                layout.add_widget(lab2)

class Test(App):

    def build(self):
        self.root = Builder.load_file('test.kv')
        return self.root

对于 kv 文件的更改包括将 Label 更改为 MyLabel,尽可能多地移到 MyLabel 类中,并移除示例标签:

<Button@Button>:
    font_size: 15
    font_name: 'Verdana'
    size_hint_y:None
    height: 30

<MyLabel>:
    font_size: 15
    font_name: 'Verdana'
    size_hint_y:None
    height: 30
    text_size: self.size
    valign: 'middle'
    canvas.before:
        Color:
            rgb: .6, .6, .6
        Rectangle:
            pos: self.pos
            size: self.size

Invoice:
    BoxLayout:
        orientation: "vertical"
        padding : 15, 15

        BoxLayout:
            orientation: "vertical"
            padding : 5, 5
            size_hint: .6, None
            pos_hint: {'x': .18,}


            BoxLayout:
                orientation: "horizontal"
                padding : 5, 5
                spacing: 10, 10
                size: 800, 40
                size_hint: 1, None

                Button:
                    text: "Show"
                    size_hint_x: .05
                    spacing_x: 30
                    on_press:root.abc()

        BoxLayout:
            orientation: "horizontal"
            size_hint: 1, 1

            BoxLayout:
                orientation: "vertical"
                size_hint: .5, 1
                padding : 0, 15
                spacing: 10, 10
                size: 500, 30

                Button:
                    text: "Invoice"
                    text_size: self.size
                    halign: 'center'
                    valign: 'middle'

                GridLayout:
                    id: invoices
                    cols: 2
                    #orientation: "horizontal"
                    padding : 5, 0
                    spacing: 10, 0
                    #size: 500, 30
                    size_hint: 1, 1
                    pos: self.pos
                    size: self.size

4
尽管遍历数据并动态生成小部件的选项是可行的,但长期来看它是无法击败的。如果您拥有结构化信息,则适合使用设计模式,kivy提供了RecycleView用于这些情况,它实现了MVC模式,因此我们只需要传递数据并建立一个视图,一个适当的适配器就可以提供。
在您的情况下,设计一个小部件即可,该小部件显示在每一行中。
<Item@GridLayout>:
    cols: 2
    text: "" # new property
    value: 0 # new property
    padding : 5, 0
    spacing: 10, 0
    Label:
        size_hint_x: .35
        text: root.text
        halign: 'left'
        valign: 'middle'
        canvas.before:
            Color:
                rgb: .6, .6, .6
            Rectangle:
                pos: self.pos
                size: self.size

    Label:
        size_hint_x: .15
        text: str(root.value)
        halign: 'right'
        valign: 'middle'
        canvas.before:
            Color:
                rgb: .6, .6, .6
            Rectangle:
                pos: self.pos
                size: self.size

然后将 GridLayout 替换为 RecycleView:

RecycleView:
    id: rv
    viewclass: 'Item'
    RecycleBoxLayout:
        default_size: None, dp(30)
        default_size_hint: 1, None
        size_hint_y: None
        height: self.minimum_height
        orientation: 'vertical'

在按钮分配数据的情况下,您需要将数据转换为一个字典列表,其中字段将是Item的文本和值属性。请注意保留HTML标签。
def convert_data(data):
    l = []
    for item in data:
        for key, value in item.items():
            l.append({'text': key, 'value': value})
    return l

class Invoice(Screen):
    def abc(self):
        #fetching from database
        arr = ({'Item1': 5000},{'Item2': 1000})

        # convert to [{'text': 'Item1', 'value': 5000}, {'text': 'Item2', 'value': 1000}]
        self.rv.data = convert_data(arr)

完整代码:

main.py

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen

def convert_data(data):
    l = []
    for item in data:
        for key, value in item.items():
            l.append({'text': key, 'value': value})
    return l

class Invoice(Screen):
    def abc(self):
        #fetching from database
        arr = ({'Item1': 5000},{'Item2': 1000})

        # convert to [{'text': 'Item1', 'value': 5000}, {'text': 'Item2', 'value': 1000}]
        self.rv.data = convert_data(arr)

class MyApp(App):
    def build(self):
        return Builder.load_file('test.kv')

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

test.kv

<Button@Button>:
    font_size: 15
    size_hint_y:None
    height: 30

<Label@Label>:
    font_size: 15
    size_hint_y:None
    height: 30

<Item@GridLayout>:
    cols: 2
    text: ""
    value: 0
    padding : 5, 0
    spacing: 10, 0
    Label:
        size_hint_x: .35
        text: root.text
        halign: 'left'
        valign: 'middle'
        canvas.before:
            Color:
                rgb: .6, .6, .6
            Rectangle:
                pos: self.pos
                size: self.size

    Label:
        size_hint_x: .15
        text: str(root.value)
        halign: 'right'
        valign: 'middle'
        canvas.before:
            Color:
                rgb: .6, .6, .6
            Rectangle:
                pos: self.pos
                size: self.size

Invoice:
    rv: rv
    BoxLayout:
        orientation: "vertical"
        padding : 15, 15

        BoxLayout:
            orientation: "vertical"
            padding : 5, 5
            size_hint: .6, None
            pos_hint: {'x': .18,}


            BoxLayout:
                orientation: "horizontal"
                padding : 5, 5
                spacing: 10, 10
                size: 800, 40
                size_hint: 1, None

                Button:
                    text: "Show"
                    size_hint_x: .05
                    spacing_x: 30
                    on_press:root.abc()

        BoxLayout:
            orientation: "horizontal"
            size_hint: 1, 1

            BoxLayout:
                orientation: "vertical"
                size_hint: .5, 1
                padding : 0, 15
                spacing: 10, 10
                size: 500, 30

                Button:
                    text: "Invoice"
                    text_size: self.size
                    halign: 'center'
                    valign: 'middle'

                BoxLayout:
                    RecycleView:
                        id: rv
                        viewclass: 'Item'
                        RecycleBoxLayout:
                            default_size: None, dp(30)
                            default_size_hint: 1, None
                            size_hint_y: None
                            height: self.minimum_height
                            orientation: 'vertical'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接