flet
flet copied to clipboard
SelectionArea fails for TextSpan elements
Description When ft.Text is in a SelectionArea the on_change callback works as intended, unless either selectable is True or the Text is using TextSpans. In the later case the spans are not selectable (unless selectable is True which breaks the on_change callback). WebView and local Linux client behave identically.
Code example to reproduce the issue:
import flet as ft
name = "CupertinoSegmentedButton example"
def example(tag="plain",s=False):
def pev(e):
try:
print("PEV(%s %s)"%(tag,s),vars(e.data))
except Exception as ex:
print(ex)
print(e)
def pe(e):
try:
print("PE(%s %s)"%(tag,s),vars(e))
except Exception as ex:
print(ex)
pev(e)
return ft.SelectionArea(
content=ft.Text(value="TEST [ %s select %s]\n 43240932840329\nsffsf"%(tag,s),
spans=[ ft.TextSpan("Test\n"), ft.TextSpan("sjflfff\n"), ft.TextSpan("sfsfdfd\n"), ft.TextSpan("sdfsdfsd\n")] if tag != "plain" else None,
selectable=s,
),on_change=pe
)
def main(page: ft.Page):
page.add(example())
page.add(example("spans"))
page.add(example(s=True))
page.add(example("spans",True))
#ft.app(target=main,view=ft.AppView.WEB_BROWSER)
ft.app(target=main)
Describe the results you received:
Only the first text works as expected, this are selectable areas
and only these callbacks are generated:
$ python tcg.py package:media_kit_libs_linux registered. PE(plain False) {'target': '_2', 'name': 'change', 'data': '', 'control': SelectionArea(), 'page': Page(id='page', route='/', pwa='false', web='false', debug='false', platform='linux', platformbrightness='light', media='{"padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_insets":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0}}', width='1280.0', height='720.0', windowwidth='1280.0', windowheight='720.0', windowtop='0.0', windowleft='0.0', clientip='', clientuseragent='', windowminimized='false', windowmaximized='false', windowfocused='false', windowfullscreen='false')} PE(plain False) {'target': '_2', 'name': 'change', 'data': 'T', 'control': SelectionArea(), 'page': Page(id='page', route='/', pwa='false', web='false', debug='false', platform='linux', platformbrightness='light', media='{"padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_insets":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0}}', width='1280.0', height='720.0', windowwidth='1280.0', windowheight='720.0', windowtop='0.0', windowleft='0.0', clientip='', clientuseragent='', windowminimized='false', windowmaximized='false', windowfocused='false', windowfullscreen='false')} PE(plain False) {'target': '_2', 'name': 'change', 'data': 'TE', 'control': SelectionArea(), 'page': Page(id='page', route='/', pwa='false', web='false', debug='false', platform='linux', platformbrightness='light', media='{"padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_insets":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0}}', width='1280.0', height='720.0', windowwidth='1280.0', windowheight='720.0', windowtop='0.0', windowleft='0.0', clientip='', clientuseragent='', windowminimized='false', windowmaximized='false', windowfocused='false', windowfullscreen='false')} PE(plain False) {'target': '_2', 'name': 'change', 'data': 'TEST [ plain select False]\n 432', 'control': SelectionArea(), 'page': Page(id='page', route='/', pwa='false', web='false', debug='false', platform='linux', platformbrightness='light', media='{"padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_insets":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0}}', width='1280.0', height='720.0', windowwidth='1280.0', windowheight='720.0', windowtop='0.0', windowleft='0.0', clientip='', clientuseragent='', windowminimized='false', windowmaximized='false', windowfocused='false', windowfullscreen='false')} PE(plain False) {'target': '_2', 'name': 'change', 'data': 'TEST [ plain select False]\n 4324', 'control': SelectionArea(), 'page': Page(id='page', route='/', pwa='false', web='false', debug='false', platform='linux', platformbrightness='light', media='{"padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_insets":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0}}', width='1280.0', height='720.0', windowwidth='1280.0', windowheight='720.0', windowtop='0.0', windowleft='0.0', clientip='', clientuseragent='', windowminimized='false', windowmaximized='false', windowfocused='false', windowfullscreen='false')} PE(plain False) {'target': '_2', 'name': 'change', 'data': 'TEST [ plain select False]\n 43240932840329\nsffsf', 'control': SelectionArea(), 'page': Page(id='page', route='/', pwa='false', web='false', debug='false', platform='linux', platformbrightness='light', media='{"padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_insets":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0}}', width='1280.0', height='720.0', windowwidth='1280.0', windowheight='720.0', windowtop='0.0', windowleft='0.0', clientip='', clientuseragent='', windowminimized='false', windowmaximized='false', windowfocused='false', windowfullscreen='false')} PE(plain False) {'target': '_2', 'name': 'change', 'data': '', 'control': SelectionArea(), 'page': Page(id='page', route='/', pwa='false', web='false', debug='false', platform='linux', platformbrightness='light', media='{"padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_insets":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0}}', width='1280.0', height='720.0', windowwidth='1280.0', windowheight='720.0', windowtop='0.0', windowleft='0.0', clientip='', clientuseragent='', windowminimized='false', windowmaximized='false', windowfocused='false', windowfullscreen='false')}
Describe the results you expected:
Expectation is receiving events also for text-spans, ideally as array with text_span-id + selected text in span
Additional information you deem important (e.g. issue happens only occasionally):
Flet version (pip show flet
):
Name: flet
Version: 0.22.0
Summary: Flet for Python - easily build interactive multi-platform apps in Python
Home-page:
Author: Appveyor Systems Inc.
Author-email: [email protected]
License: Apache-2.0
Location: /home/grefen/.local/lib/python3.12/site-packages
Requires: cookiecutter, fastapi, flet-runtime, packaging, qrcode, uvicorn, watchdog
Required-by:
``
**Operating system**:
<!--
Linux
-->
**Additional environment details:**
One hint is in https://github.com/flutter/flutter/issues/113530 , in the thread the recommendation is to use Text.rich instead of RichText. Text.dart:
return control.attrBool("selectable", false)!
? (spans.isNotEmpty)
? SelectableText.rich(
TextSpan(text: text, style: style, children: spans),
maxLines: maxLines,
textAlign: textAlign,
)
: SelectableText(
text,
semanticsLabel: semanticsLabel,
maxLines: maxLines,
style: style,
textAlign: textAlign,
)
: (spans.isNotEmpty)
? RichText(
text: TextSpan(text: text, style: style, children: spans),
maxLines: maxLines,
softWrap: !noWrap,
textAlign: textAlign,
overflow: overflow,
)
: Text(
text,
semanticsLabel: semanticsLabel,
maxLines: maxLines,
softWrap: !noWrap,
style: style,
textAlign: textAlign,
overflow: overflow,
);
I'm going to try a build with the change
The following patch seems to fix it:
git diff -u ../packages/flet/lib/src/controls/text.dart
diff --git a/packages/flet/lib/src/controls/text.dart b/packages/flet/lib/src/controls/text.dart
index 7d489e5..54d8217 100644
--- a/packages/flet/lib/src/controls/text.dart
+++ b/packages/flet/lib/src/controls/text.dart
@@ -116,8 +116,9 @@ class TextControl extends StatelessWidget with FletStoreMixin {
textAlign: textAlign,
)
: (spans.isNotEmpty)
- ? RichText(
- text: TextSpan(text: text, style: style, children: spans),
+ ? Text.rich(
+ TextSpan(text: text, style: style, children: spans),
+ semanticsLabel: semanticsLabel,
maxLines: maxLines,
softWrap: !noWrap,
textAlign: textAlign,
Will you mind opening a PR with the suggestion?