Open nottherealsanta opened 1 year ago
There may be more performant way to achieve the same effect. I hope this is true.
It's 10,000 controls - my guess redux is getting slow... anyway, will take a look in the meantime - interesting case.
As a more performant way to do such kind of visualization I'd look at building SVG and then displaying it in Flet - its Image
control supports SVGs.
...and, yeah, it works faster when only 20x20 are visible because when visible=False
the control is just not rendered at all.
it works faster when only 20x20 are visible because when visible=False the control is just not rendered at all
The laggy on is where 20x20 are visible but there are 100x100 controls. The smooth one only has 20x20 in total
Ah, right, you're right. Then it looks more like redux (most probably my incorrect usage of redux :).
Thanks for your reply. 😄
I am working creating a 2d environment with drag-able containers ( which itself has other elements like buttons and textfield ). I would guess there would be few hundred of these containers. How would I go about doing this ?
What do you mean by redux ?
It's a library Flet uses to maintain app state (controls tree).
Take a look at this
https://user-images.githubusercontent.com/24403606/207780832-e21dbe2e-3fe5-4f4a-be38-f37b4e6592e6.mov
When I drag the main stack, it lags quite a bit.
Only few of those print hello world
containers are set to visible.
Drop me a code sample for that as well.
from flet import *
import flet as ft
from random import randint
class CellType:
CODE = "code"
MARKDOWN = "markdown"
RAW = "raw"
class Cell(Container):
def __init__(
self,
width: int,
text: str,
top: int = 0,
left: int = 0,
**kwargs,
):
self.text = text
self.focused = False
self.side_bar_width = 40
height = self._get_height()
self.text_area = CellTextArea(
text=self.text,
cell_type=CellType.CODE,
on_change=self.on_change,
on_focus=self.on_focus,
on_blur=self.on_blur,
height=height - 20,
width=width - self.side_bar_width,
)
self.side_bar = CellSideBar(
height=height,
width=self.side_bar_width,
on_pan_update=self.on_pan_update,
on_run_click=self.on_run_click,
)
self.stack = Stack(
controls=[
self.text_area,
self.side_bar,
],
height=height,
width=width,
)
self.main_container = Container(
content=self.stack,
border_radius=10,
bgcolor=colors.WHITE,
)
super().__init__(
content=self.main_container,
top=top,
left=left,
width=width,
height=height,
expand=True,
margin=0,
border_radius=10,
clip_behavior=ft.ClipBehavior.HARD_EDGE,
**kwargs,
)
def _get_height(
self,
):
return min(self.text.count("\n") * 25 + 60, 500)
def _set_height(self):
self.height = self._get_height()
self.text_area.set_height(self.height - 20)
self.side_bar.set_height(self.height)
self.update()
def on_pan_update(self, e: DragUpdateEvent):
self.top = max(self.top + e.delta_y, 0)
self.left = max(self.left + e.delta_x, 0)
self.update()
def on_run_click(self, e):
print("Run Clicked")
print(self.text_area.text)
def on_change(self, e):
self.text = e.control.value
self._set_height()
def on_focus(self, e):
print("Focused")
self.focused = True
def on_blur(self, e):
print("Blurred")
self.focused = False
def build(self):
print("Building Cell")
return self
class CellTextArea(Container):
def __init__(
self,
text: str,
height: int,
width: int,
cell_type: str,
on_change,
on_focus,
on_blur,
right: int = 0,
top: int = 0,
):
self.text = text
self.cell_type = cell_type
self.on_change = on_change
self.on_focus = on_focus
self.on_blur = on_blur
self.text_field = TextField(
value=self.text,
on_change=self.on_change,
on_focus=self.on_focus,
on_blur=self.on_blur,
border_width=0,
multiline=True,
border_radius=0,
text_size=16,
content_padding=10,
)
super().__init__(
content=self.text_field,
width=width,
height=height,
expand=True,
margin=0,
# border_radius=10,
right=right,
top=top,
bgcolor=colors.BLUE_GREY_100,
)
def build(self):
return self
def set_height(self, height):
self.height = height
self.update()
class CellSideBar(Stack):
def __init__(self, height: int, width: int, on_pan_update, on_run_click, **kwargs):
self.on_pan_update = on_pan_update
self.on_run_click = on_run_click
self.left_border_color = colors.BLUE
self.run_button = IconButton(
icon=icons.PLAY_ARROW_SHARP,
on_click=self.on_run_click,
)
self.container = Container(
bgcolor=colors.WHITE,
border=border.only(
left=border.BorderSide(width=3, color=self.left_border_color),
right=border.BorderSide(width=0, color=colors.TRANSPARENT),
top=border.BorderSide(width=0, color=colors.TRANSPARENT),
bottom=border.BorderSide(width=0, color=colors.TRANSPARENT),
),
border_radius=10,
)
self.gesture_detector = GestureDetector(
content=self.container,
mouse_cursor=MouseCursor.GRAB,
on_pan_update=self.on_pan_update,
left=0,
top=0,
height=height,
width=width,
)
super().__init__(
controls=[
self.gesture_detector,
# self.run_button,
],
height=height,
width=width,
)
def set_height(self, height):
self.height = height
self.gesture_detector.height = height
self.update()
def build(self):
return self
class OutputArea(Container):
def __init__(self, input_cell: Cell, text: str, **kwargs):
self.input_cell = input_cell
self.text = text
width = input_cell.width
super().__init__(
content=Text(value=self.text),
width=width,
height=1000,
expand=True,
margin=0,
border_radius=10,
bgcolor=colors.BLUE_GREY_100,
top=input_cell.top + input_cell.height + 10,
left=input_cell.left,
)
class Canvas(UserControl):
def __init__(self, width, height, **kwargs):
super().__init__(**kwargs)
self.C = []
for i in range(500):
self.C.append(
Cell(
top=i * 100,
left=100,
width=700,
text='print("Hello World")',
visible=False if i > 100 else True,
)
)
self.gd = GestureDetector(
content=Stack(controls=self.C),
on_pan_update=self.on_pan_update,
mouse_cursor=MouseCursor.GRAB,
top=0,
left=0,
)
self.stack_b = Stack(
controls=[self.gd],
height=height,
width=width,
)
def build(self):
return self.stack_b
def on_pan_update(self, event: DragUpdateEvent):
self.gd.top = self.gd.top + event.delta_y
self.gd.left = self.gd.left + event.delta_x
self.update()
def main(page: Page):
page.scroll = ScrollMode.ALWAYS
# page.auto_scroll = True
page.bgcolor = colors.BLACK12
canvas = Canvas(width=page.width, height=page.height - 100)
def page_resize(e):
# print("New page size:", page.window_width, page.window_height)
print("New page size:", page.width, page.height)
canvas.width = page.width
canvas.height = page.height - 100
page.on_resize = page_resize
page.add(canvas)
View
app(target=main)
Excuse the import *
I am just prototyping here.
Two examples here, one with 100x100 container on stack ( only 20x20 are visible ) and the other with just 20x20.
https://user-images.githubusercontent.com/24403606/207773382-b7931b72-0745-43de-b1cd-dae32fa3f629.mov
https://user-images.githubusercontent.com/24403606/207773357-ee7101ca-8ba4-48b4-ab19-64b01e6053f5.mov
here is the code
for 100x100 ( only 20x20 visible )
for 20x20 visible