Skip to content

拖放控件 (Drag and Drop) ​


Flet 中的拖放(Drag-and-Drop)机制非常简单 —— 用户开始拖拽 Draggable 控件,并将其“释放”在 DragTarget 控件上。如果拖拽控件和拖拽目标属于同一个分组(group),拖拽目标将调用 on_accept 事件处理函数,并将拖拽控件本身作为 e.src(其 ID 作为 e.src_id)传入。在这种情况下,拖拽控件将作为拖放操作的源"数据"。

让我们来看下面的例子。在下面的程序中,你可以拖动左侧显示 “1” 的控件,并将其放置在右侧显示 “0” 的控件上。当拖动操作完成后,左侧控件会被替换为 “0”,而右侧控件会变成 “1”:

python
import flet as ft

def main(page: ft.Page):
    page.title = "Drag and Drop example"

    def drag_accept(e):
        # 更新拖拽源(Draggable)控件内部 the text
        e.src.content.content.value = "0"
        # 更新拖拽目标(DragTarget)控件内部 the text
        e.control.content.content.value = "1"
        page.update()

    page.add(
        ft.Row(
            controls=[
                ft.Draggable(
                    group="number",
                    content=ft.Container(
                        width=50,
                        height=50,
                        bgcolor=ft.Colors.CYAN_200,
                        border_radius=5,
                        content=ft.Text("1", size=20),
                        alignment=ft.Alignment.CENTER,
                    ),
                ),
                ft.Container(width=100),
                ft.DragTarget(
                    group="number",
                    content=ft.Container(
                        width=50,
                        height=50,
                        bgcolor=ft.Colors.PINK_200,
                        border_radius=5,
                        content=ft.Text("0", size=20),
                        alignment=ft.Alignment.CENTER,
                    ),
                    on_accept=drag_accept,
                ),
            ]
        )
    )

ft.run(main)

拖放数字

因此,当触发 on_accept 事件时,决定“源”控件(Draggable)和“目标”控件(DragTarget)如何变化是开发者的职责。

尝试一些操作 ​

将 DragTarget 的 group 属性更改为 number1,然后注意:当你再次将 “1” 拖放到目标上时,on_accept 事件将不会被触发。

Flet 还提供了其他的属性和事件处理函数,可以让拖放操作更加富有交互性。例如,Draggable 拥有 content_when_dragging 属性,用于在拖动过程中展示一个不同的控件来代替原本的 content 控件。此外,还有一个 content_feedback 属性,用于在指针下方显示一个不同的控件。默认情况下,拖动时指针下方会显示相同的 content 控件,但其不透明度(opacity)会降低为 50%。

让我们修改示例中的 Draggable,在控件被拖走的原位置处显示一个“虚位(hole)”,并在拖动时让指针下方仅显示一个简单的 “1”:

python
...
                ft.Draggable(
                    group="number",
                    content=ft.Container(
                        width=50,
                        height=50,
                        bgcolor=ft.Colors.CYAN_200,
                        border_radius=5,
                        content=ft.Text("1", size=20),
                        alignment=ft.Alignment.CENTER,
                    ),
                    content_when_dragging=ft.Container(
                        width=50,
                        height=50,
                        bgcolor=ft.Colors.BLUE_GREY_200,
                        border_radius=5,
                    ),
                    content_feedback=ft.Text("1"),
                ),
...

拖放数字 2

拖拽目标(DragTarget)控件还额外提供了 on_will_accept 和 on_leave 事件处理函数,它们可以更好地可视化提示何时适合将物体“释放”在目标上。让我们修改示例中的 DragTarget,当其准备好接受拖入的元素时,在目标控件的周围绘制一个边框:

python
import flet as ft

def main(page: ft.Page):
    page.title = "Drag and Drop example 2"

    def drag_accept(e):
        # 更新拖拽源(Draggable)控件内部 the text
        e.src.content.content.value = "0"
        # 重置源控件的分组,使其不能再被拖放到目标上
        e.src.group = ""
        # 更新拖拽目标(DragTarget)控件内部 the text
        e.control.content.content.value = "1"
        # 重置边框
        e.control.content.border = None
        page.update()

    def drag_will_accept(e):
        # 允许释放时显示黑色边框,不允许时显示红色边框
        e.control.content.border = ft.Border.all(
            2, ft.Colors.BLACK_45 if e.data == "true" else ft.Colors.RED
        )
        e.control.update()

    def drag_leave(e):
        e.control.content.border = None
        e.control.update()

    page.add(
        ft.Row(
            controls=[
                ft.Draggable(
                    group="number",
                    content=ft.Container(
                        width=50,
                        height=50,
                        bgcolor=ft.Colors.CYAN_200,
                        border_radius=5,
                        content=ft.Text("1", size=20),
                        alignment=ft.Alignment.CENTER,
                    ),
                    content_when_dragging=ft.Container(
                        width=50,
                        height=50,
                        bgcolor=ft.Colors.BLUE_GREY_200,
                        border_radius=5,
                    ),
                    content_feedback=ft.Text("1"),
                ),
                ft.Container(width=100),
                ft.DragTarget(
                    group="number",
                    content=ft.Container(
                        width=50,
                        height=50,
                        bgcolor=ft.Colors.PINK_200,
                        border_radius=5,
                        content=ft.Text("0", size=20),
                        alignment=ft.Alignment.CENTER,
                    ),
                    on_accept=drag_accept,
                    on_will_accept=drag_will_accept,
                    on_leave=drag_leave,
                ),
            ]
        )
    )

ft.run(main)

拖放数字 3


关注我,学习大模型、大数据、Python等热门技术。