Skip to content

Commit 6a55d69

Browse files
committed
Refactor ToDo tutorial to use code includes
Updated the ToDo tutorial to reference example code files using --8<-- includes instead of embedding code directly. Improved formatting, clarified instructions, and streamlined explanations for better readability and maintainability.
1 parent a8df00a commit 6a55d69

File tree

1 file changed

+25
-213
lines changed
  • sdk/python/packages/flet/docs/tutorials

1 file changed

+25
-213
lines changed

sdk/python/packages/flet/docs/tutorials/todo.md

Lines changed: 25 additions & 213 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
title: ToDo Tutorial
3+
examples: ../../examples/tutorials/todo
34
---
45

56
In this tutorial we will show you, step-by-step, how to create a To-Do app in Python using Flet framework and then publish it as a desktop, mobile or web app. The app is a single-file console program of just
@@ -22,55 +23,37 @@ The tutorial consists of the following steps:
2223
* [Final touches](#final-touches)
2324
* [Publishing the app](#publishing-the-app)
2425

25-
/// details | For beginners
26-
type: info
27-
To create a multi-platform app in Python with Flet, you don't need to know HTML, CSS or JavaScript, but you do need a basic knowledge of Python and object-oriented programming.
26+
## Getting started with Flet
27+
28+
To create a multi-platform app in Python with Flet, you don't need to know HTML,
29+
CSS or JavaScript, but you do need a basic knowledge of Python and object-oriented
30+
programming.
2831

2932
Before you can create your first Flet app, you need to
30-
[setup your development environment](../getting-started/installation.md).
33+
[setup your development environment](../getting-started/installation.md), which requires Python 3.10 or above and `flet` package.
3134

3235
Once you have Flet installed, let's [create](../getting-started/create-flet-app.md) a simple hello-world app.
3336

3437
Create `hello.py` with the following contents:
3538

3639
```python title="hello.py"
37-
import flet as ft
38-
39-
def main(page: ft.Page):
40-
page.add(ft.Text(value="Hello, world!"))
41-
42-
ft.run(main)
40+
--8<-- "{{ examples }}/hello.py"
4341
```
4442

45-
Run this app, and you will see a new window with a greeting:
43+
Run this app and you will see a new window with a greeting:
4644

4745
{{ image("../examples/tutorials/todo/media/hello-world.png", alt="hello-world", width="80%") }}
4846

4947

50-
///
51-
5248
## Adding page controls and handling events
5349

54-
To start, we'll need a [`TextField`][flet.TextField] for entering a task name, and an "+"
55-
[`FloatingActionButton`][flet.FloatingActionButton] with an event handler that will display
56-
a [`Checkbox`][flet.Checkbox] with a new task.
50+
To start, we'll need a [`TextField`][flet.TextField] for entering a task name, and "+"
51+
[`FloatingActionButton`][flet.FloatingActionButton] with an event handler that will display a [`Checkbox`][flet.Checkbox] with a new task.
5752

5853
Create `todo.py` with the following contents:
5954

6055
```python title="todo.py"
61-
import flet as ft
62-
63-
def main(page: ft.Page):
64-
def add_clicked(e):
65-
page.add(ft.Checkbox(label=new_task.value))
66-
new_task.value = ""
67-
page.update()
68-
69-
new_task = ft.TextField(hint_text="What's needs to be done?")
70-
71-
page.add(new_task, ft.FloatingActionButton(icon=ft.Icons.ADD, on_click=add_clicked))
72-
73-
ft.run(main)
56+
--8<-- "{{ examples }}/step_1.py"
7457
```
7558

7659
Run the app and you should see a page like this:
@@ -80,8 +63,7 @@ Run the app and you should see a page like this:
8063

8164
### Page layout
8265

83-
Now let's make the app look nice! We want the entire app to be at the top center of the page,
84-
taking up 600 px width. The TextField and the "+" button should be aligned horizontally, and take up full app width:
66+
Now let's make the app look nice! We want the entire app to be at the top center of the page, taking up 600 px width. The TextField and the "+" button should be aligned horizontally, and take up full app width:
8567

8668
{{ image("../examples/tutorials/todo/media/diagram-1.svg", alt="diagram-1", width="80%") }}
8769

@@ -91,34 +73,8 @@ taking up 600 px width. The TextField and the "+" button should be aligned horiz
9173

9274
Replace `todo.py` contents with the following:
9375

94-
```python title="todo.py"
95-
import flet as ft
96-
97-
def main(page: ft.Page):
98-
def add_clicked(e):
99-
tasks_view.controls.append(ft.Checkbox(label=new_task.value))
100-
new_task.value = ""
101-
view.update()
102-
103-
new_task = ft.TextField(hint_text="What needs to be done?", expand=True)
104-
tasks_view = ft.Column()
105-
view=ft.Column(
106-
width=600,
107-
controls=[
108-
ft.Row(
109-
controls=[
110-
new_task,
111-
ft.FloatingActionButton(icon=ft.Icons.ADD, on_click=add_clicked),
112-
],
113-
),
114-
tasks_view,
115-
],
116-
)
117-
118-
page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
119-
page.add(view)
120-
121-
ft.run(main)
76+
```python title="hello.py"
77+
--8<-- "{{ examples }}/step_2.py"
12278
```
12379

12480
Run the app and you should see a page like this:
@@ -128,54 +84,12 @@ Run the app and you should see a page like this:
12884

12985
### Reusable UI components
13086

131-
While we could continue writing our app in the `main` function, the best practice would be to
132-
create a [reusable UI component](../cookbook/custom-controls.md). Imagine you are working on an app header, a side menu,
133-
or UI that will be a part of a larger project. Even if you can't think of such uses right now,
134-
we still recommend creating all your Flet apps with composability and reusability in mind.
87+
While we could continue writing our app in the `main` function, the best practice would be to create a [reusable UI component](../cookbook/custom-controls.md). Imagine you are working on an app header, a side menu, or UI that will be a part of a larger project. Even if you can't think of such uses right now, we still recommend creating all your Flet apps with composability and reusability in mind.
13588

136-
To make a reusable To-Do app component, we are going to encapsulate its state and presentation
137-
logic in a separate class:
89+
To make a reusable To-Do app component, we are going to encapsulate its state and presentation logic in a separate class:
13890

13991
```python title="todo.py"
140-
import flet as ft
141-
142-
class TodoApp(ft.Column):
143-
# application's root control is a Column containing all other controls
144-
def __init__(self):
145-
super().__init__()
146-
self.new_task = ft.TextField(hint_text="What needs to be done?", expand=True)
147-
self.tasks_view = ft.Column()
148-
self.width = 600
149-
self.controls = [
150-
ft.Row(
151-
controls=[
152-
self.new_task,
153-
ft.FloatingActionButton(
154-
icon=ft.Icons.ADD, on_click=self.add_clicked
155-
),
156-
],
157-
),
158-
self.tasks_view,
159-
]
160-
161-
def add_clicked(self, e):
162-
self.tasks_view.controls.append(ft.Checkbox(label=self.new_task.value))
163-
self.new_task.value = ""
164-
self.update()
165-
166-
167-
def main(page: ft.Page):
168-
page.title = "To-Do App"
169-
page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
170-
page.update()
171-
172-
# create application instance
173-
todo = TodoApp()
174-
175-
# add application's root control to the page
176-
page.add(todo)
177-
178-
ft.run(main)
92+
--8<-- "{{ examples }}/step_3.py"
17993
```
18094

18195
/// details | Try this out!
@@ -195,127 +109,25 @@ page.add(app1, app2)
195109
## View, edit and delete list items
196110

197111
In the [previous step](#adding-page-controls-and-handling-events), we created a basic To-Do app with task items shown as checkboxes.
198-
Let's improve the app by adding "Edit" and "Delete" buttons next to a task name. The "Edit" button
199-
will switch a task item to edit mode.
112+
Let's improve the app by adding "Edit" and "Delete" buttons next to a task name. The "Edit" button will switch a task item to edit mode.
200113

201114
{{ image("../examples/tutorials/todo/media/diagram-2.svg", alt="diagram-2", width="80%") }}
202115

203116

204-
Each task item is represented by two rows: `display_view` row with Checkbox, "Edit" and "Delete"
205-
buttons and `edit_view` row with TextField and "Save" button. `view` column serves as a container
206-
for both `display_view` and `edit_view` rows.
117+
Each task item is represented by two rows: `display_view` row with Checkbox, "Edit" and "Delete" buttons and `edit_view` row with TextField and "Save" button. `view` column serves as a container for both `display_view` and `edit_view` rows.
207118

208-
Before this step, the code was short enough to be fully included in the tutorial. Going forward,
209-
we will be highlighting only the changes introduced in a step.
119+
To encapsulate task item views and actions, we introduced a new `Task` class.
210120

211-
Copy the entire code for this step from [here](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/tutorials/todo/to-do-4.py). Below we will explain the changes we've done
212-
to implement view, edit, and delete tasks.
121+
Additionally, we changed `TodoApp` class to create and hold `Task` instances when the "Add" button is clicked.
213122

214-
To encapsulate task item views and actions, we introduced a new `Task` class:
123+
For "Delete" task operation, we implemented `task_delete()` method in `TodoApp` class which accepts task control instance as a parameter.
215124

216-
```python title="todo.py"
217-
class Task(ft.Column):
218-
def __init__(self, task_name, task_delete):
219-
super().__init__()
220-
self.task_name = task_name
221-
self.task_delete = task_delete
222-
self.display_task = ft.Checkbox(value=False, label=self.task_name)
223-
self.edit_name = ft.TextField(expand=1)
224-
225-
self.display_view = ft.Row(
226-
alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
227-
vertical_alignment=ft.CrossAxisAlignment.CENTER,
228-
controls=[
229-
self.display_task,
230-
ft.Row(
231-
spacing=0,
232-
controls=[
233-
ft.IconButton(
234-
icon=ft.Icons.CREATE_OUTLINED,
235-
tooltip="Edit To-Do",
236-
on_click=self.edit_clicked,
237-
),
238-
ft.IconButton(
239-
ft.Icons.DELETE_OUTLINE,
240-
tooltip="Delete To-Do",
241-
on_click=self.delete_clicked,
242-
),
243-
],
244-
),
245-
],
246-
)
247-
248-
self.edit_view = ft.Row(
249-
visible=False,
250-
alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
251-
vertical_alignment=ft.CrossAxisAlignment.CENTER,
252-
controls=[
253-
self.edit_name,
254-
ft.IconButton(
255-
icon=ft.Icons.DONE_OUTLINE_OUTLINED,
256-
icon_color=ft.Colors.GREEN,
257-
tooltip="Update To-Do",
258-
on_click=self.save_clicked,
259-
),
260-
],
261-
)
262-
self.controls = [self.display_view, self.edit_view]
263-
264-
def edit_clicked(self, e):
265-
self.edit_name.value = self.display_task.label
266-
self.display_view.visible = False
267-
self.edit_view.visible = True
268-
self.update()
269-
270-
def save_clicked(self, e):
271-
self.display_task.label = self.edit_name.value
272-
self.display_view.visible = True
273-
self.edit_view.visible = False
274-
self.update()
275-
276-
def delete_clicked(self, e):
277-
self.task_delete(self)
278-
```
279-
280-
Additionally, we changed `TodoApp` class to create and hold `Task` instances when the "Add" button is clicked:
125+
Then, we passed a reference to `task_delete` method into Task constructor and called it on "Delete" button event handler.
281126

282127
```python title="todo.py"
283-
class TodoApp(ft.Column):
284-
# application's root control is a Column containing all other controls
285-
def __init__(self):
286-
super().__init__()
287-
self.new_task = ft.TextField(hint_text="What needs to be done?", expand=True)
288-
self.tasks = ft.Column()
289-
self.width = 600
290-
self.controls = [
291-
ft.Row(
292-
controls=[
293-
self.new_task,
294-
ft.FloatingActionButton(
295-
icon=ft.Icons.ADD, on_click=self.add_clicked
296-
),
297-
],
298-
),
299-
self.tasks,
300-
]
301-
302-
def add_clicked(self, e):
303-
task = Task(self.new_task.value, self.task_delete)
304-
self.tasks.controls.append(task)
305-
self.new_task.value = ""
306-
self.update()
307-
308-
def task_delete(self, task):
309-
self.tasks.controls.remove(task)
310-
self.update()
128+
--8<-- "{{ examples }}/step_4.py"
311129
```
312130

313-
For "Delete" task operation, we implemented `task_delete()` method in `TodoApp` class which
314-
accepts task control instance as a parameter.
315-
316-
Then, we passed a reference to `task_delete` method into Task constructor and called it on
317-
"Delete" button event handler.
318-
319131
Run the app and try to edit and delete tasks:
320132

321133
{{ image("../examples/tutorials/todo/media/view-edit-delete.gif", alt="view-edit-delete", width="80%") }}

0 commit comments

Comments
 (0)