Search code examples
pythonandroidkivydesktop-applicationkivymd

Showing tasks only after new program launch. kivy


Good evening. I'm learning kivy and trying to make something like "microsoft to do". But I have a problem. Now I'm doing an adding task function. The main idea of it:

  1. When I click "add task"(button with plus icon) button, my screen changes on "AddingNewTaskScreen".
  2. In AddingNewTaskScreen class I created a function ""addTask that takes text from TextInput and add it in text file. Then it changes this screen on "MainMenuScreen"
  3. In MainMenuScreen class(it is first screen), in constructor i call a "taskRead" function that takes text from text file and write it in array. Then it adds elements of arrays in MDList and after it, it adds this MDList to ScrollView.

And it works, but it takes shows me tasks after new programm launch. For example: I add the task and the "MainMenuScreen" doesn't show me anything. But when I restart my programm, everything are in ScrollView. If you have any ideas how it can be fixed, please tell me, I wold really apreciate it. Thank you for advance.

main.py

from kivy.uix.button import Button
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivymd.app import MDApp
from kivymd.uix.list import OneLineListItem, MDList
from kivy.properties import ObjectProperty
from kivy.uix.scrollview import ScrollView
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition

class MainMenuScreen(Screen):
    listBox = ObjectProperty()
    theme_changer = ObjectProperty()
    search_task = ObjectProperty()
    all_tasks = ObjectProperty()
    important_tasks = ObjectProperty()
    create_list = ObjectProperty()
    completed_tasks = ObjectProperty()
    list_name = ObjectProperty()
    sort = ObjectProperty()
    rename = ObjectProperty()
    add_button = ObjectProperty()
    scroll = ScrollView()
    list_view = MDList()

    def __init__(self, **kw):
        super().__init__(**kw)
        self.taskRead()

    def taskRead(self):

        sv = open('tasks.txt', 'r', encoding='utf-8')
        arr = sv.read().split('\n')
        sv.close()
        for i in range(len(arr)):
            self.list_view.add_widget(OneLineListItem(text=arr[i], on_press=self.scr))
            self.add_widget(MDList())
        self.scroll.add_widget(self.list_view)
        self.listBox.add_widget(self.scroll)

    def scr(self, value):
        self.manager.transition = FadeTransition()
        self.manager.current = 'goodbye_screen'


class ToDoListApp(MDApp):

    def __init__(self, **kw):
        super().__init__(**kw)

    def build(self):
        self.theme_cls.theme_style = "Dark"
        Window.size = (1300, 700)
        sm = ScreenManager()
        sm.add_widget(MainMenuScreen(name='main_menu_screen'))
        sm.add_widget(ImportantOrCompletedTaskCheckScreen(name='goodbye_screen'))
        sm.add_widget(AddingNewTaskScreen(name='adding_newTask_screen'))
        return sm


class AddingNewTaskScreen(Screen):
    taskToTxt = ObjectProperty()
    addTaskButton = ObjectProperty()

    def __init__(self, **kw):
        super().__init__(**kw)

    def addTask(self):
        task_text = str(self.taskToTxt.text)
        sv = open('tasks.txt', 'a', encoding='utf-8')
        sv.writelines(str(task_text) + '\n')
        sv.close()
        ToDoListApp.get_running_app().root.current = "main_menu_screen"


# Class for another problem
class ImportantOrCompletedTaskCheckScreen(Screen):
    pass


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


todolist.kv

<MainMenuScreen@Screen>:
    listBox:listBox
    rename:rename
    search_task:search_task
    theme_changer:theme_changer
    all_tasks:all_tasks
    important_tasks:important_tasks
    create_list:create_list
    completed_tasks:completed_tasks
    list_name:list_name
    sort:sort
    #add_button:add_button
    orientation: 'vertical'

    # right lateral panel
    BoxLayout:
        BoxLayout:
            size_hint: '0.3', '0.8'
            pos_hint: {'y': 0.17}
            orientation: 'vertical'
            GridLayout:
                cols: 1
                rows: 9
                MDRoundFlatButton:
                    id: theme_changer
                    size_hint: 0.5, 0.3
                    text: 'Light theme'
                    line_color: 1,1,1,1
                    elevation_normal: 0
                    on_press: root.change_theme()
                BoxLayout:
                    size_hint: 1, 0.5
                MDRoundFlatButton:
                    size_hint: 1, 0.7
                    text: 'All tasks'
                    line_color: 1,1,1,1
                    id: all_tasks
                BoxLayout:
                    size_hint: 1, 0.08
                MDRoundFlatButton:
                    size_hint: 1, 0.7
                    text: 'Important'
                    line_color: 1,1,1,1
                    id: important_tasks
                BoxLayout:
                    size_hint: 1, 0.08
                MDRoundFlatButton:
                    size_hint: 1, 0.7
                    text: '+ Create \nlist'
                    line_color: 1,1,1,1
                    id: create_list
                BoxLayout:
                    size_hint: 1, 0.08
                MDRoundFlatButton:
                    size_hint: 1, 0.7
                    text: 'Completed \ntasks'
                    line_color: 1,1,1,1
                    id: completed_tasks


        # top panel
        BoxLayout:
            orientation: 'vertical'
            AnchorLayout:
                anchor_y: 'top'
                size_hint: 1, 0.05
                GridLayout:
                    size_hint: 1, 0.05
                    cols: 4
                    rows: 1
                    Label:
                        text: 'Name'
                        size_hint: 0.5, 0.05
                        id: list_name
                    MDTextField:
                        id:search_task
                        halign: 'center'
                        valign: 'center'
                        hint_text: 'Search'
                        size_hint: 1, None
                        line_color_normal: 0.15,0.15,0.15
                    MDRectangleFlatButton:
                        id: rename
                        text: 'Rename'
                        line_color: 1,1,1,1
                    MDRectangleFlatButton:
                        text: 'Sort'
                        line_color: 1,1,1,1
                        id: sort

            # Center

            BoxLayout:
                orientation: 'vertical'
                size_hint: 0.1, 0.1
                MDFloatingActionButton:
                    icon: "plus"
                    md_bg_color: 'black'
                    on_press: root.manager.current = 'adding_newTask_screen'

            BoxLayout:
                orientation: 'vertical'
                size_hint: 1,1

                BoxLayout:
                    ScrollView:
                        line_color_normal: 1,1,0,1
                        id: listBox

