如何在Kivy .kv文件中使用for循环创建标签?

时间:2019-10-10 12:08:23

标签: python kivy kivy-language

我正在使用Kivy开发PDF解析应用程序。我在.py文件中使用屏幕管理器。在其中一个屏幕中,我选择pdf文件并将其添加到列表中,在另一个屏幕(“文件”)中更新功能,然后切换到该屏幕。我的.py文件如下:-

import kivy
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.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
kivy.require("1.11.1")

from kivy.uix.floatlayout import FloatLayout
from kivy.config import Config


from kivy.properties import ObjectProperty
from kivy.uix.widget import Widget
Config.set('graphics', 'resizable', True)

from PyPDF2 import PdfFileReader, PdfFileWriter

FILE_LIST = []
PAGE_LIST = []
OUTPUT_LIST = []


def add_output_list(page_name):
    for item in PAGE_LIST:
        if item[0] == page_name:
            if item[-1] not in OUTPUT_LIST:
                OUTPUT_LIST.append(item[-1])
    print(OUTPUT_LIST)


class FinalPage(GridLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.cols = 1


class ParsingPage(GridLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.cols = 4

    def update_pages(self):
        for item in PAGE_LIST:
            self.inside = GridLayout()
            self.inside.cols = 3

            self.inside.select = Button(text="sel")
            self.inside.add_widget(self.inside.select)
            self.inside.select.bind(on_press=lambda x: self.select_button(item[-1]))

            self.inside.clock = Button(text="c")
            self.inside.add_widget(self.inside.clock)

            self.inside.anticlock = Button(text="ac")
            self.inside.add_widget(self.inside.anticlock)

            self.add_widget(self.inside)
            self.add_widget(Label(text=f'{item[0]}'))
        self.inside_2 = GridLayout()
        self.inside_2.cols = 2
        self.inside_2.done = Button(text="Done")
        self.inside_2.add_widget(self.inside_2.done)
        self.inside_2.done.bind(on_press=self.done_button)

        self.inside_2.cancel = Button(text="Cancel")
        self.inside_2.add_widget(self.inside_2.cancel)
        self.inside_2.cancel.bind(on_press=self.cancel_button)

    def select_button(self, page_name):
        add_output_list(page_name)

    def done_button(self):
        pass

    def cancel_button(self):
        pass


class SelectionPage(Widget):

    def select(self, *args):
        try:
            if args[1][0].split('.')[-1] != 'pdf':
                self.label.text = 'You can only select a PDF File.'
            else:
                self.label.text = args[1][0]
        except:
            pass

    def add_button(self):
        FILE_LIST.append(self.label.text)
        pdf_app.files_page.update_files(self.label.text)
        pdf_app.screen_manager.current = 'Files'

    def next_button(self):
        pdf_app.screen_manager.current = 'Files'


class FilesPage(Widget):
    def update_files(self):
        return FILE_LIST


class BrowsePage(Widget):

    def browse_button(self):
        pdf_app.screen_manager.current = 'Selection'


class PdfParserApp(App):
    FILE_LIST = []

    def build(self):

        self.screen_manager = ScreenManager()
        self.browse_page = BrowsePage()
        screen = Screen(name='Browse')
        screen.add_widget(self.browse_page)
        self.screen_manager.add_widget(screen)

        # Info page
        self.selection_page = SelectionPage()
        screen = Screen(name='Selection')
        screen.add_widget(self.selection_page)
        self.screen_manager.add_widget(screen)

        self.files_page = FilesPage()
        screen = Screen(name='Files')
        screen.add_widget(self.files_page)
        self.screen_manager.add_widget(screen)

        self.parsing_page = ParsingPage()
        screen = Screen(name='Parsing')
        screen.add_widget(self.parsing_page)
        self.screen_manager.add_widget(screen)

        return self.screen_manager


if __name__ == '__main__':
    pdf_app = PdfParserApp()
    pdf_app.run()

FILE_LIST是所有类之外的变量(以便可以在所有类中使用。

现在,我要遍历此FILE_LIST并在下一个屏幕上创建标签。但是我想使用.kv文件来实现,这样我就可以在整个应用程序中保持设计的一致性。我的.kv文件是:-

#, kv file implementation
#:import Label kivy.uix.label.Label

<BrowsePage>:
    GridLayout:
        size : root.width-200, root.height-200
        pos : 100, 100
        cols : 1
        Label :
            text: "Welcome to PDF Parser"
            color: [ 66/255, 103/255, 178/255, 1]
            font_size: 38
            size_hint : (0.2, 0.5)
        Label :
            text : "Select the file(s)."
            color: [ 66/255, 103/255, 178/255, 1]
            font_size: 20
            size_hint : (0.2, 0.5)
        AnchorLayout:
            anchor_x : "center"
            Button:
                text : "Browse"
                size_hint : (.15, .15)

                on_press : root.browse_button()

<SelectionPage>:

    label: label


    GridLayout:
        size : root.width, root.height
        cols :1

        FileChooserIconView:

            pos_hint: {"x":0, "top" : 1}
            on_selection: root.select(*args)

        Label:

            id: label
            size_hint : (.1, .1)

        GridLayout:
            cols : 3
            size_hint : (1, .15)

            AnchorLayout:
                anchor_x : "center"
                Button:
                    text : "Cancel"
                    size_hint : (.15, .15)

            AnchorLayout:
                anchor_x : "center"
                Button:
                    text : "Add"
                    size_hint : (.15, .15)
                    on_press: root.add_button()
            AnchorLayout:
                anchor_x : "center"
                Button:
                    text : "Next"
                    size_hint : (.15, .15)
                    on_press: root.next_button()



<FilesPage>
    GridLayout:
        size : root.width, root.height

        cols: 1
        on_parent:
            for i in root.update_files(): txt = "Label {0}".format(i); self.add_widget(Label(text = txt, text_size=(cm(2), cm(2)), pos=self.pos,
            id=txt, color=(1,1,1,1)))


我认为,当我切换屏幕时,它将以某种方式创建一个新的空白列表。循环代码没有任何错误,就像我在FilePage中硬编码一个列表一样,然后出现了标签。

任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:0)

我个人认为,将太多的代码放入KV文件中是不良设计的标志。窗口小部件的结构(如KV文件中所述)与实际逻辑之间应有清晰的区分,而实际逻辑应在Python中实现。在这种情况下,我们可以利用override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) for cell in tableView.visibleCells { (cell as VideoCell).stopVideo() } } 事件在显示on_enter屏幕时创建标签。看起来如下

