嗨高级python用户,感谢您阅读本文。我目前正在尝试编写一个可以为用户读写文件的会计应用程序。
在kivy的listitemview中显示用户文件中的数据时遇到了一些麻烦。我希望项目的支出和描述与其标题一致,基本上通过使用键盘中的标签功能。但是,选项卡根本不由列表项视图表示。我该如何解决这个问题?
此外,我是否有效地使用此应用程序?我知道逻辑是由python文件处理的,设计相关的东西都在.kv文件中
请原谅,如果我犯了一些错误,因为这是我的第一篇文章,我是使用python的新手,甚至更新的kivy。
python文件:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.lang import Builder
from kivy.properties import ObjectProperty, StringProperty, ListProperty
from kivy.uix.popup import Popup
from kivy.uix.button import Button
import os, re
class HomePage(Screen):
#Includes the name of the App, Instructions, as well as 2 buttons that lead to their respective screens
pass
class NewUserPage(Screen):
def saveuser(self, username, filename):
if len(username) != 0:
newuserfilepath = "users\\"+str(username)
if not os.path.exists(newuserfilepath):
os.makedirs(newuserfilepath)
if len(filename) != 0:
filepath = os.path.join("users\\" + str(username), str(filename) + ".txt")
f = open(filepath, "w")
f.close()
else:
print "Please key in at least one character for a filename."
else:
print "Please type in a Username."
def saveuserpopup(self, username, filename):
filepath = os.path.join("users\\"+str(username), str(filename))
if not os.path.exists(filepath):
box = BoxLayout(orientation="vertical")
box.add_widget(Label(text="Confirm Save %s, under filename: %s" %(username,filename)))
Button1 = Button(text = "Confirm")
Button2 = Button(text = "Cancel")
box.add_widget(Button1)
box.add_widget(Button2)
popup = Popup(title = "Confirm Save User", content = box, size_hint=(0.5,0.5))
buttoncallback = lambda *args: self.saveuser(username, filename)
Button1.bind(on_press = buttoncallback)
Button1.bind(on_release = popup.dismiss)
#Button1.bind(on_press = self.saveuser(username,filename))
Button2.bind(on_press = popup.dismiss)
popup.open()
class ExistingUserPage(Screen):
text = StringProperty("")
content = StringProperty("")
expenditure = StringProperty("")
itemlist = StringProperty("")
def loaduser(self, username, filename):
filepath = os.path.join("users\\"+str(username), str(filename)+".txt")
if os.path.exists(filepath):
try:
file = open(filepath,"r")
content = file.read()
expenditure = content.split()[0::2]
itemlist = content.split()[1::2]
self.text = "User: " + str(username).upper() + " filename: " + str(filename).upper()
self.content = str(content).upper()
self.expenditure = str(expenditure)
self.itemlist = str(itemlist)
except(IOError):
print "You did not fill in sufficient information"
self.content = str("Please fill in the details correctly")
else:
print "Please key in a valid username or filename."
self.text = "User: " + str(username).upper() + " filename: " + str(filename).upper()
self.content = str("Please fill in the details correctly")
class ProcessingUserPage(Screen):
text = StringProperty("")
content = StringProperty("")
expenditure = StringProperty("")
itemlist = StringProperty("")
content_list = ListProperty([])
def function(self,expenditure,itemlist,content): #Function called from the .kv file
integer = re.findall("[0-9]+", expenditure)
word = re.sub("[^\w]"," ", itemlist).split() #https://stackoverflow.com/questions/6181763/converting-a-string-to-a-list-of-words
for i in range(len(integer)):
self.content_list.append((integer[i] + word[i]))
class ScreenManagement(ScreenManager):
pass
class AccountApp(App):
def build(self):
pass
if __name__ == "__main__":
AccountApp().run()
.kv文件:
#: import Factory kivy.factory.Factory
#: import ListAdapter kivy.adapters.listadapter.ListAdapter
#: import ListItemButton kivy.uix.listview.ListItemButton
ScreenManagement:
HomePage:
NewUserPage:
ExistingUserPage:
id: ExistingUserPage
ProcessingUserPage:
text: ExistingUserPage.text
content: ExistingUserPage.content
expenditure: ExistingUserPage.expenditure
itemlist: ExistingUserPage.itemlist
<CustomListItemButton@ListItemButton>:
halign: "left"
text_size: self.size
<HomePage>:
name: "HomePage"
GridLayout:
cols:1
rows:3
padding: 10
spacing: 10
BoxLayout:
Label:
text: "My Account"
color: 0,0,1,1 #Blue
text_size: root.width, None
font_size: root.height * 0.1
halign: "center"
valign: "top"
BoxLayout:
Label:
text: "Hello there! I am your friendly accountant Bill! Please select below if you are a 'New' or 'Existing' member"
color: 0.6, 0, 0.6, 1 #True Purple
text_size: root.width, None
font_size: root.height * 0.05
halign: "center"
valign: "top"
GridLayout:
cols: 2
rows: 1
spacing: 30
padding: 50
Button:
font_size: self.width * 0.1
text: "New"
color: 0.43, 0.61, 0.95, 1
background_color: 1, 0.84, 0, 1
on_release: app.root.current = "NewUserPage"
Button:
font_size: self.width * 0.1
text: "Existing"
color: 0.43, 0.61, 0.95, 1
background_color: 1, 0.84, 0, 1
on_release: app.root.current = "ExistingUserPage"
<NewUserPage>:
name: "NewUserPage"
id: NewUserPage
username: user_name
GridLayout:
rows: 7
cols: 1
BoxLayout:
height: "100dp"
size_hint_y: None
padding: 10
Label:
size: self.texture_size
text: "My Account"
color: 0,0,1,1 #Blue
text_size: root.width, None
font_size: root.height * 0.1
halign: "center"
valign: "top"
BoxLayout:
height: "100dp"
size_hint_y: None
Label:
size: self.texture_size
text: "New User Sign Up"
color: 0.6, 0, 0.6, 1 #True Purple
text_size: root.width, None
font_size: root.height * 0.05
halign: "center"
valign: "top"
BoxLayout:
FileChooserIconView:
path: "users\\"
BoxLayout:
height: "40dp"
size_hint_y: None
orientation: "horizontal"
Label:
text: "Insert User Name Here"
TextInput:
id: user_name
BoxLayout:
height: "40dp"
size_hint_y: None
orientation: "horizontal"
Label:
text: "Insert File Name Here"
TextInput:
id: file_name
Button:
height: "40dp"
size_hint_y: None
text: "Submit"
#on_release: NewUserPage.saveuserpopup(user_name.text, file_name.text)
on_release: root.saveuserpopup(user_name.text, file_name.text)
BoxLayout:
height: "40dp"
size_hint_y: None
Button:
text: "Return to Home Page"
on_release: app.root.current = "HomePage"
<ExistingUserPage>:
name: "ExistingUserPage"
id: ExistingUserPage
GridLayout:
cols: 1
rows: 7
BoxLayout:
height: "100dp"
size_hint_y: None
Label:
size: self.texture_size
text: "My Account"
color: 0,0,1,1 #Blue
text_size: root.width, None
font_size: root.height * 0.1
halign: "center"
valign: "bottom"
BoxLayout:
height: "100dp"
size_hint_y: None
Label:
size: self.texture_size
text: "Existing User"
color: 0.6, 0, 0.6, 1 #True Purple
text_size: root.width, None
font_size: root.height * 0.05
halign: "center"
valign: "top"
BoxLayout:
FileChooserIconView:
path: "C:\\Users\\Jamesong\\mystuff\\Kivy_apps\\account\\users\\"
BoxLayout:
height: "40dp"
size_hint_y: None
orientation: "horizontal"
Label:
text: "Insert User Name Here"
TextInput:
id: user_name
multiline: False
BoxLayout:
height: "40dp"
size_hint_y: None
orientation: "horizontal"
Label:
text: "Insert File Name Here"
TextInput:
id: file_name
multiline: False
Button:
height: "40dp"
size_hint_y: None
text: "Submit"
on_press: ExistingUserPage.loaduser(user_name.text, file_name.text)
on_release: app.root.current = "ProcessingUserPage"
on_release: user_name.text = ""
on_release: file_name.text = ""
#on_release: ProcessingPage.load(user_name.text, file_name.text)
BoxLayout:
height: "40dp"
size_hint_y: None
Button:
text: "Return to Home Page"
on_release: app.root.current = "HomePage"
<ProcessingUserPage>:
name: "ProcessingUserPage"
BoxLayout:
orientation: "vertical"
Label:
size_hint_y: 0.1
text: "My Account"
color: 0,0,1,1 #Blue
text_size: self.size
font_size: root.height * 0.1
halign: "center"
valign: "bottom"
Label:
size_hint_y: 0.1
text: "Processing " + root.text
color: 0.6, 0, 0.6, 1 #True Purple
text_size: self.size
font_size: root.height * 0.05
halign: "center"
valign: "bottom"
BoxLayout:
orientation: "horizontal"
size_hint_y: 0.1
Label:
size_hint_x: 0.2
text_size: self.size
text: "Expenditure"
halign: "center"
Label:
size_hint_x: 0.8
text_size: self.size
text: "Item"
halign: "left"
BoxLayout:
orientation: "horizontal"
size_hint_y: 0.5
ListView:
id: content_list_view
adapter:
ListAdapter(data = root.content_list, cls = Factory.CustomListItemButton)
BoxLayout:
orientation: "horizontal"
size_hint_y: 0.1
Label:
text: "Input"
TextInput:
id: input
multiline: False
Button:
size_hint_y: 0.1
text: "Press"
on_press: root.function(root.expenditure,root.itemlist,root.content)
Button:
size_hint_y: 0.1
text: "Back to Home"
on_press: app.root.current = "HomePage"
例如.txt文件
10 LUNCH
13 DINNER
8 DRINK
18 SHOP
13 DRINK
4 SNACK
6 SNACK
10 LUNCH
13 DINNER
8 DRINK
18 SHOP
13 DRINK
4 SNACK
6 SNACK
答案 0 :(得分:0)
解决方案是将ListView替换为RecycleView,因为自Kivy版本1.10.0以来我不推荐使用ListView,我们正在使用RecycleGridLayout。有关详细信息,请参阅示例。
该示例是在Ubuntu Linux上使用Python 3.5开发的。
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.properties import StringProperty, ListProperty, BooleanProperty
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
import os
import re
class HomePage(Screen):
# Includes the name of the App, Instructions, as well as 2 buttons that lead to their
# respective screens
pass
class NewUserPage(Screen):
def saveuser(self, username, filename):
if len(username) != 0:
# Windows - newuserfilepath = "users\\" + str(username)
newuserfilepath = "/home/" + str(username)
if not os.path.exists(newuserfilepath):
os.makedirs(newuserfilepath)
if len(filename) != 0:
# Windows - filepath = os.path.join("users\\" + str(username), str(filename) + ".txt")
filepath = os.path.join("/home/" + str(username), str(filename) + ".txt")
f = open(filepath, "w")
f.close()
else:
# Python2.x - print "Please key in at least one character for a filename."
print("Please key in at least one character for a filename.")
else:
# Python2.x - print "Please type in a Username."
print("Please type in a Username.")
def saveuserpopup(self, username, filename):
# Windows - filepath = os.path.join("users\\"+str(username), str(filename))
filepath = os.path.join("/home/"+str(username), str(filename))
if not os.path.exists(filepath):
box = BoxLayout(orientation="vertical")
box.add_widget(Label(text="Confirm Save %s, under filename: %s" % (username, filename)))
Button1 = Button(text="Confirm")
Button2 = Button(text="Cancel")
box.add_widget(Button1)
box.add_widget(Button2)
popup = Popup(title="Confirm Save User", content=box, size_hint=(0.5, 0.5))
buttoncallback = lambda *args: self.saveuser(username, filename)
Button1.bind(on_press=buttoncallback)
Button1.bind(on_release=popup.dismiss)
# Button1.bind(on_press = self.saveuser(username,filename))
Button2.bind(on_press=popup.dismiss)
popup.open()
class ExistingUserPage(Screen):
text = StringProperty("")
content = StringProperty("")
content_list = ListProperty([])
def loaduser(self, username, filename):
# Windows - filepath = os.path.join("users\\"+str(username), str(filename)+".txt")
filepath = os.path.join("/home/"+str(username), str(filename)+".txt")
self.text = "User: " + str(username).upper() + " filename: " + str(filename).upper()
self.content = str("Please fill in the details correctly")
if os.path.exists(filepath):
try:
with open(filepath, "r") as fobj:
for line in fobj:
for word in line.rsplit():
self.content_list.append(word)
except IOError:
# Python2.x - print "You did not fill in sufficient information"
print("You did not fill in sufficient information")
else:
# Python2.x - print "Please key in a valid username or filename."
print("Please key in a valid username or filename.")
class ProcessingUserPage(Screen):
text = StringProperty("")
content = StringProperty("")
content_list = ListProperty([])
def function(self, content_list, inputString): # Function called from the .kv file
words = re.sub("[^\w]", " ", inputString).rsplit()
print("words=", words)
for word in words:
print("word=", word)
content_list.append(word)
# TO-DO List
# Append words to file
class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleGridLayout):
''' Adds selection and focus behaviour to the view. '''
class SelectableButton(RecycleDataViewBehavior, Button):
''' Add selection support to the Label '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableButton, self).refresh_view_attrs(rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableButton, self).on_touch_down(touch):
return True
if self.collide_point(*touch.pos) and self.selectable:
return self.parent.select_with_touch(self.index, touch)
def apply_selection(self, rv, index, is_selected):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
class ScreenManagement(ScreenManager):
pass
class AccountApp(App):
def build(self):
return ScreenManagement()
if __name__ == "__main__":
AccountApp().run()
#:kivy 1.10.0
<ScreenManagement>:
HomePage:
NewUserPage:
ExistingUserPage:
id: ExistingUserPage
ProcessingUserPage:
text: ExistingUserPage.text
content: ExistingUserPage.content
content_list: ExistingUserPage.content_list
<HomePage>:
name: "HomePage"
GridLayout:
cols:1
rows:3
padding: 10
spacing: 10
BoxLayout:
Label:
text: "My Account"
color: 0,0,1,1 #Blue
text_size: root.width, None
font_size: root.height * 0.1
halign: "center"
valign: "top"
BoxLayout:
Label:
text: "Hello there! I am your friendly accountant Bill! Please select below if you are a 'New' or 'Existing' member"
color: 0.6, 0, 0.6, 1 #True Purple
text_size: root.width, None
font_size: root.height * 0.05
halign: "center"
valign: "top"
GridLayout:
cols: 2
rows: 1
spacing: 30
padding: 50
Button:
font_size: self.width * 0.1
text: "New"
color: 0.43, 0.61, 0.95, 1
background_color: 1, 0.84, 0, 1
on_release: app.root.current = "NewUserPage"
Button:
font_size: self.width * 0.1
text: "Existing"
color: 0.43, 0.61, 0.95, 1
background_color: 1, 0.84, 0, 1
on_release: app.root.current = "ExistingUserPage"
<NewUserPage>:
name: "NewUserPage"
id: NewUserPage
username: user_name
BoxLayout:
orientation: "vertical"
BoxLayout:
height: dp(100)
size_hint_y: None
padding: 10
Label:
size: self.texture_size
text: "My Account"
color: 0,0,1,1 #Blue
text_size: root.width, None
font_size: root.height * 0.1
halign: "center"
valign: "top"
BoxLayout:
height: dp(100)
size_hint_y: None
Label:
size: self.texture_size
text: "New User Sign Up"
color: 0.6, 0, 0.6, 1 #True Purple
text_size: root.width, None
font_size: root.height * 0.05
halign: "center"
valign: "top"
BoxLayout:
FileChooserIconView:
# Windows - path: "users\\"
path: "/home/"
BoxLayout:
height: dp(40)
size_hint_y: None
orientation: "horizontal"
Label:
text: "Insert User Name Here"
TextInput:
id: user_name
multiline: False
BoxLayout:
height: dp(40)
size_hint_y: None
orientation: "horizontal"
Label:
text: "Insert File Name Here"
TextInput:
id: file_name
multiline: False
Button:
height: dp(40)
size_hint_y: None
text: "Submit"
#on_release: NewUserPage.saveuserpopup(user_name.text, file_name.text)
on_release: root.saveuserpopup(user_name.text, file_name.text)
Button:
height: dp(40)
size_hint_y: None
text: "Return to Home Page"
on_release: app.root.current = "HomePage"
<ExistingUserPage>:
name: "ExistingUserPage"
id: ExistingUserPage
BoxLayout:
orientation: "vertical"
BoxLayout:
height: dp(100)
size_hint_y: None
Label:
size: self.texture_size
text: "My Account"
color: 0,0,1,1 #Blue
text_size: root.width, None
font_size: root.height * 0.1
halign: "center"
valign: "bottom"
BoxLayout:
height: dp(100)
size_hint_y: None
Label:
size: self.texture_size
text: "Existing User"
color: 0.6, 0, 0.6, 1 #True Purple
text_size: root.width, None
font_size: root.height * 0.05
halign: "center"
valign: "top"
BoxLayout:
FileChooserIconView:
# Windows - path: "C:\\Users\\Jamesong\\mystuff\\Kivy_apps\\account\\users\\"
path: "/home/iam/"
BoxLayout:
height: dp(40)
size_hint_y: None
orientation: "horizontal"
Label:
text: "Insert User Name Here"
TextInput:
id: user_name
multiline: False
BoxLayout:
height: dp(40)
size_hint_y: None
orientation: "horizontal"
Label:
text: "Insert File Name Here"
TextInput:
id: file_name
multiline: False
Button:
height: dp(40)
size_hint_y: None
text: "Submit"
on_press: ExistingUserPage.loaduser(user_name.text, file_name.text)
on_release:
app.root.current = "ProcessingUserPage"
user_name.text = ""
file_name.text = ""
Button:
height: dp(40)
size_hint_y: None
text: "Return to Home Page"
on_release: app.root.current = "HomePage"
<SelectableButton>:
# Draw a background to indicate selection
canvas.before:
Color:
rgba: (.0, 0.9, .1, .3) if self.selected else (0, 0, 0, 1)
Rectangle:
pos: self.pos
size: self.size
<ProcessingUserPage>:
name: "ProcessingUserPage"
BoxLayout:
orientation: "vertical"
Label:
size_hint_y: 0.1
text: "My Account"
color: 0,0,1,1 #Blue
text_size: self.size
font_size: root.height * 0.1
halign: "center"
valign: "bottom"
Label:
size_hint_y: 0.1
text: "Processing " + root.text
color: 0.6, 0, 0.6, 1 #True Purple
text_size: self.size
font_size: root.height * 0.05
halign: "center"
valign: "bottom"
BoxLayout:
orientation: "horizontal"
size_hint_y: 0.1
GridLayout:
size_hint: 1, None
size_hint_y: None
height: 25
cols: 2
Label:
text: "Expenditure"
Label:
text: "Item"
BoxLayout:
orientation: "horizontal"
size_hint_y: 0.5
RecycleView:
viewclass: 'SelectableButton'
data: [{'text': str(x)} for x in root.content_list]
SelectableRecycleGridLayout:
default_size: None, 25
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: True
touch_multiselect: True
cols: 2
BoxLayout:
orientation: "horizontal"
size_hint_y: 0.1
Label:
text: "Input"
TextInput:
id: input
multiline: False
Button:
size_hint_y: 0.1
text: "Press"
on_press: root.function(root.content_list, input.text)
Button:
size_hint_y: 0.1
text: "Back to Home"
on_press: app.root.current = "HomePage"