跳到主要内容

拖放 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_accepton_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)