FilesPage

答案 1 :(得分:0)

此回复基于问题标题。 我也同意@Nykakin,这是一种将UI逻辑与UI设计分开的好习惯。

我个人对此采取了不同的方法。

add_label.kv

<MainView>:
    orientation: 'vertical'


<MyLabel>:
    text: root.label_text
    color: root.label_color

然后在python中

add_label.py

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.properties import StringProperty, ListProperty

MY_FILE_LIST = [
    {
        'label_text': 'foo label_0',
        'label_color': [1, .5, .4, 1]
    },
    {
        'label_text': 'bar label_1',
        'label_color': [.2, .4, .3, 1]
    },
    {
        'label_text': 'foobar label_2',
        'label_color': [.2, .9, .1, 1]
    },
]

Builder.load_file('add_label.kv')


class MainView (BoxLayout):

    def __init__(self, **kwargs):
        super(MainView, self).__init__(**kwargs)
        for file in MY_FILE_LIST:
            lbl = MyLabel()
            lbl.label_text = file['label_text']
            lbl.label_color = file['label_color']
            self.add_widget(lbl)


class MyLabel(Label):
    label_text = StringProperty()
    label_color = ListProperty()


class LabelApp (App):

    def build(self):
        return MainView()


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

如果您要在视图上一次添加少量小部件,则此方法将起作用(我不超过大约10〜30)。如果您的数据集大于30点,则您的应用可能会挂起,直到在视图上创建并添加所有小部件实例为止。 同样,使用此方法更难更新MY_FILE_LIST,并且该更新要反映在UI上。不是不可能,但是要做到这一点有些棘手。

RecycledView是针对大型数据集的更合适的解决方案。或者,如果您希望MY_FILE_LIST上的更新会反映在用户界面上。