TVirtualStringTree — это мощный компонент для отображения иерархических данных в Delphi, предоставляющий широкие возможности кастомизации. Одним из востребованных сценариев является добавление кнопки или иконки удаления для узлов, которая становится видимой только при наведении курсора или выборе строки. В этой статье мы рассмотрим, как реализовать такую функциональность.
Подготовка компонента
Для начала необходимо настроить TVirtualStringTree так, чтобы он поддерживал отрисовку дополнительных элементов управления в ячейках.
Для отображения иконки удаления при наведении или выборе узла воспользуемся событием OnBeforeCellPaint.
procedure TForm1.VirtualStringTree1BeforeCellPaint(Sender: TBaseVirtualTree;
TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect);
var
DeleteButtonRect: TRect;
IsHot: Boolean;
begin
if Column = 0 then // Иконка удаления будет в первой колонке
begin
IsHot := (Node = Sender.HotNode) or (vsSelected in Node.States);
if IsHot then
begin
DeleteButtonRect := Rect(
CellRect.Right - 20,
CellRect.Top + 2,
CellRect.Right - 4,
CellRect.Bottom - 2
);
// Рисуем иконку удаления (можно использовать TImageList или системную иконку)
TargetCanvas.Brush.Color := clBtnFace;
TargetCanvas.FillRect(DeleteButtonRect);
TargetCanvas.Pen.Color := clRed;
TargetCanvas.Rectangle(DeleteButtonRect);
TargetCanvas.TextOut(DeleteButtonRect.Left + 4, DeleteButtonRect.Top + 2, 'X');
end;
end;
end;
Обработка клика по иконке
Чтобы обработать клик по иконке удаления, используем событие OnMouseDown:
procedure TForm1.VirtualStringTree1MouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
Node: PVirtualNode;
HitInfo: THitInfo;
DeleteButtonRect: TRect;
begin
if Button = mbLeft then
begin
Sender.GetHitTestInfoAt(X, Y, True, HitInfo);
Node := HitInfo.HitNode;
if Assigned(Node) and (HitInfo.HitColumn = 0) then
begin
DeleteButtonRect := Rect(
Sender.Header.Columns[0].Width - 20,
Sender.GetNodeRect(Node).Top + 2,
Sender.Header.Columns[0].Width - 4,
Sender.GetNodeRect(Node).Bottom - 2
);
if PtInRect(DeleteButtonRect, Point(X, Y)) then
begin
// Удаляем узел
Sender.DeleteNode(Node);
end;
end;
end;
end;
Улучшение UX: анимация и подсказки
Для лучшего пользовательского опыта можно добавить:
Подсказку при наведении на иконку
procedure TForm1.VirtualStringTree1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
Node: PVirtualNode;
HitInfo: THitInfo;
begin
Sender.GetHitTestInfoAt(X, Y, True, HitInfo);
Node := HitInfo.HitNode;
if Assigned(Node) and (HitInfo.HitColumn = 0) then
begin
if IsPointOverDeleteButton(Sender, X, Y) then
ShowMessage('Удалить узел')
else
HideMessage();
end;
end;
Плавное появление иконки (используя AlphaBlend или анимацию через TAnimation)
Альтернативное решение: использование TVTHeaderPopupMenu
Если необходимо реализовать удаление через контекстное меню, можно использовать стандартный механизм TVirtualStringTree:
procedure TForm1.VirtualStringTree1PopupHeader(Sender: TObject;
HitInfo: TVTHeaderHitInfo; const P: TPoint; var Result: Boolean);
begin
if HitInfo.Column = 0 then
begin
PopupMenu1.Popup(P.X, P.Y);
Result := True;
end;
end;
Заключение
Реализация иконки удаления в TVirtualStringTree требует комбинации событий отрисовки и обработки мыши. Предложенный подход позволяет гибко настраивать внешний вид и поведение компонента. Для более сложных сценариев можно использовать дополнительные библиотеки, такие как VirtualTreeView-Styles, или расширить функционал через наследование.
Пример кода можно скачать по ссылке (если применимо).
Оптимизируйте ваш UI с TVirtualStringTree и делайте интерфейсы удобнее!
Реализация отображения и обработки иконки удаления в TVirtualStringTree при наведении или выборе узла с использованием событий отрисовки и мыши.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.