Ошибка Объект 'ControlEvent' не имеет атрибута 'local_x' при использовании flet
Пишу игру-кликер с помощью flet. При написании функции score_up (хочу чтобы на экране появлялось +1, где кликает пользователь) возникла ошибка:
score_count.left = event.local_x
^^^^^^^^^^^^^
AttributeError: 'ControlEvent' object has no attribute 'local_x'
import asyncio
import flet as ft
async def main(page: ft.Page):
page.title = "Привет"
page.theme_mode = ft.ThemeMode.DARK
page.bgcolor = "#141221"
page.vertical_alignment = ft.MainAxisAlignment.CENTER
page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
page.fonts = {"RobotoSlab": "https://github.com/google/fonts/raw/main/apache/robotoslab/RobotoSlab%5Bwght%5D.ttf"}
page.theme = ft.Theme(font_family = "RobotoSlab")
async def score_up(event: ft.ContainerTapEvent):
score.data += 1
score.value = str(score.data)
image.scale = 0.95
score_count.opacity = 50
score_count.value = "+1"
score_count.right = 0
score_count.left = event.local_x
score_count.top = event.local_y
score_count.bottom = 0
progress_bar.value += (1 / 100)
await page.update_async()
await asyncio.sleep(0.1)
image.scale = 1
score_count.opacity = 0
await page.update_async()
score = ft.Text(value="0", size=100, data=0)
score_count = ft.Text(size=50, animate_opacity=ft.Animation(duration=600, curve=ft.AnimationCurve.BOUNCE_IN))
image = ft.Image(src="cat.png", fit=ft.ImageFit.CONTAIN, animate_scale=ft.Animation(duration=600, curve=ft.AnimationCurve.EASE))
progress_bar = ft.ProgressBar(value=0, width=page.width - 100, bar_height=20, color="#ff8b1f", bgcolor="#bf6524")
await page.add_async(
score,
ft.Container(content=ft.Stack(controls=[image, score_count]), on_click=score_up, margin=ft.Margin(0, 0, 0, 30)),
ft.Container(content=progress_bar, border_radius=ft.BorderRadius(10, 10, 10, 10))
)
if __name__ == "__main__":
ft.app(target = main, view = ft.WEB_BROWSER)
Искал решение в документации: нашёл про событие on_click, но должного результата это не дало
Ответы (1 шт):
Автор решения: Mantih
→ Ссылка
В итоге получилось. Разработчики забыли обновить документацию. Нужно делать через on_tap_down()
вместе с on_click()
(без него on_tap_down()
работать не будет).
Вот что я сделал:
Добавил глобальную переменную tap_position
для хранения координат нажатия:
tap_position = (0, 0)
Добавил функцию on_tap_down()
для обработки события нажатия и обновления координат:
def on_tap_down(event: ft.ContainerTapEvent):
global tap_position
tap_position = (event.local_x, event.local_y)
Заменил:
score_count.left = event.local_x
score_count.top = event.local_y
на:
score_count.left = tap_position[0]
score_count.top = tap_position[1]
Добавил обработчик on_tap_down()
в контейнер:
ft.Container(content=ft.Stack(controls=[image, score_count]),
on_click=score_up, on_tap_down=on_tap_down, margin=ft.Margin(0, 0, 0, 30))
Полный код получился таким:
import asyncio
import flet as ft
async def main(page: ft.Page):
page.title = "Привет"
page.theme_mode = ft.ThemeMode.DARK
page.bgcolor = "#141221"
page.vertical_alignment = ft.MainAxisAlignment.CENTER
page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
page.fonts = {"RobotoSlab": "https://github.com/google/fonts/raw/main/apache/robotoslab/RobotoSlab%5Bwght%5D.ttf"}
page.theme = ft.Theme(font_family = "RobotoSlab")
async def score_up(event: ft.ContainerTapEvent):
score.data += 1
score.value = str(score.data)
image.scale = 0.95
score_count.opacity = 50
score_count.value = "+1"
score_count.right = 0
score_count.left = tap_position[0]
score_count.top = tap_position[1]
score_count.bottom = 0
progress_bar.value += (1 / 100)
await page.update_async()
await asyncio.sleep(0.1)
image.scale = 1
score_count.opacity = 0
await page.update_async()
def on_tap_down(event: ft.ContainerTapEvent):
global tap_position
tap_position = (event.local_x, event.local_y)
score = ft.Text(value="0", size=100, data=0)
score_count = ft.Text(size=50, animate_opacity=ft.Animation(duration=600, curve=ft.AnimationCurve.BOUNCE_IN))
image = ft.Image(src="cat.png", fit=ft.ImageFit.CONTAIN, animate_scale=ft.Animation(duration=600, curve=ft.AnimationCurve.EASE))
progress_bar = ft.ProgressBar(value=0, width=page.width - 100, bar_height=20, color="#ff8b1f", bgcolor="#bf6524")
await page.add_async(
score,
ft.Container(content=ft.Stack(controls=[image, score_count]), on_click=score_up, on_tap_down=on_tap_down, margin=ft.Margin(0, 0, 0, 30)),
ft.Container(content=progress_bar, border_radius=ft.BorderRadius(10, 10, 10, 10))
)
if __name__ == "__main__":
tap_position = (0, 0)
ft.app(target = main, view = ft.WEB_BROWSER)