Перетащите с 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.