Kivy:从.txt获取数据到listitemview

时间:2017-10-22 10:43:16

标签: python-2.7 kivy

嗨高级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 

1 个答案:

答案 0 :(得分:0)

解决方案是将ListView替换为RecycleView,因为自Kivy版本1.10.0以来我不推荐使用ListView,我们正在使用RecycleGridLayout。有关详细信息,请参阅示例。

注意

该示例是在Ubuntu Linux上使用Python 3.5开发的。

实施例

account.py

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()

account.kv

#: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"

输出

enter image description here enter image description here