我正在使用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中硬编码一个列表一样,然后出现了标签。
任何帮助将不胜感激。
答案 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
上的更新会反映在用户界面上。