Перетащите с TTreeView в Firemonkey

Я использую C++ Builder 10.2.2 Токио с FireMonkey (FMX).

Я хочу добавить функцию перетаскивания в TTreeViewТаким образом, пользователь может изменить порядок элементов дерева. Я добавил обработчик в TTreeView.OnMouseDown событие, основанное на этом примере проекта Drag and Drop.

Благодаря этому программа теперь может перетаскивать элементы, чтобы изменить их порядок, но кажется, что для перемещения TTreeViewItem быть ребенком из TTreeViewItem он вставляется вместо вставки после этого элемента.

Как я могу переопределить это поведение по умолчанию, чтобы TTreeViewItem вставляется на том же уровне в TTreeViewи с индексом 1 больше, чем TTreeViewItem это брошено на?

1 ответ

Следуя предложению Абдуллы, вы можете достичь этого, создав собственный компонент. Направления для создания обычного компонента в целом здесь. Я рекомендую установить его в 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;
}
//---------------------------------------------------------------------------

После установки пользовательского компонента в палитру инструментов вы можете добавить его в форму, как и любой другой компонент.

Отдельное спасибо Майку Саттону, у которого был код для изменения более ранней версии TTreeView здесь.

После добавления в форму установите для параметра AllowDrag элемента управления TMyTreeView значение true.

Другие вопросы по тегам