Search code examples
pythonlistkivyupdating

How to create an updating list that grabs data from a text file in kivy


so right now I am trying to create a list in a kivy app. The app grabs data from a text file. The text file receives new data after the submission of information from the user, I would like the list to update every time the user submits more data. In this case the data is the names of colleges. I have been digging and digging for an answer to this problem but just cant seem to figure it out, I keep getting errors. Also, I am pretty new to programming in python (and programming in general) and this is also my first kivy app so excuse my lack of knowledge and stupidity. Below I have posted my python and kivy files along with the text file (just in case). Please help!

.py

from kivy.properties import ObjectProperty, ListProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from database import DataBase
from kivy.app import App
from kivy.uix.recycleview import RecycleViewBehavior


class MainPage(Screen):
    pass


class NewEntryPage(Screen, RecycleViewBehavior):
    addschool = ObjectProperty(None)
    costofsecondary = ObjectProperty(None)
    addtravelexpenses = ObjectProperty(None)
    ListOfSchools = ListProperty([])

    def pressBtn(self):
        newSchool = self.addschool.text
        costOfSecondary = self.costofsecondary.text
        addTravelExpense = self.addtravelexpenses.text

        print("New School:", newSchool, "\nCost Of Secondary:", costOfSecondary, "\naddTravelExpense:", addTravelExpense, "\n", self.ListOfSchools)

        if self.addschool.text != "" and self.costofsecondary.text != "" and self.addtravelexpenses.text != "":
            db.add_school_and_secondary(self.addschool.text, self.costofsecondary.text, self.addtravelexpenses.text)
            self.reset()
            SchoolsAppliedToPage().updatelist("/Users/PycharmProjects/msft/schools.txt", self.ListOfSchools)

    def reset(self):
        self.addschool.text = ""
        self.costofsecondary.text = ""
        self.addtravelexpenses.text = ""


class SchoolsAppliedToPage(Screen):
    rvlist = ObjectProperty(None)
    ListOfSchools = NewEntryPage.ListOfSchools

    def updatelist(self, filename, listofschools):
        file = open(filename, "r")
        for line in file:
            school, cos, ate, space = line.strip().split(";")
            listofschools.append(school)
        self.rvlist.data.append([{'text': school} for school in listofschools])
        print(listofschools)
        print(self.ListOfSchools)


class WindowManager(ScreenManager):
    pass


kv = Builder.load_file("msft.kv")
db = DataBase("/Users/PycharmProjects/msft/schools.txt")


class msftApp(App):

    def build(self):
        return kv


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

.kv

ScreenManager:
    MainPage:
    NewEntryPage:
    SchoolsAppliedToPage:

<Button>
    font_size:40
    font_name: "/Users/Desktop/App_Files/Antonio-Bold.ttf"
    size_hint:0.25, 0.075
    color:0.969, 0.463, 0.333, 1
    background_color: 0.17, 0.55, 0.92, 1

<MainPage>

    name: "MainPage"

    FloatLayout:
        Widget:
            canvas:
                Color:
                    rgb:0.969, 0.463, 0.333, 1
                Rectangle:
                    size:self.width, self.height

                Color:
                    rgb:1, 1, 1, 1
                Rectangle:
                    size:self.width * 0.95, self.height * 0.95
                    pos:root.center_x * 0.05, root.center_y * 0.05

                Color:
                    rgb:0, 0.18, 0.361, 1
                Rectangle:
                    size:self.width * 0.95, self.height / 10
                    pos:root.center_x * 0.05, root.center_y * 1.75

        Image:
            source:"/Users/Desktop/App_Files/doc.jpg"
            size_hint:0.1, 0.1
            pos_hint:{"x": 0.01, "top": 0.87}

        Image:
            source:"/Users/Desktop/App_Files/doc.jpg"
            size_hint:0.1, 0.1
            pos_hint:{"x": 0.895, "top": 0.87}


        Button:
            text:"Schools Applied to"
            size_hint:0.3,0.1
            pos_hint:{"x":0.07, "top":0.45}
            on_release:
                app.root.current = "SchoolsAppliedToPage"
                root.manager.transition.direction = "down"


        Button:
            text:"Add/Edit School"
            size_hint:0.3,0.1
            pos_hint:{"x":0.07, "top":0.3}
            on_release:
                app.root.current = "NewEntryPage"
                root.manager.transition.direction = "up"

        Button:
            text:"Add/Edit Travel"
            size_hint:0.3,0.1
            pos_hint:{"x":0.07, "top":0.15}
            on_release:

        Label:
            text:"Medical School is hard enough...let's try and save every penny that we can!"
            size_hint:0.1, 0.1
            pos_hint:{"x":0.45, "top":0.98}
            font_name:"/Users/Desktop/App_Files/DancingScript-Regular.otf"
            font_size: (root.width + root.height) / 70
            color:0.97, 0.97, 0.97, 1


