拖放 Drag and drop
Flet中拖放的机制非常简单 - 用户开始拖动Draggable
控件,并将其“放置”在DragTarget
上。如果可拖动控件和拖放目标具有相同的group
,则拖放目标将调用on_accept
事件处理程序,并将可拖动控件的ID作为事件数据传递。在这种情况下,可拖动控件充当拖放操作的源“数据”。
让我们看下面的例子。在下面的程序中,您可以将显示“1”的左侧控件拖放到显示“0”的右侧控件上,当拖放操作完成后,左侧控件会被替换为“0”,而右侧控件则变为“1”:
import flet as ft
def main(page: ft.Page):
page.title = "拖放示例"
def drag_accept(e):
# 通过ID获取可拖动(源)控件
src = page.get_control(e.src_id)
# 更新可拖动控件内的文本
src.content.content.value = "0"
# 更新拖放目标控件内的文本
e.control.content.content.value = "1"
page.update()
page.add(
ft.Row(
[
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.app(target=main)

因此,在on_accept
事件发生时,开发人员有责任确定“源”(可拖动的)和“目标”(拖放目标)控件的行为。
尝试一些内容
将DragTarget的group属性更改为 number1
,并注意当您将“1”放在目标上时不再调用on_accept
事件。
还有一些其他的属性和事件处理程序可以使拖放操作更加交互。例如,可拖动控件具有content_when_dragging
属性,在进行拖动操作时显示与content
不同的控件。还有content_feedback
属性,在指针下方显示不同的控件。默认情况下,当拖动时,会在光标下方显示相同的content
控件,但不透明度为50%。
让我们修改我们的示例中的Draggable,以便在拖动时显示一个“空洞”来代替拖动控件,拖动时光标下方只显示“1”:
...
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"),
),
...

拖放目标控件还具有on_will_accept
和on_leave
事件处理程序,可以帮助更好地可视化何时可以将其拖放到目标上。让我们修改我们的示例中的DragTarget,在准备好接收拖放时绘制目标控件周围的边框:
import flet as ft
def main(page: ft.Page):
page.title = "拖放示例 2"
def drag_accept(e):
# 通过ID获取可拖动(源)控件
src = page.get_control(e.src_id)
# 更新可拖动控件内的文本
src.content.content.value = "0"
# 重置源组,以防无法将其拖放到目标上
src.group = ""
# 更新拖放目标控件内的文本
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.BLACK45 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(
[
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.app(target=main)
