You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Kivy项目中存储Project至列表或字典?项目管理器应用开发求助

Kivy Project Manager: Data Storage Solution & Code Improvements

Hey Micheno, let's break down how to solve your data storage problem and polish up your code for better maintainability.

1. Data Storage Solution

You need two layers of storage: in-memory storage for active sessions, and persistent storage to save data between app restarts.

In-Memory Storage (Structured with Classes)

Raw lists/dictionaries get messy fast—define simple classes to represent your Project and Task data for cleaner management:

class Task:
    def __init__(self, name, is_completed=False, notes=""):
        self.name = name
        self.is_completed = is_completed
        self.notes = notes

class Project:
    def __init__(self, name):
        self.name = name
        self.tasks = []

Update your screens to use these classes:

  • In PRS, replace the class-level projects list with an instance variable to avoid shared state across screen instances:
    class PRS(Screen, BoxLayout):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            self.projects = []  # Instance-specific project list
            # ... rest of your __init__ code
    
  • When creating a new project, capture the input text and add a Project instance to your list:
    def new_pr(self, *args):
        # ... your existing code to create txt1, label1, check1, etc.
        
        # Save project when user finishes typing
        def save_project(instance):
            project_name = instance.text.strip()
            if project_name:
                new_project = Project(project_name)
                self.projects.append(new_project)
                print(f"Added project: {project_name}")
                # Optional: Link this project to its OPEN button
                button.project = new_project
        
        txt1.bind(on_text_validate=save_project)
        
        # ... rest of your code for buttons/spinner
    
  • Pass the active project to the TASKS screen when clicking "OPEN":
    def open_project(self, instance):
        self.manager.current = 'task'
        # Send the project to the tasks screen
        tasks_screen = self.manager.get_screen('task')
        tasks_screen.current_project = instance.project
    

Persistent Storage (Using JsonStore)

You already imported JsonStore—let's use it to save/load data between app sessions:

  • Initialize the store in your MApp class:
    class MApp(App):
        title = "PROJECT MANAGER"
        def build(self):
            self.store = JsonStore('project_data.json')
            sm = ScreenManager()
            # ... rest of your screen setup
            return sm
    
  • Add methods to save and load projects in PRS:
    def save_projects(self):
        # Convert projects to JSON-serializable data
        project_data = []
        for proj in self.projects:
            task_data = [
                {"name": t.name, "is_completed": t.is_completed, "notes": t.notes}
                for t in proj.tasks
            ]
            project_data.append({"name": proj.name, "tasks": task_data})
        
        App.get_running_app().store.put('saved_projects', data=project_data)
    
    def load_projects(self):
        app = App.get_running_app()
        if app.store.exists('saved_projects'):
            saved_data = app.store.get('saved_projects')['data']
            for proj_data in saved_data:
                project = Project(proj_data['name'])
                # Recreate tasks
                for task_data in proj_data['tasks']:
                    project.tasks.append(Task(**task_data))
                self.projects.append(project)
            # Optional: Render loaded projects on the screen
    
  • Call save_projects() when the app closes, or when projects are added/deleted. Call load_projects() in PRS's __init__ method.

2. Code Improvements

Here are key tweaks to make your code more maintainable:

Move Layouts to KV File

Hardcoding widgets in Python makes the code hard to read. Define static layouts in main.kv instead:

<PRS>:
    name:"project"
    BoxLayout:
        orientation: 'vertical'
        # Header buttons
        BoxLayout:
            size_hint_y: 0.1
            Button:
                text: "NEW PROJECT"
                on_release: root.new_pr()
            Button:
                text: "BACK"
                on_release: root.changer2()
        # ScrollView for projects (prevents overflow)
        ScrollView:
            BoxLayout:
                id: project_container
                orientation: 'vertical'
                size_hint_y: None
                height: self.minimum_height

Then add new project widgets to the project_container instead of the main screen.

Fix Class Variable Issues

Variables like widgets1, l1top are class-level—this means all PRS instances share them. Convert them to instance variables in __init__:

class PRS(Screen, BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.widgets1 = []
        self.l1x = .1
        self.l1top = .87
        self.txt1x = .4
        self.txt1top = .88
        # ... rest of your variables

Fix Notes Functionality

Your current code adds a new TextInput every time the notes button is clicked. Instead, create a single widget and toggle its visibility:

class TASKS(Screen, BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.current_project = None
        # Create a single notes input, hidden by default
        self.notes_input = TextInput(multiline=True, size_hint=(.4,.5), pos_hint={"x":0.56,"top":.74}, opacity=0)
        self.add_widget(self.notes_input)
        # ... rest of your __init__ code

    def note(self, *args):
        self.notes_input.opacity = 1
        # Load existing notes if available
        if self.current_project:
            self.notes_input.text = self.current_project.notes

    def change(self, *args):
        self.notes_input.opacity = 0
        # Save notes back to the project
        if self.current_project:
            self.current_project.notes = self.notes_input.text

Remove Duplicate Imports

Clean up your imports to include each module only once:

from kivy.app import App
import sys
from kivy.storage.jsonstore import JsonStore
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.checkbox import CheckBox
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.spinner import Spinner
from kivy.uix.scrollview import ScrollView

Implement Theme Toggle

Add logic to your theme buttons in OPS:

class OPS(Screen, BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        label = Label(text="COLOR THEME:", size_hint=(.2,.1), pos_hint={"x":.25,"top":.9})
        self.add_widget(label)
        
        self.dark_btn = ToggleButton(text="DARK", size_hint=(.2, .1), pos_hint={"x":.5,"top":.9}, background_normal="", background_color=(0,0,0,0))
        self.light_btn = ToggleButton(text="LIGHT", size_hint=(.2, .1), pos_hint={"x": .7, "top": .9}, background_normal="", background_color=(1,1,1,1))
        
        self.dark_btn.bind(on_press=self.set_dark_theme)
        self.light_btn.bind(on_press=self.set_light_theme)
        
        self.add_widget(self.dark_btn)
        self.add_widget(self.light_btn)

    def set_dark_theme(self, instance):
        Window.clearcolor = (0,0,0,1)
        # Update widget colors (e.g., set button text to white)
        for child in self.parent.parent.children:
            if isinstance(child, Button):
                child.color = (1,1,1,1)

    def set_light_theme(self, instance):
        Window.clearcolor = (1,1,1,1)
        # Update widget colors (e.g., set button text to black)
        for child in self.parent.parent.children:
            if isinstance(child, Button):
                child.color = (0,0,0,1)

Final Tips

  • Add validation to prevent empty project/task names.
  • Use ScrollView in both PRS and TASKS to handle large numbers of items.
  • Call save_projects() when the app closes (override on_stop in MApp).

内容的提问来源于stack exchange,提问作者Micheno

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 05:57:28