Search code examples
delphivirtualtreeview

How to underline or highlight a part of node caption


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


Solution

  • 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:

    enter image description here

    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:

    enter image description here

    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.