<NewEntryPage>

    name:"NewEntryPage"

    addschool:addschool
    costofsecondary:cos
    addtravelexpenses:ate


    FloatLayout:
        Widget:
            canvas:
                Color:
                    rgb: 0, 0.18, 0.361, 1
                Rectangle:
                    size: self.width, self.height

                Color:
                    rgb: 0.97, 0.97, 0.97, 1
                Rectangle:
                    pos: 0, root.center_y * 1.75
                    size: self.width, self.height/8

                Color:
                    rgb: 0.97, 0.97, 0.97, 1
                Rectangle:
                    size: self.width * 0.9, self.height * 0.78
                    pos: root.center_x * 0.1, root.center_y * 0.1

                Color:
                    rgb: 0, 0.18, 0.361, 1
                Rectangle:
                    size: self.width * 0.72, self.height / 11
                    pos: root.center_x * 0.28, root.center_y * 1.78

                Color:
                    rgb: 0.969, 0.463, 0.333, 1
                Rectangle:
                    size: self.width * 0.7, self.height / 14
                    pos: root.center_x * 0.3, root.center_y * 1.80


        Label:
            font_name:"/Users/Desktop/App_Files/Antonio-Bold.ttf"
            size_hint:0.3, 0.3
            pos_hint:{"x":0.37, "top":0.93}
            text:"Add School"
            color:0.063, 0.024, 0.60, 1

        TextInput:
            id:addschool
            size_hint:0.3, 0.1
            pos_hint:{"x":0.37, "top": 0.75}
            multinline:False


        Label:
            font_name:"/Users/Desktop/App_Files/Antonio-Bold.ttf"
            size_hint:0.3, 0.3
            pos_hint:{"x":0.37, "top":0.73}
            text:"Cost Of Secondary"
            color:0.063, 0.024, 0.60, 1

        TextInput:
            id:cos
            size_hint:0.3, 0.1
            pos_hint:{"x":0.37, "top": 0.55}
            multinline:False


        Label:
            font_name:"/Users/Desktop/App_Files/Antonio-Bold.ttf"
            size_hint:0.3, 0.3
            pos_hint:{"x":0.37, "top":0.53}
            text:"Add Travel Expenses"
            color:0.063, 0.024, 0.60, 1

        TextInput:
            id:ate
            size_hint:0.3, 0.1
            pos_hint:{"x":0.37, "top": 0.35}
            multinline:False


        Button:
            id:btn
            text: "Submit" if btn.state == "normal" else "Done!"
            pos_hint:{"x":0.395, "top":0.20}
            on_press:root.pressBtn()

        Image:
            source:"/Users/Desktop/App_Files/med.png"
            size_hint:0.1, 0.1
            pos_hint:{"top": 0.99}

        Image:
            source:"/Users/Desktop/App_Files/med.png"
            size_hint:0.1, 0.1
            pos_hint:{"x":0.9, "top":0.99}

        Label:
            text:"Medical School is hard enough...let's try and save every penny that we can!"
            size_hint:0.1, 0.1
            pos_hint:{"x":0.45, "top":0.99}
            font_name:"/Users/Desktop/App_Files/DancingScript-Regular.otf"
            font_size: (root.width + root.height) / 70
            color:0, 0.18, 0.361, 1

        Button:
            text:"Home"
            pos_hint:{"x":0.13, "top":0.80}
            size_hint:0.1, 0.05
            on_release:
                app.root.current = "MainPage"
                root.manager.transition.direction = "down"

<SchoolsAppliedToPage>
    name:"SchoolsAppliedToPage"
    rvlist:rvlist

    BoxLayout:
        orientation: "vertical"
        size_hint_y: 0.5

        RecycleView:
            id:rvlist
            data:[{'text': school} for school in root.ListOfSchools]
            viewclass:'Label'
            RecycleGridLayout:
                default_size: 100, 100
                default_size_hint: 100, 100
                size_hint_y:None
                height: 500
                orientation: 'vertical'
                multiselect: True
                touch_multiselect: True
                cols: 4


    Button:
        text:"Home"
        size_hint:0.3,0.1
        pos_hint:{"x":0.07, "top":0.75}
        on_release:
            app.root.current = "MainPage"
            root.manager.transition.direction = "up"

.txt

Harvard;$100;$100;

The app runs and displays, but when I try to update the list after a user submission I get this error: ph = item.get('pos_hint', ph) AttributeError: 'list' object has no attribute 'get'


Solution

  • In your pressBtn() method of NewEntryPage, the line:

    SchoolsAppliedToPage().updatelist("/Users/PycharmProjects/msft/schools.txt", self.ListOfSchools)
    

    is creating a new instance of SchoolsAppliedToPage, and calling updatelist() on that new instance. Unfortunately, that new instance is not the one that is in your GUI, so that code has no effect on what you see on the screen.

    Try replacing that line with something like:

    satp = App.get_running_app().root.get_screen('SchoolsAppliedToPage')
    satp.updatelist("/Users/PycharmProjects/msft/schools.txt", self.ListOfSchools)
    

    This code gets a reference to the instance of SchoolsAppliedToPage, then calls updatelist() on that instance.

    Disclaimer: I have not tested the above code, but I believe that it suggests a correct approach.