python - 如何在 Kivy 的 .kv 文件中使用 for 循环创建标签?
问题描述
我正在 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 中硬编码一个列表,然后出现标签。
任何帮助将不胜感激。
解决方案
此响应基于问题标题。我也同意@Nykakin,这是将 UI 逻辑与 UI 设计分开的好习惯。
我个人对此采取了不同的方法。
add_label.kv
<MainView>:
orientation: 'vertical'
<MyLabel>:
text: root.label_text
color: root.label_color
然后在python中:
添加标签.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
会反映在 UI 上。
推荐阅读
- c++ - 如何安全地使用 deque::pop_front() 中的元素?
- apache-beam - 如何从 Apache Beam Row 写入 Avro 文件
- javascript - 如何对具有 document.querySelector 的函数进行单元测试?
- matplotlib - 使用 Matplotlib 理解和绘制 L2 正则化
- huawei-mobile-services - 应用程序在 AppGallery 和 GooglePlaystore 中使用相同的包名后,由于 Google Play 保护而被删除
- c# - Serilog ThreadId 始终输出为 1
- amazon-web-services - 使用会话凭据测试 Boto3 客户端
- reactjs - 将具有对象的状态传递给 React 中的另一个兄弟组件并映射它
- gcc - Cortex-M 编译器生成不正确的 FOR 循环
- html - 我创建了一个自定义光标,它工作正常,但是当我在网页上滚动时,光标失去了位置