-->

How to underline or highlight a part of node capti

2019-03-16 22:55发布

问题:

I want to implement a search function in my virtualtreeview. And I want to highlight or underline the searched word in the nodes.

How can I do this? Thank you

回答1:

I would write a handler for the OnDrawText event because it's the only event (at this time) where you'll get passed the node text, the rectangle where that text is about to be rendered as well as the canvas prepared for such rendering. There are more proper events for both tasks (like OnBeforeCellPaint, or OnAfterItemErase for text background highlighting, and OnAfterCellPaint or OnAfterItemPaint for text underlining), just none of them provide text rendering specific parameters as the OnDrawText one.

If your nodes won't be multiline and you don't care about text alignment, reading orientation, nor string shortening, then your task might be as easy as one of the following examples.

1. Matching text background color

procedure TForm1.VirtualTreeDrawText(Sender: TBaseVirtualTree; TargetCanvas: TCanvas;
  Node: PVirtualNode; Column: TColumnIndex; const Text: string; const CellRect: TRect;
  var DefaultDraw: Boolean);
var
  BackMode: Integer;
begin
  // if the just rendered node's Text starts with the text written in a TEdit control
  // called Edit, then...
  if StartsText(Edit.Text, Text) then
  begin
    // store the current background mode; we need to use Windows API here because the
    // VT internally uses it (so the TCanvas object gets out of sync with the DC)
    BackMode := GetBkMode(TargetCanvas.Handle);
    // setup the color and draw the rectangle in a width of the matching text
    TargetCanvas.Brush.Color := clYellow;
    TargetCanvas.FillRect(Rect(
      CellRect.Left,
      CellRect.Top + 1,
      CellRect.Left + TargetCanvas.TextWidth(Copy(Text, 1, Length(Edit.Text))),
      CellRect.Bottom - 1)
    );
    // restore the original background mode (as it likely was modified by setting the
    // brush color)
    SetBkMode(TargetCanvas.Handle, BackMode);
  end;
end;

An example visual output:

2. Matching text underline

procedure TForm1.VirtualTreeDrawText(Sender: TBaseVirtualTree; TargetCanvas: TCanvas;
  Node: PVirtualNode; Column: TColumnIndex; const Text: string; const CellRect: TRect;
  var DefaultDraw: Boolean);
begin
  // if the just rendered node's Text starts with the text written in a TEdit control
  // called Edit, then...
  if StartsText(Edit.Text, Text) then
  begin
    TargetCanvas.Pen.Color := clRed;
    TargetCanvas.MoveTo(CellRect.Left, CellRect.Bottom - 2);
    TargetCanvas.LineTo(
      CellRect.Left + TargetCanvas.TextWidth(Copy(Text, 1, Length(Edit.Text))),
      CellRect.Bottom - 2
    );
  end;
end;

And an example visual output:

In real code I'd suggest pre-calculating those highlight shapes and in the OnDrawText event only draw, but optimization I would leave on you; the main point is the event itself, I think.



回答2:

Little modification. Pay attention to if.

var
  BackMode: integer;
begin
  inherited;

  // if the just rendered node's Text starts with the text written in a TEdit control
  // called Edit, then...
  if StartsText(Sender.SearchBuffer, Text) and (Node = Sender.FocusedNode) then
  begin
    TargetCanvas.Pen.Color := clRed;
    TargetCanvas.MoveTo(CellRect.Left, CellRect.Bottom - 2);
    TargetCanvas.LineTo(
      CellRect.Left + TargetCanvas.TextWidth(Copy(Text, 1, Length(Sender.SearchBuffer))),
      CellRect.Bottom - 2
    );
  end;
end;