问题
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;
来源:https://stackoverflow.com/questions/31984898/how-to-underline-or-highlight-a-part-of-node-caption