My kivy app run this error: KeyError: 'container' can someone hel me please?
My kivy app run this error: KeyError: 'container' can someone hel me please?
我想用 kivy/kivymd 做一个待办事项列表应用程序,我想用多个屏幕做它,一切都很好,直到我在列表中添加一个小部件,当我按下时出现这个错误保存。
这是main.py
from cgitb import small
from kivymd.app import MDApp
from kivymd.uix.dialog import MDDialog
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.picker import MDDatePicker
from datetime import datetime
from kivymd.uix.list import TwoLineAvatarIconListItem, ILeftBodyTouch
from kivymd.uix.selectioncontrol import MDCheckbox
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.core.text import LabelBase
from kivy.utils import platform
from kivy.core.window import Window
import sqlite3
Window.size = (360, 640)
class Database:
def __init__(self):
self.con = sqlite3.connect('todo.db')
self.cursor = self.con.cursor()
self.create_task_table()
def create_task_table(self):
"""Create tasks table"""
self.cursor.execute("CREATE TABLE IF NOT EXISTS tasks(id integer PRIMARY KEY AUTOINCREMENT, task varchar(50) NOT NULL, due_date varchar(50), completed BOOLEAN NOT NULL CHECK (completed IN (0, 1)))")
self.con.commit()
def create_task(self, task, due_date=None):
"""Create a task"""
self.cursor.execute("INSERT INTO tasks(task, due_date, completed) VALUES(?, ?, ?)", (task, due_date, 0))
self.con.commit()
# GETTING THE LAST ENTERED ITEM SO WE CAN ADD IT TO THE TASK LIST
created_task = self.cursor.execute("SELECT id, task, due_date FROM tasks WHERE task = ? and completed = 0", (task,)).fetchall()
return created_task[-1]
def get_tasks(self):
"""Get tasks"""
uncomplete_tasks = self.cursor.execute("SELECT id, task, due_date FROM tasks WHERE completed = 0").fetchall()
completed_tasks = self.cursor.execute("SELECT id, task, due_date FROM tasks WHERE completed = 1").fetchall()
return completed_tasks, uncomplete_tasks
def mark_task_as_complete(self, taskid):
"""Marking tasks as complete"""
self.cursor.execute("UPDATE tasks SET completed=1 WHERE id=?", (taskid,))
self.con.commit()
def mark_task_as_incomplete(self, taskid):
"""Mark task as uncomplete"""
self.cursor.execute("UPDATE tasks SET completed=0 WHERE id=?", (taskid,))
self.con.commit()
# return the text of the task
task_text = self.cursor.execute("SELECT task FROM tasks WHERE id=?", (taskid,)).fetchall()
return task_text[0][0]
def delete_task(self, taskid):
"""Delete a task"""
self.cursor.execute("DELETE FROM tasks WHERE id=?", (taskid,))
self.con.commit()
def close_db_connection(self):
self.con.close()
db = Database()
class DialogContent(MDBoxLayout):
"""OPENS A DIALOG BOX THAT GETS THE TASK FROM THE USER"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.ids.date_text.text = str(datetime.now().strftime('%A %d %B %Y'))
def show_date_picker(self):
"""Opens the date picker"""
date_dialog = MDDatePicker()
date_dialog.bind(on_save=self.on_save)
date_dialog.open()
def on_save(self, instance, value, date_range):
"""This functions gets the date from the date picker and converts its it a
more friendly form then changes the date label on the dialog to that"""
date = value.strftime('%A %d %B %Y')
self.ids.date_text.text = str(date)
class ListItemWithCheckbox(TwoLineAvatarIconListItem):
'''Custom list item'''
def __init__(self, pk=None, **kwargs):
super().__init__(**kwargs)
# state a pk which we shall use link the list items with the database primary keys
self.pk = pk
def mark(self, check, the_list_item):
'''mark the task as complete or incomplete'''
if check.active == True:
the_list_item.text = '[s]'+the_list_item.text+'[/s]'
db.mark_task_as_complete(the_list_item.pk)# here
else:
the_list_item.text = str(db.mark_task_as_incomplete(the_list_item.pk))# Here
def delete_item(self, the_list_item):
'''Delete the task'''
self.parent.remove_widget(the_list_item)
db.delete_task(the_list_item.pk)# Here
class LeftCheckbox(ILeftBodyTouch, MDCheckbox):
'''Custom left container'''
class Screen1(Screen):
pass
class Screen2(Screen):
pass
class MainApp(MDApp):
task_list_dialog = None
def build(self):
self.theme_cls.primary_palette = "Blue"
sm = ScreenManager()
sm.add_widget(Screen1(name='screen1'))
sm.add_widget(Screen2(name='screen2'))
return sm
def show_task_dialog(self):
if not self.task_list_dialog:
self.task_list_dialog = MDDialog(
title="Create Task",
type="custom",
content_cls=DialogContent(),
)
self.task_list_dialog.open()
def close_dialog(self, *args):
self.task_list_dialog.dismiss()
def on_start(self):
"""Load the saved tasks and add them to the MDList widget when the application starts"""
try:
completed_tasks, uncomplete_tasks = db.get_tasks()
if uncomplete_tasks != []:
for task in uncomplete_tasks:
add_task = ListItemWithCheckbox(pk=task[0],text=task[1], secondary_text=task[2])
self.root.ids.container.add_widget(add_task)
if completed_tasks != []:
for task in completed_tasks:
add_task = ListItemWithCheckbox(pk=task[0],text='[s]'+task[1]+'[/s]', secondary_text=task[2])
add_task.ids.check.active = True
self.root.ids.container.add_widget(add_task)
except Exception as e:
print(e)
pass
def add_task(self, task, task_date):
'''Add task to the list of tasks'''
# Add task to the db
created_task = db.create_task(task.text, task_date)# Here
# return the created task details and create a list item
self.root.ids['container'].add_widget(ListItemWithCheckbox(pk=created_task[0], text='[b]'+created_task[1]+'[/b]', secondary_text=created_task[2]))# Here
task.text = ''
if __name__ == '__main__':
app = MainApp()
app.run()
这是main.kv
我必须对要发布的代码进行描述
我必须对要发布的代码进行描述
我必须对要发布的代码进行描述
我必须对要发布的代码进行描述
我必须对要发布的代码进行描述
我必须对要发布的代码进行描述
我必须对要发布的代码进行描述
我必须对要发布的代码进行描述
我必须对要发布的代码进行描述
我必须对要发布的代码进行描述
我必须对要发布的代码进行描述
我必须对要发布的代码进行描述
我必须对要发布的代码进行描述
我必须对要发布的代码进行描述
#:kivy 1.10.1
<Screen1>:
MDTextButton:
text: "Next Screen"
theme_text_color: "Custom"
text_color: rgba(168, 168, 168, 225)
font_size: "50sp"
on_press: app.root.current = "screen2"
<Screen2>:
MDFloatLayout:
MDLabel:
id: task_label
halign: 'center'
markup: True
text: "My Tasks"
font_name: "Poppins-Bold"
font_size: 40
pos_hint: {'y': .45}
ScrollView:
pos_hint: {'center_y': .5, 'center_x': .5}
size_hint: .9, .8
MDList:
id: container
MDFloatingActionButton:
icon: 'plus-thick'
on_release: app.show_task_dialog()
elevation_normal: 12
pos_hint: {'x': .8, 'y':.05}
<DialogContent>:
orientation: "vertical"
spacing: "10dp"
size_hint: 1, None
height: "130dp"
GridLayout:
rows: 1
MDTextField:
id: task_text
hint_text: "Add Task..."
pos_hint: {"center_y": .4}
max_text_length: 50
on_text_validate: (app.add_task(task_text, date_text.text), app.close_dialog())
MDIconButton:
icon: 'calendar'
on_release: root.show_date_picker()
padding: '10dp'
MDLabel:
spacing: '10dp'
id: date_text
BoxLayout:
orientation: 'horizontal'
MDRaisedButton:
text: "SAVE"
on_release: (app.add_task(task_text, date_text.text), app.close_dialog())
MDFlatButton:
text: 'CANCEL'
on_release: app.close_dialog()
<ListItemWithCheckbox>:
id: the_list_item
markup: True
LeftCheckbox:
id: check
on_release:
root.mark(check, the_list_item)
IconRightWidget:
icon: 'trash-can-outline'
theme_text_color: "Custom"
text_color: 1, 0, 0, 1
on_release:
root.delete_item(the_list_item)
在你的方法 add_task
中你做了 self.root.ids['container']
这表明你想从你的根小部件(这里 ScreenManager
).
但是很明显这个根没有分配id。看起来您想要从您的 Screen2
访问 ID container
。为了实现这一目标,您可以这样做,
def add_task(self, task, task_date):
'''Add task to the list of tasks'''
# Add task to the db
created_task = db.create_task(task.text, task_date)# Here
# return the created task details and create a list item
# Access the relevant screen first.
screen2 = self.root.get_screen("screen2")
# Now access the `MDList` and add the items.
screen2.ids['container'].add_widget(ListItemWithCheckbox(pk=created_task[0], text='[b]'+created_task[1]+'[/b]', secondary_text=created_task[2]))# Here
task.text = ''
我想用 kivy/kivymd 做一个待办事项列表应用程序,我想用多个屏幕做它,一切都很好,直到我在列表中添加一个小部件,当我按下时出现这个错误保存。
这是main.py
from cgitb import small
from kivymd.app import MDApp
from kivymd.uix.dialog import MDDialog
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.picker import MDDatePicker
from datetime import datetime
from kivymd.uix.list import TwoLineAvatarIconListItem, ILeftBodyTouch
from kivymd.uix.selectioncontrol import MDCheckbox
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.core.text import LabelBase
from kivy.utils import platform
from kivy.core.window import Window
import sqlite3
Window.size = (360, 640)
class Database:
def __init__(self):
self.con = sqlite3.connect('todo.db')
self.cursor = self.con.cursor()
self.create_task_table()
def create_task_table(self):
"""Create tasks table"""
self.cursor.execute("CREATE TABLE IF NOT EXISTS tasks(id integer PRIMARY KEY AUTOINCREMENT, task varchar(50) NOT NULL, due_date varchar(50), completed BOOLEAN NOT NULL CHECK (completed IN (0, 1)))")
self.con.commit()
def create_task(self, task, due_date=None):
"""Create a task"""
self.cursor.execute("INSERT INTO tasks(task, due_date, completed) VALUES(?, ?, ?)", (task, due_date, 0))
self.con.commit()
# GETTING THE LAST ENTERED ITEM SO WE CAN ADD IT TO THE TASK LIST
created_task = self.cursor.execute("SELECT id, task, due_date FROM tasks WHERE task = ? and completed = 0", (task,)).fetchall()
return created_task[-1]
def get_tasks(self):
"""Get tasks"""
uncomplete_tasks = self.cursor.execute("SELECT id, task, due_date FROM tasks WHERE completed = 0").fetchall()
completed_tasks = self.cursor.execute("SELECT id, task, due_date FROM tasks WHERE completed = 1").fetchall()
return completed_tasks, uncomplete_tasks
def mark_task_as_complete(self, taskid):
"""Marking tasks as complete"""
self.cursor.execute("UPDATE tasks SET completed=1 WHERE id=?", (taskid,))
self.con.commit()
def mark_task_as_incomplete(self, taskid):
"""Mark task as uncomplete"""
self.cursor.execute("UPDATE tasks SET completed=0 WHERE id=?", (taskid,))
self.con.commit()
# return the text of the task
task_text = self.cursor.execute("SELECT task FROM tasks WHERE id=?", (taskid,)).fetchall()
return task_text[0][0]
def delete_task(self, taskid):
"""Delete a task"""
self.cursor.execute("DELETE FROM tasks WHERE id=?", (taskid,))
self.con.commit()
def close_db_connection(self):
self.con.close()
db = Database()
class DialogContent(MDBoxLayout):
"""OPENS A DIALOG BOX THAT GETS THE TASK FROM THE USER"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.ids.date_text.text = str(datetime.now().strftime('%A %d %B %Y'))
def show_date_picker(self):
"""Opens the date picker"""
date_dialog = MDDatePicker()
date_dialog.bind(on_save=self.on_save)
date_dialog.open()
def on_save(self, instance, value, date_range):
"""This functions gets the date from the date picker and converts its it a
more friendly form then changes the date label on the dialog to that"""
date = value.strftime('%A %d %B %Y')
self.ids.date_text.text = str(date)
class ListItemWithCheckbox(TwoLineAvatarIconListItem):
'''Custom list item'''
def __init__(self, pk=None, **kwargs):
super().__init__(**kwargs)
# state a pk which we shall use link the list items with the database primary keys
self.pk = pk
def mark(self, check, the_list_item):
'''mark the task as complete or incomplete'''
if check.active == True:
the_list_item.text = '[s]'+the_list_item.text+'[/s]'
db.mark_task_as_complete(the_list_item.pk)# here
else:
the_list_item.text = str(db.mark_task_as_incomplete(the_list_item.pk))# Here
def delete_item(self, the_list_item):
'''Delete the task'''
self.parent.remove_widget(the_list_item)
db.delete_task(the_list_item.pk)# Here
class LeftCheckbox(ILeftBodyTouch, MDCheckbox):
'''Custom left container'''
class Screen1(Screen):
pass
class Screen2(Screen):
pass
class MainApp(MDApp):
task_list_dialog = None
def build(self):
self.theme_cls.primary_palette = "Blue"
sm = ScreenManager()
sm.add_widget(Screen1(name='screen1'))
sm.add_widget(Screen2(name='screen2'))
return sm
def show_task_dialog(self):
if not self.task_list_dialog:
self.task_list_dialog = MDDialog(
title="Create Task",
type="custom",
content_cls=DialogContent(),
)
self.task_list_dialog.open()
def close_dialog(self, *args):
self.task_list_dialog.dismiss()
def on_start(self):
"""Load the saved tasks and add them to the MDList widget when the application starts"""
try:
completed_tasks, uncomplete_tasks = db.get_tasks()
if uncomplete_tasks != []:
for task in uncomplete_tasks:
add_task = ListItemWithCheckbox(pk=task[0],text=task[1], secondary_text=task[2])
self.root.ids.container.add_widget(add_task)
if completed_tasks != []:
for task in completed_tasks:
add_task = ListItemWithCheckbox(pk=task[0],text='[s]'+task[1]+'[/s]', secondary_text=task[2])
add_task.ids.check.active = True
self.root.ids.container.add_widget(add_task)
except Exception as e:
print(e)
pass
def add_task(self, task, task_date):
'''Add task to the list of tasks'''
# Add task to the db
created_task = db.create_task(task.text, task_date)# Here
# return the created task details and create a list item
self.root.ids['container'].add_widget(ListItemWithCheckbox(pk=created_task[0], text='[b]'+created_task[1]+'[/b]', secondary_text=created_task[2]))# Here
task.text = ''
if __name__ == '__main__':
app = MainApp()
app.run()
这是main.kv 我必须对要发布的代码进行描述 我必须对要发布的代码进行描述 我必须对要发布的代码进行描述 我必须对要发布的代码进行描述 我必须对要发布的代码进行描述 我必须对要发布的代码进行描述 我必须对要发布的代码进行描述 我必须对要发布的代码进行描述 我必须对要发布的代码进行描述 我必须对要发布的代码进行描述 我必须对要发布的代码进行描述 我必须对要发布的代码进行描述 我必须对要发布的代码进行描述 我必须对要发布的代码进行描述
#:kivy 1.10.1
<Screen1>:
MDTextButton:
text: "Next Screen"
theme_text_color: "Custom"
text_color: rgba(168, 168, 168, 225)
font_size: "50sp"
on_press: app.root.current = "screen2"
<Screen2>:
MDFloatLayout:
MDLabel:
id: task_label
halign: 'center'
markup: True
text: "My Tasks"
font_name: "Poppins-Bold"
font_size: 40
pos_hint: {'y': .45}
ScrollView:
pos_hint: {'center_y': .5, 'center_x': .5}
size_hint: .9, .8
MDList:
id: container
MDFloatingActionButton:
icon: 'plus-thick'
on_release: app.show_task_dialog()
elevation_normal: 12
pos_hint: {'x': .8, 'y':.05}
<DialogContent>:
orientation: "vertical"
spacing: "10dp"
size_hint: 1, None
height: "130dp"
GridLayout:
rows: 1
MDTextField:
id: task_text
hint_text: "Add Task..."
pos_hint: {"center_y": .4}
max_text_length: 50
on_text_validate: (app.add_task(task_text, date_text.text), app.close_dialog())
MDIconButton:
icon: 'calendar'
on_release: root.show_date_picker()
padding: '10dp'
MDLabel:
spacing: '10dp'
id: date_text
BoxLayout:
orientation: 'horizontal'
MDRaisedButton:
text: "SAVE"
on_release: (app.add_task(task_text, date_text.text), app.close_dialog())
MDFlatButton:
text: 'CANCEL'
on_release: app.close_dialog()
<ListItemWithCheckbox>:
id: the_list_item
markup: True
LeftCheckbox:
id: check
on_release:
root.mark(check, the_list_item)
IconRightWidget:
icon: 'trash-can-outline'
theme_text_color: "Custom"
text_color: 1, 0, 0, 1
on_release:
root.delete_item(the_list_item)
在你的方法 add_task
中你做了 self.root.ids['container']
这表明你想从你的根小部件(这里 ScreenManager
).
但是很明显这个根没有分配id。看起来您想要从您的 Screen2
访问 ID container
。为了实现这一目标,您可以这样做,
def add_task(self, task, task_date):
'''Add task to the list of tasks'''
# Add task to the db
created_task = db.create_task(task.text, task_date)# Here
# return the created task details and create a list item
# Access the relevant screen first.
screen2 = self.root.get_screen("screen2")
# Now access the `MDList` and add the items.
screen2.ids['container'].add_widget(ListItemWithCheckbox(pk=created_task[0], text='[b]'+created_task[1]+'[/b]', secondary_text=created_task[2]))# Here
task.text = ''