Textual (python) - 如何在简单的Text object中添加点击事件?

Textual (python) - how to add click event in simple Text object?

我正在尝试获取它,以便我可以在 Textual 呈现的文本中添加链接。

我的文字可能有多个链接,例如:

Hello [@click=hello]World[/] there, how are you?
This is a test of [@click=more] more info[/] being clickable as well.

在我制作的这个简单示例中,单击“世界”一词应该有望将背景颜色更改为红色,但它不起作用。

注意:我还绑定了“b”键来做几乎相同的事情,所以我可以看到它有效 它应该更改背景颜色和应用程序的副标题。

import os
import sys
from rich.console import RenderableType
from rich.panel import Panel
from rich.text import Text
from textual.app import App
from textual.widgets import Header, Footer, ScrollView
from textual.widgets import Placeholder

class MyApp(App):

    async def on_load(self) -> None:
        await self.bind("b", "color('blue')")

    async def on_mount(self) -> None:
        await self.view.dock(Header(), size=5, edge="top")
        await self.view.dock(Footer(), edge="bottom")
        await self.view.dock(ScrollView(Panel("Hello [@click=hello]World[/] more info here")), edge="top")

    async def action_color(self, color:str) -> None:
        self.app.sub_title = "KEYBOARD"
        self.background = f"on {color}"

    async def action_hello(self) -> None:
        self.app.sub_title = "CLICKED"
        self.background = "on red"

MyApp.run(title="Test click", log="textual.log")

我在 textual discussions and originally rich discussions 中问过同样的问题,但无法从我在那里收到的反馈中看出如何进行这项工作,这肯定有帮助,但我遗漏了一些东西在这里,非常感谢您的任何意见。

似乎 @click=action 在文本中不起作用(至少我根本无法让它起作用)。
在深入研究了丰富的文档之后,我选择了 Text class。那个有 on method,可以创建 click 回调。

它支持 __add__,因此您可以使用 + 运算符连接多个 Text(s)。

第二个难题是找出要设置为 click 回调的内容。我再次查看源代码并在 app.py 中找到 _action_targets。即包含{"app", "view"}集。

综上所述,您可以使用 Texton(click="app.callback()") 创建 link(s),这将调用 MyApp Class 的 action_callback 方法(文本应用程序的实例)。然后通过将其他 Text(s) 和 link(s) 连接在一起来创建最终面板文本。

这是工作示例,点击 Hello 将背景变为红色或点击 World 变为绿色。

from rich.panel import Panel
from rich.text import Text
from textual.app import App
from textual.widgets import Header, Footer, ScrollView


class MyApp(App):

    async def on_load(self) -> None:
        await self.bind("b", "color('blue')")

    async def on_mount(self) -> None:
        await self.view.dock(Header(), size=5, edge="top")
        await self.view.dock(Footer(), edge="bottom")
        link1 = Text("Hello").on(click="app.hello()")
        link2 = Text("World").on(click="app.world()")
        panel_text = link1 + " " + link2 + Text(" more info here")
        await self.view.dock(ScrollView(Panel(panel_text)), edge="top")

    async def action_color(self, color: str) -> None:
        self.app.sub_title = "KEYBOARD"
        self.background = f"on {color}"

    async def action_hello(self) -> None:
        self.app.sub_title = "CLICKED Hello"
        self.background = "on red"

    async def action_world(self) -> None:
        self.app.sub_title = "CLICKED World"
        self.background = "on green"


MyApp.run(title="Test click", log="textual.log")

我知道这不是理想的解决方案,但它是我最接近您想要的解决方案。

您还可以使用 Text.assemble():

制作具有不同属性的文本
async def on_mount(self) -> None:
    await self.view.dock(Header(), size=5, edge="top")
    await self.view.dock(Footer(), edge="bottom")
    panel_text = Text.assemble(
        "Hello ",
        Text("World","dark_blue u").on({"@click" : "app.hello()"}),
        " more ",
        Text("info","dark_blue u").on({"@click" : "app.color('blue')"}),
         " here")
    await self.view.dock(ScrollView(Panel(panel_text)), edge="top")