Error when removing and inserting Control from/to Row Controls #3518
-
QuestionI am trying to create an Infinite Scrolling List of Container that loops through a Finite List of Containers. I tried to make it work by removing first/last Container from the List and inserting it to the end/start of the List, when the Scroll reaches either min_scroll_extent or max_scroll_extent.
Code sampleimport json
import flet as ft
CONTAINER_DEFAULT_SIZE = 175
def onHover(e: ft.HoverEvent):
if e.data == "true":
e.control.border = ft.border.all(
color=ft.colors.RED,
width=3,
)
e.control.shadow = ft.BoxShadow(
spread_radius=1,
blur_radius=10,
color=ft.colors.PRIMARY_CONTAINER,
blur_style=ft.ShadowBlurStyle.OUTER,
)
else:
e.control.border = None
e.control.shadow = ft.BoxShadow(
spread_radius=0,
blur_radius=0,
color=ft.colors.BACKGROUND,
offset=ft.Offset(0, 0),
blur_style=ft.ShadowBlurStyle.OUTER,
)
e.control.update()
def onScroll(e: ft.OnScrollEvent, page: ft.Page):
if e.event_type == "end":
gamesCols = page.views[-1].controls[0].content.controls
gamesRow = gamesCols[0].content
if e.pixels <= e.min_scroll_extent:
lastControl = gamesRow.controls.pop()
gamesRow.controls.insert(0, lastControl)
gamesRow.update()
elif e.pixels >= e.max_scroll_extent:
firstControl = gamesRow.controls.pop(0)
gamesRow.controls.append(firstControl)
gamesRow.update()
def onScrollRoot(e: ft.ScrollEvent, page: ft.Page):
gamesCols = page.views[-1].controls[0].content.controls
gamesRow = gamesCols[0].content
for control in gamesRow.controls: # Without this, Hover Effect is not removed when scrolling
if control.border is not None:
control.border = None
control.shadow = ft.BoxShadow(
spread_radius=0,
blur_radius=0,
color=ft.colors.BACKGROUND,
offset=ft.Offset(0, 0),
blur_style=ft.ShadowBlurStyle.OUTER,
)
control.update()
gamesRow.scroll_to(delta=json.loads(e.data)['dy'])
def main(page: ft.Page):
page.title = "Games"
page.theme_mode = ft.ThemeMode.DARK
page.window_min_width = 800
page.window_min_height = 600
games = ("Snake", "Tetris", "Pong", "Space Invaders", "Flappy Bird", "2048", "Dino", "Brick Breaker", "Frogger", "Sudoku")
gameButtons = list(map(
lambda game: ft.Container(
ft.Row(
[
ft.Text(
game,
size=20,
weight=ft.FontWeight.BOLD,
)
],
alignment=ft.MainAxisAlignment.CENTER
),
width=CONTAINER_DEFAULT_SIZE,
height=CONTAINER_DEFAULT_SIZE,
border_radius=10,
shadow = ft.BoxShadow(
color=ft.colors.BACKGROUND,
blur_style=ft.ShadowBlurStyle.OUTER,
),
bgcolor=ft.colors.ON_PRIMARY,
key=game,
on_hover=onHover,
),
games
))
# gamesRow = ft.ListView(
# gameButtons,
# True,
# 10,
# height=CONTAINER_DEFAULT_SIZE,
# auto_scroll=False,
# on_scroll=lambda e: onScroll(e, page),
# )
gamesRow = ft.Row(
gameButtons,
auto_scroll=False,
scroll=ft.ScrollMode.AUTO,
on_scroll=lambda e: onScroll(e, page),
)
gamesRowScrollDetector = ft.GestureDetector(
gamesRow,
on_scroll=lambda e: onScrollRoot(e, page),
)
page.add(
ft.Container(
ft.Column(
controls=[gamesRowScrollDetector],
alignment=ft.MainAxisAlignment.CENTER,
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
),
expand=True,
alignment=ft.alignment.center,
)
)
if __name__ == "__main__":
ft.app(main) 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\kulsw\AppData\Local\Programs\Python\Python311\Lib\concurrent\futures\thread.py", line 58, in run
result = self.fn(*self.args, **self.kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\Docs\FletTest\.venv\Lib\site-packages\flet_core\page.py", line 528, in wrapper
handler(*args)
File "D:\Docs\FletTest\test.py", line 28, in onHover
e.control.update()
File "D:\Docs\FletTest\.venv\Lib\site-packages\flet_core\control.py", line 293, 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 3 replies
-
Interesting topic. I came up with a simple repro: import flet as ft
def main(page: ft.Page):
def handle_add(e):
t = c.controls.pop(0)
print(f"After Pop: {type(t.page)}")
c.controls.append(t)
c.update()
print(f"After Append+Update: {type(t.page)}\n")
page.add(
ft.OutlinedButton("Trigger", on_click=handle_add),
c := ft.Column(
[
ft.TextButton(
"1", on_hover=lambda e: print(f"OnHover: {type(e.control.page)}")
),
ft.TextButton(
"2", on_hover=lambda e: print(f"OnHover: {type(e.control.page)}")
),
ft.TextButton(
"3", on_hover=lambda e: print(f"OnHover: {type(e.control.page)}")
),
],
scroll=ft.ScrollMode.AUTO,
),
)
ft.app(main) If you click the "Trigger" button, you get this: After Pop: <class 'flet_core.page.Page'>
After Append+Update: <class 'NoneType'> You can notice from here that the control has no page after appended to the column. If you hover on "1" (after at least one click of "Trigger"): OnHover: <class 'NoneType'> The control has no page! :) To solve this issue, I did the following:
|
Beta Was this translation helpful? Give feedback.
Interesting topic.
I came up with a simple repro: