2

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

我想向 a 添加拖放功能TTreeView,以便用户可以重新排列树项目的顺序。我已经TTreeView.OnMouseDown根据这个拖放示例项目向事件添加了一个处理程序。

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

如何覆盖此默认行为,以便将 aTTreeViewItem插入到 中的同一级别TTreeView,并且索引 1 大于TTreeViewItem它被拖放到的位置?

4

1 回答 1

1

按照 Abdullah 的建议,您可以通过创建自定义组件来实现此目的。通常创建自定义组件的说明在此处。我建议将它安装在 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 。

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

于 2018-01-16T23:43:29.563 回答