среда, 25 февраля 2026 г.

Полезняшки. DevExpress Custom draw cell - подсветка поисковой строки в ячейке

Подсветка поисковой строки в CxGrid ячейке
код для включения подсветки
procedure TForm3.DBBTCustomDrawCell(Sender: TcxCustomGridTableView;
  ACanvas: TcxCanvas; AViewInfo: TcxGridTableDataCellViewInfo;
  var ADone: Boolean);
var
  idx_DATA2       : Integer;
begin
  {Основной обработчик отрисовки}
  TMyDrawEvent.MyCustomDrawCell(Sender,ACanvas,AViewInfo,ADone);

  idx_DATA2       := GetIndex('_DATA2');
  if AViewInfo.Item.Index = idx_DATA2 then
     TMyDrawEvent.HighlightMiltiTextUseCustomDrawCell(Edit1.Text,
                                                 Sender, ACanvas, AViewInfo, ADone);
end;

Класс

Type
  TMyDrawEvent = class(TObject)
  public
   class procedure MyCustomDrawCell(Sender: TcxCustomGridTableView;
                          ACanvas: TcxCanvas;
                          AViewInfo: TcxGridTableDataCellViewInfo;
                         var ADone: Boolean);   
   // Отрисовка подсветки текста при поиске
   class procedure HighlightMiltiTextUseCustomDrawCell(AText: string;
                          Sender: TcxCustomGridTableView;
                          ACanvas: TcxCanvas;
                          AViewInfo: TcxGridTableDataCellViewInfo;
                          var ADone: Boolean);
  end;


*****

class procedure TMyDrawEvent.HighlightMiltiTextUseCustomDrawCell(AText: string;
  Sender: TcxCustomGridTableView; ACanvas: TcxCanvas;
  AViewInfo: TcxGridTableDataCellViewInfo; var ADone: Boolean);
var
  R: TRect;
  H: Integer;
  brushColor, fontColor: TColor;

  procedure CanvasInitDefault;
  begin
    ACanvas.Font.Style := [];
    ACanvas.Font.Color  := fontColor;
    ACanvas.Brush.Color := brushColor; //$0080FF80;
  end;

  procedure CanvasInitSelection;
  begin
    ACanvas.Font.Style := [];
    ACanvas.Font.Color  := clBlack;  //Sender.LookAndFeelPainter.DefaultSelectionTextColor;
    ACanvas.Brush.Color := clYellow; //Sender.LookAndFeelPainter.DefaultSelectionColor;
  end;

  function GetLengthBlock(Text : String; CanvasSize : Integer; out BlockWidth : Integer) : Integer;
  var
   I : Integer;
   S : string;
  begin
   Result    := 0;
   BlockWidth:= 0;

   I := Length(Text);
   while true do
   begin
       if I < 0  then Exit;
       S := Copy(Text, 1, I);
       BlockWidth := ACanvas.TextWidth(S);
       if BlockWidth > CanvasSize then
       begin
          Dec(I);
          Continue;
       end
       else
       begin
          Result := I;
          exit;
       end
   end;
  end;

  procedure SetRectOutput(var OutRect: TRect; const AreaRect : TRect; const wBlock: Integer);
  begin
   OutRect.Left   := AreaRect.left;
   OutRect.Top    := AreaRect.Top;
   OutRect.Width  := wBlock;
   OutRect.Bottom := AreaRect.Top + H;
  end;

var
  AreaRect, OutRect: TRect;
  posFind, lT, lSearch, wSearch, wS: Integer;
  sTextAll, sSearch,  sBlock, S: string;
  p, wBlock : Integer;
begin
  R          := AViewInfo.Bounds; // Общая область
  sTextAll   := AViewInfo.Text;   // Текст общий

  sSearch := AText; // поисковый запрос
  posFind := AnsiPos(AnsiUpperCase(sSearch), AnsiUpperCase(sTextAll));
  if posFind < 1 then  Exit;

  ADone := True;

  // Цвет и канва
  fontColor  := ACanvas.Font.Color;
  brushColor := ACanvas.Brush.Color;

  // Затираем все
  ACanvas.FillRect(R);
  // Высота текста
  H  := ACanvas.TextHeight(sTextAll);
  // Основная область отрисовки
  AreaRect.Left   := R.Left + 1;
  AreaRect.Top    := R.Top  + 2;
  AreaRect.Right  := R.Right - 1;
  AreaRect.Bottom := R.Bottom - 2;

  CanvasInitDefault;
  sBlock := Copy(sTextAll, 1, PosFind-1);
  if sBlock <> '' then
  begin
      repeat
        // Нужно определить сколь символов влезает в блок текста
        p := GetLengthBlock(sBlock, AreaRect.Width, wBlock);
        s := Copy(sBlock,1, p);

        SetRectOutput(OutRect, AreaRect,wBlock);
        ACanvas.Canvas.TextRect(OutRect, OutRect.Left, OutRect.Top, s);

        Delete(sBlock, 1, p);
        // текст в основной блок не влез, сдвигает вниз
        if sBlock <> '' then
        begin
           Inc(AreaRect.Top, H);
           AreaRect.Left := R.Left + 1;
           if (AreaRect.Bottom - AreaRect.Top) < H then Exit;
        end
        else
           Inc(AreaRect.Left, wBlock)
      until (sBlock = '');
  end;

  CanvasInitSelection;
  sBlock := sSearch;
  repeat
    // Нужно определить сколь символов влезает в блок текста
    p := GetLengthBlock(sBlock, AreaRect.Width, wBlock);
    s := Copy(sBlock,1, p);

    SetRectOutput(OutRect, AreaRect,wBlock);
    ACanvas.Canvas.TextRect(OutRect, OutRect.Left, OutRect.Top, s);

    Delete(sBlock, 1, p);
    // текст в основной блок не влез, сдвигает вниз
    if sBlock <> '' then
    begin
       Inc(AreaRect.Top, H);
       AreaRect.Left := R.Left + 1;
       if (AreaRect.Bottom - AreaRect.Top) < H then Exit;
    end
    else
       Inc(AreaRect.Left, wBlock)
  until (sBlock = '');

  CanvasInitDefault;
  sBlock := Copy(sTextAll, PosFind + Length(sSearch), Length(sTextAll));
  if sBlock <> '' then
  begin
   repeat
    // Нужно определить сколь символов влезает в блок текста
    p := GetLengthBlock(sBlock, AreaRect.Width, wBlock);
    s := Copy(sBlock,1, p);

    SetRectOutput(OutRect, AreaRect,wBlock);
    ACanvas.Canvas.TextRect(OutRect, OutRect.Left, OutRect.Top, s);

    Delete(sBlock, 1, p);
    // текст в основной блок не влез, сдвигает вниз
    if sBlock <> '' then
    begin
       Inc(AreaRect.Top, H);
       AreaRect.Left := R.Left + 1;
       if (AreaRect.Bottom - AreaRect.Top) < H then Exit;
    end
    else
       Inc(AreaRect.Left, wBlock)
   until (sBlock = '');
  end;
end;