【问题标题】:Drag and drop with TTreeView in Firemonkey在 Firemonkey 中使用 TTreeView 拖放
【发布时间】:2018-06-17 22:32:01
【问题描述】:

我正在使用带有 FireMonkey (FMX) 的 C++ Builder 10.2.2 Tokyo。

我想向TTreeView 添加拖放功能,以便用户可以重新排列树项目的顺序。我在TTreeView.OnMouseDown 事件中添加了一个处理程序,基于this Drag and Drop sample project

有了这个,程序现在可以拖放来重新排列项目,但似乎有一些默认行为可以将 TTreeViewItem 移动到它被拖放到的 TTreeViewItem 的子级,而不是在之后插入那个项目。

如何覆盖此默认行为,以便将 TTreeViewItem 插入到 TTreeView 的同一级别,并在比 TTreeViewItem 大的索引 1 处插入它?

【问题讨论】:

  • 请在您的问题中包含基本代码。没有人应该需要从另一个站点获取详细信息。如果删除或移动链接的资源,您的问题将变得毫无价值。
  • @Tom,虽然我使用示例中提供的代码来启动拖放操作,因为它为拖放操作提供了自定义 bmp,但这不是必需的。将控件的 AllowDrag 设置为 true,并确保 DragMode 设置为 dmManual。同样的问题 - 如何将项目插入与项目相同的级别,而不是默认行为将其添加为项目的子项目
  • 您可以创建自己的组件扩展 TTreeViewItem 然后您可以更改、覆盖或任何您想做的事情。
  • @Abdullah,你能说更多关于这个,包括细节吗?
  • @AnthonyBurg,你有没有创建过自定义组件?创建一个包项目并从 TTreeView 创建 TMyTreeView 类并覆盖您要更改的所有行为。您需要更改的所有内容都可以从您的自定义类中更改。然后你可以在执行相关事件后自动更改节点索引。

标签: drag-and-drop treeview firemonkey c++builder c++builder-10.2-tokyo


【解决方案1】:

按照 Abdullah 的建议,您可以通过创建自定义组件来实现此目的。通常创建自定义组件的说明是here。我建议将它安装在 Tool Palette 上的 Standard 中,因为那是 TTreeView 所在的位置。

这里称为 TMyTreeView 的自定义组件在标题中特别包含:

class PACKAGE TMyTreeView : public TTreeView
{
private:
    bool IsAncestor (TTreeViewItem* oItem, TTreeViewItem* oTargetItem);
protected:
    int DragDelta;
    void StartDrag ();
    void __fastcall DragDrop (const Fmx::Types::TDragObject &Data, const System::Types::TPointF &Point);
    void __fastcall MouseDown (System::Uitypes::TMouseButton Button, System::Classes::TShiftState Shift, float X, float Y);
    void __fastcall MouseMove (System::Classes::TShiftState Shift, float X, float Y);
public:
    __fastcall TMyTreeView(TComponent* Owner);
    __fastcall ~TMyTreeView ();
    TBitmap* DragBmp;
    TPointF MouseDownPoint;
    TTreeViewItem* DragStartItem;
__published:

};
//---------------------------------------------------------------------------

其中函数在对应的cpp文件中如下:

    __fastcall TMyTreeView::TMyTreeView(TComponent* Owner)
    : TTreeView(Owner)
{
    DragBmp = NULL;
    DragStartItem = NULL;
    DragDelta = 5;
}
//---------------------------------------------------------------------------

__fastcall TMyTreeView::~TMyTreeView ()
{
    if (DragBmp)
        delete DragBmp;
}
//---------------------------------------------------------------------------

void __fastcall TMyTreeView::MouseMove (System::Classes::TShiftState Shift, float X, float Y)
{
    TTreeView::MouseMove (Shift, X, Y);

    if ((abs (X-MouseDownPoint.X) > DragDelta) || (abs (Y-MouseDownPoint.Y) > DragDelta))
        StartDrag ();
}
//---------------------------------------------------------------------------

void TMyTreeView::StartDrag ()
{
    if (!AllowDrag)
        return;
    if (!DragStartItem)
        return;

    if (DragBmp)
        delete DragBmp;

    _di_IFMXDragDropService service;
    if ((TPlatformServices::Current->SupportsPlatformService (__uuidof(IFMXDragDropService)) &&
        (service = TPlatformServices::Current->GetPlatformService (__uuidof(IFMXDragDropService)))))
    {
        TDragObject dragData;
        if (!DragStartItem)
            return;
        dragData.Source = DragStartItem;
        DragBmp = DragStartItem->MakeScreenshot ();
        dragData.Data = DragBmp;
        service->BeginDragDrop  ((TForm*)this->Owner, dragData, DragBmp);
        DragStartItem = NULL;
    }

}
//---------------------------------------------------------------------------

void __fastcall TMyTreeView::MouseDown (System::Uitypes::TMouseButton Button, System::Classes::TShiftState Shift, float X, float Y)
{
    TTreeView::MouseDown (Button, Shift, X, Y);

    if (AllowDrag)
    {
        DragStartItem = ItemByPoint (X, Y);
        MouseDownPoint.X = X;
        MouseDownPoint.Y = Y;
    }
    else
        DragStartItem = NULL;
}
//---------------------------------------------------------------------------

void __fastcall TMyTreeView::DragDrop (const Fmx::Types::TDragObject &Data, const System::Types::TPointF &Point)
{
    TTreeViewItem* item = ItemByPoint (Point.X, Point.Y);
    if (!item)
        return;

    TTreeViewItem* srcItem = (TTreeViewItem*)Data.Source;
    if (!srcItem)
        return;

    if (IsAncestor (srcItem, item))
        return;

    if (item->ParentItem ())
        item->ParentItem ()->InsertObject (item->Index, srcItem);
    else
        this->InsertObject (item->Index, srcItem);

    //TTreeView::DragDrop (Data, Point);
}
//---------------------------------------------------------------------------

bool TMyTreeView::IsAncestor (TTreeViewItem* oItem, TTreeViewItem* oTargetItem)
{
    for (int i=0; i<oItem->Count; i++)
    {
        TTreeViewItem* item = oItem->Items [i];
        if (item == oTargetItem)
            return true;
        if (IsAncestor (item, oTargetItem))
            return true;
    }
    return false;
}
//---------------------------------------------------------------------------

将自定义组件安装到工具面板后,您可以像添加任何其他组件一样将其添加到表单中。

特别感谢 Mike Sutton,他有代码可以修改早期版本的 TTreeView here

添加到表单后,将 TMyTreeView 控件的 AllowDrag 设置为 true。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-12
    • 2014-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-01
    相关资源
    最近更新 更多