[SOLVED] How to stop updating a control during route change #5038
-
Question0 I developed a simple app using Python Flet 0.21.2. The app consists into two main views: the 'Welcome' and the 'Login', each of them defined into separate classes. Routing occurs into the main() function, in the route_change event, in which the 'views_manager()' is called. The 'Welcome' view implements a simple UI, with a container, a progress bar and a button defined into the build method. According to the user control lifecycle documentation, the did_mount() event occurs after the control is added to the page, whilst the will_unmount() event occurs before the control is removed from the page. So, in order to update the layout, which consists of changing the controls color, the update_layout() method is called into the did_mount() event. In the will_unmount() the value of a boolean variable is changed in order to stop the layout updating. Here is the full code. The error occuring when the user clicks on the button is attached below. How can I stop the layout update when the 'Login' view is loaded? Code sampleimport flet as ft
import time
def views_manager(page):
# returns a dictionary of views with keys corresponding to their routes
return {
'/' : Welcome(
parent_page=page,
route='/',
on_click=lambda _: page.go('/login')
),
'/login' : Login(
parent_page=page,
route='login',
on_click=lambda _: page.go('/')
),
}
class Welcome(ft.View):
def __init__(self, parent_page, route, on_click):
super().__init__()
self.padding = 0
self.parent_page = parent_page
self.route = route
self.login_on_click = on_click
self.updating = None
def update_layout(self):
"""
Updates the layout by incrementally changing the progress bar value and updating the background color of the
top container and the login button every 10% of progress.
This function iterates from 0 to 100, updating the progress bar's value and sleeping for 0.05 seconds
between each increment. When the progress reaches a multiple of 10, it changes the background color of
the top container and the login button based on a predefined list of green shades. After reaching 100%,
it resets the progress.
"""
colors = [ft.colors.GREEN_50, ft.colors.GREEN_100, ft.colors.GREEN_200, ft.colors.GREEN_300, ft.colors.GREEN_400, ft.colors.GREEN_500, ft.colors.GREEN_600, ft.colors.GREEN_700, ft.colors.GREEN_800, ft.colors.GREEN_900]
val=0
while val < 101:
if not self.updating:
break
else:
#if self.pb in self.controls:
self.pb.value = val * 0.01
#update container bgcolor every 10%
mod = val % 10
if mod == 0.0:
self.topContainer.bgcolor = colors[int(val/10) - 1]
self.loginButton.style = ft.ButtonStyle(bgcolor=colors[int(val/10) - 1])
#update val value
val += 1
if val == 100:
val=0
#update the page
time.sleep(0.05)
self.update()
def did_mount(self):
self.updating = True
self.update_layout()
def will_unmount(self):
self.updating = False
def build(self):
self.topContainer = ft.Container(
bgcolor=ft.colors.GREEN,
width=self.parent_page.window_width,
height=self.parent_page.window_height * 0.25,
)
self.pb = ft.ProgressBar()
self.loginButton=ft.FilledButton(text="LOGIN", on_click = self.login_on_click)
return ft.Column(
controls=[
self.topContainer,
self.pb,
ft.Row(
[
ft.Container(
content=self.loginButton,
padding=ft.padding.only(top=120),
)
],
alignment="center",
vertical_alignment="end",
)
],
spacing=0,
)
class Login(ft.View):
def __init__(self, parent_page, route, on_click):
super().__init__()
self.parent_page = parent_page
self.route = route
self.back_to_main = on_click
def build(self):
return ft.Container(
content = ft.IconButton(
icon=ft.icons.ARROW_BACK, icon_size=30,
on_click=self.back_to_main,
),
)
def main(page: ft.Page):
def route_change(route):
page.views.clear()
page.views.append(
# returns a dictionary of views with keys corresponding to their routes
views_manager(page)[page.route]
)
page.update()
page.theme = ft.Theme(color_scheme_seed = ft.colors.GREEN)
page.theme_mode = "light"
page.horizontal_alignment = "center"
page.vertical_alignment = "center"
page.window_height = 700
page.window_width = 400
page.window_left = 990
page.window_resizable = False
page.window_maximizable = False
page.on_route_change = route_change
page.go("/")
ft.app(target=main, assets_dir="assets") Error messageFuture exception was never retrieved
future: <Future finished exception=AssertionError('Control must be added to the page first.')>
Traceback (most recent call last):
File "C:\Users\idoec\miniconda3\Lib\concurrent\futures\thread.py", line 58, in run
result = self.fn(*self.args, **self.kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\idoec\Desktop\main.py", line 120, in route_change
page.update()
File "C:\Users\idoec\miniconda3\Lib\site-packages\flet_core\page.py", line 303, in update
self.__handle_mount_unmount(*r)
File "C:\Users\idoec\miniconda3\Lib\site-packages\flet_core\page.py", line 448, in __handle_mount_unmount
ctrl.did_mount()
File "C:\Users\idoec\Desktop\main.py", line 64, in did_mount
self.update_layout()
File "C:\Users\idoec\Desktop\main.py", line 60, in update_layout
self.update()
File "C:\Users\idoec\miniconda3\Lib\site-packages\flet_core\control.py", line 286, in update
assert self.__page, "Control must be added to the page first."
AssertionError: Control must be added to the page first. ------------------------------------------------------
|
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
The problem is that you execute the code, make changes, and then wait for 0.05 seconds. During this time, you switch to the Login state, and only after that do you call self.update(). You need to do the opposite: first call self.update(), then run time.sleep(). |
Beta Was this translation helpful? Give feedback.
The problem is that you execute the code, make changes, and then wait for 0.05 seconds. During this time, you switch to the Login state, and only after that do you call self.update(). You need to do the opposite: first call self.update(), then run time.sleep().