# Screen for another problem
<ImportantOrCompletedTaskCheckScreen@Screen>:
    name: 'goodbye_screen'
    AnchorLayout:
        anchor_x: 'center'
        anchor_y: 'center'
        BoxLayout:
            orientation: 'vertical'
            size_hint: 0.5, 0.25
            GridLayout:
                cols: 2
                rows: 1
                size_hint: 0.3, 0.25
                pos_hint: {'x': 0.35}
                MDSwitch:
                    size_hint: 0.3, 0.3
                    theme_text_color: "Custom"
                    text_color: 1, 1, 1, 1
                    line_color: 1, 1, 1, 1
                Label:
                    text: 'Important'
            BoxLayout:
                size_hint: 0, 0.5
            GridLayout:
                cols: 2
                rows: 1
                size_hint: 0.3, 0.25
                pos_hint: {'x': 0.35}
                MDSwitch:
                    text: 'Important'
                    size_hint: 0.3, 0.3
                    theme_text_color: "Custom"
                    text_color: 1, 1, 1, 1
                    line_color: 1, 1, 1, 1
                Label:
                    text: 'Completed'
            AnchorLayout:
                anchor_x: 'center'
                anchor_y: 'center'
                MDRoundFlatButton:
                    text: 'Continue'
                    size_hint: 1, 0.5
                    theme_text_color: "Custom"
                    text_color: 1, 1, 1, 1
                    line_color: 1, 1, 1, 1
                    on_press: root.manager.current='main_menu_screen'


<AddingNewTaskScreen@Screen>:
    taskToTxt:taskToTxt

    AnchorLayout:
        anchor_x: 'center'
        anchor_y: 'center'
        BoxLayout:
            orientation: 'vertical'
            size_hint: 0.5, 0.25
            MDTextField:
                id: taskToTxt
                hint_text: 'Name of new task'
                color: 'white'
                halign: 'center'
                valign: 'center'
                size_hint: 1, None
                multiline: False
            AnchorLayout:
                anchor_x: 'center'
                anchor_y: 'center'
                MDRoundFlatButton:
                    text: 'Add task'
                    id: addTaskButton
                    on_press: root.addTask()
                    size_hint: 1, 0.5
                    theme_text_color: "Custom"
                    text_color: 1, 1, 1, 1
                    line_color: 1, 1, 1, 1

Solution

  • In addTask you should get access to main screen

    main_screen = ToDoListApp.get_running_app().root.get_screen('main_menu_screen')
    

    and then you can add task to list

    main_screen.list_view.add_widget(OneLineListItem(text=task_text, on_press=main_screen.scr))
    

        def addTask(self):
            task_text = str(self.taskToTxt.text)
            sv = open('tasks.txt', 'a', encoding='utf-8')
            sv.writelines(str(task_text) + '\n')
            sv.close()
            
            main_screen = ToDoListApp.get_running_app().root.get_screen('main_menu_screen')
            main_screen.list_view.add_widget(OneLineListItem(text=task_text, on_press=main_screen.scr))
            
            ToDoListApp.get_running_app().root.current = "main_menu_screen"
    

    BTW:

    ScreenManager is a parent for every Screen so you could write shorter with self.parent.

    Or you could use self.manager

    main_screen = self.parent.get_screen('main_menu_screen')
    #main_screen = self.manager.get_screen('main_menu_screen')
    
    # ... code ...
    
    self.parent.current = "main_menu_screen"
    #self.manager.current = "main_menu_screen"
    

    In MainMenuScreen you could also create function to add single task

    class MainMenuScreen(Screen):
    
        def add_task(self, text):
            self.list_view.add_widget(OneLineListItem(text=text, on_press=self.scr))
    

    and then you could write it simpler in addTask

    main_screen = self.parent.get_screen('main_menu_screen')
    main_screen.add_task(task_text)
    

    and in taskRead you could reduce for-loop

    for text in arr:
        self.add_task(text)