Issue
I want to create a todo app using Kivy. When I add the task using Label it appear with border, this border is created using canvas. The problem is that the border follow the last element created so just one task appear with border others not. This problem appear only when I include the ScrollView.
**The problem in figure below: **
The code:
class TasksBox(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.size_hint = (1, None)
self.cols = 1
self.bind(minimum_height=self.setter("height"))
class ScrollBox(ScrollView):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.size_hint = (1, None)
self.size = (Window.width, Window.height)
class MainWidget(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.size_hint = (1, None)
self.cols = 1
self.spacing = dp(10)
self.padding = dp(10)
self.size_hint = (1, 1)
self.bind(size=lambda instance, value: self.update_size(instance, value, (1, 1, 1)))
self.btn_height = dp(40)
self.text_value = ""
add_button = AddButton(self.btn_height).create()
self.task_field = TaskField(self.btn_height).create()
add_button.bind(on_press=self.create_task)
self.task_field.bind(on_text_validate=self.create_task)
self.task_field.bind(text=self.get_value)
# text input + submit button
box = BoxLayout(size_hint=(1, None), height=self.btn_height, orientation="horizontal")
box.spacing = dp(20)
box.add_widget(self.task_field)
box.add_widget(add_button)
self.add_widget(box)
self.task_field.focus = True
self.tasks_box = TasksBox()
scroll_box = ScrollBox()
scroll_box.add_widget(self.tasks_box)
self.add_widget(scroll_box)
def get_value(self, instance, value):
self.text_value = value
def create_task(self, instance):
todo = Todo()
if len(self.text_value) > 2:
todo.create_task(self.text_value, d.datetime.now().strftime("%Y-%m-%d %H:%M"), "Todo")
self.add_task(todo.get_tasks())
self.task_field.text = ""
else:
print("Please write a task! Contains more than 4 characters!")
self.task_field.focus = True
def add_task(self, tasks):
task = tasks[len(tasks)-1]
task_name = task["name"]
task_id = task["id"]
task_status = task["status"]
task_date = task["date"]
task_box = BoxLayout(size_hint=(1, None), height=self.btn_height)
task_box.spacing = dp(10)
task_name_box = Label(text=task_name, valign="middle", halign="left", size_hint=(.6, None), height=self.btn_height, color=(0, 0, 0), padding=(dp(10)))
task_name_box.bind(size=task_name_box.setter("text_size"))
task_name_box.bind(size=lambda instance, value: self.update_border_size(instance, value, (0, 0, 0)))
task_id_box = Label(text=f"{task_id}", size_hint=(.1, None), height=self.btn_height, color=(1, 1, 1))
task_id_box.bind(size=lambda instance, value: self.update_size(instance, value, (0, .6, 1)))
task_status_box = Label(text=task_status, size_hint=(.1, None), height=self.btn_height, color=(0, 0, 0))
task_status_box.bind(size=lambda instance, value:self.update_size(instance, value, (.5, 1, .5)))
task_date_box = Label(text=f"{task_date}", size_hint=(.2, None), height=self.btn_height, color=(163/255, 163/255, 163/255))
task_date_box.bind(size=lambda instance, value:self.update_border_size(instance, value, (0, 0, 0, .7)))
task_box.add_widget(task_id_box)
task_box.add_widget(task_status_box)
task_box.add_widget(task_name_box)
task_box.add_widget(task_date_box)
self.tasks_box.add_widget(task_box)
def update_size(self, instance, value, color):
instance.canvas.before.clear()
with instance.canvas.before:
instance.canvas.before.clear()
Color(*color)
Rectangle(size=value, pos=instance.pos)
def update_border_size(self, instance, value, color):
instance.canvas.before.clear()
with instance.canvas.before:
instance.canvas.before.clear()
Color(*color)
Line(rectangle=(instance.pos[0], instance.pos[1], value[0], value[1]))
I want each task appear with it border so the canvas update the pos foreach task.
Solution
You have bound your canvas updates to the size of several of the widgets, but most of them are not changing size except when you resize the entire app. However, the TaskBox
changes size every time a new task is added, so bind an update method to the size of the TaskBox
, and use that update method to cycle through all the tasks and update each one.
Answered By - John Anderson
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.