Delphi 如何自定义绘制TEdit控件文本?

Delphi 如何自定义绘制TEdit控件文本?,delphi,vcl,Delphi,Vcl,我想画一段TEdit。文字,使用不同于默认的字体。颜色。有没有什么例子可以说明如何做到这一点 我正在尝试这样做: 注意:这个屏幕截图只是一个毛茸茸的草稿,但它让我确信什么问题是可以解决的。否。标准tEdit不支持自定义绘图或具有多种颜色的文本。作为替代,您可以将tRichEdit与WantReturns=False一起使用。Edit控件没有所有者绘制支持,但您可以通过对其进行子分类并处理WM_PAINT(以及许多其他消息)来自定义绘制。这是可行的,但要真正100%正确地实现,这将是一个痛苦的世

我想画一段TEdit。文字,使用不同于默认的字体。颜色。有没有什么例子可以说明如何做到这一点

我正在尝试这样做:


注意:这个屏幕截图只是一个毛茸茸的草稿,但它让我确信什么问题是可以解决的。

否。标准tEdit不支持自定义绘图或具有多种颜色的文本。作为替代,您可以将tRichEdit与WantReturns=False一起使用。

Edit
控件没有所有者绘制支持,但您可以通过对其进行子分类并处理
WM_PAINT
(以及许多其他消息)来自定义绘制。这是可行的,但要真正100%正确地实现,这将是一个痛苦的世界。从文件中:

请注意,所有者绘图适用于大多数控件。但是,它不适用于编辑控件;对于列表控件,它仅适用于报表视图样式

我还想知道兔子洞有多深,所以,
下面是一个使用插入器类的代码示例(仍然需要实现选择,但当插入符号位于控件中时,自定义图形可以工作):


kobik solusion的一些改进:

procedure TMyEdit.Paint;
var
  R: TRect;
  I: Integer;

  NewColor : TColor;
  NewBackColor : TColor;

  procedure DrawEx(S: String);
  begin
     if ((i-1)>=Self.SelStart) and ((i-1)<=(Self.SelStart+(Self.SelLength-1)))
        and (Self.SelLength>0) and (Self.focused)
       then begin
         Canvas.Font.Color  := clWhite;
         Canvas.Brush.Color := NewColor;
       end else begin
         Canvas.Font.Color  := NewColor;
         Canvas.Brush.Color := NewBackColor;
       end;
     Canvas.Brush.Style := bsSolid;
     DrawText(Canvas.Handle, PChar(S), -1, R, DT_LEFT or DT_NOPREFIX or
       DT_WORDBREAK or DrawTextBiDiModeFlagsReadingOnly);
  end;

begin
  R := ClientRect;
  Inc(R.Left, 1);
  Inc(R.Top, 1);
  Canvas.Brush.Assign(Self.Brush);
  Canvas.Font.Assign(Self.Font);

  if Self.Focused then begin
      NewBackColor       := clYellow;
      Canvas.Brush.Color := NewBackColor;
      Canvas.Brush.Style := bsSolid;
      Canvas.FillRect(ClientRect);
      Canvas.DrawFocusRect(ClientRect);
    end else NewBackColor := clWhite;

  for I:=1 to Length(Text) do begin
   if PasswordChar=#0 then begin
     if Text[I] in ['0'..'9'] then begin
       NewColor := clRed;
       DrawEx(Text[I]);
      end else begin
       NewColor := clGreen;
       DrawEx(Text[I]);
      end;
     Inc(R.Left,Canvas.TextWidth(Text[I]));
    end else begin //with passwordchar
       NewColor := clBlack;
       DrawEx(PasswordChar);
     Inc(R.Left,Canvas.TextWidth(PasswordChar));
    end;
  end;
end;
程序TMyEdit.Paint;
变量
R:TRect;
I:整数;
新颜色:TColor;
NewBackColor:TColor;
程序抽屉X(S:字符串);
开始
如果((i-1)>=Self.SelStart)和((i-1)0)以及(自聚焦)
然后开始
Canvas.Font.Color:=clWhite;
Canvas.Brush.Color:=NewColor;
结束,否则开始
Canvas.Font.Color:=NewColor;
Canvas.Brush.Color:=NewBackColor;
结束;
Canvas.Brush.Style:=bsSolid;
DrawText(Canvas.Handle、PChar、-1、R、DT_LEFT或DT_NOPREFIX或
DT_断字或DrawTextBiDiModeFlagsReadingOnly);
结束;
开始
R:=ClientRect;
公司(左右1);
公司(R.Top,1);
Canvas.Brush.Assign(Self.Brush);
Canvas.Font.Assign(Self.Font);
如果自我专注,那么就开始吧
NewBackColor:=clYellow;
Canvas.Brush.Color:=NewBackColor;
Canvas.Brush.Style:=bsSolid;
Canvas.FillRect(ClientRect);
Canvas.DrawFocusRect(ClientRect);
end else NewBackColor:=clWhite;
对于I:=1到长度(文本)不开始
如果PasswordChar=#0,则开始
如果文本[I]在['0'..'9']中,则开始
NewColor:=clRed;
付款人(文本[I]);
结束,否则开始
新颜色:=clGreen;
付款人(文本[I]);
结束;
Inc(右左,Canvas.TextWidth(Text[I]);
end else begin//with passwordchar
NewColor:=clBlack;
paurex(PasswordChar);
Inc(右左,Canvas.TextWidth(PasswordChar));
结束;
结束;
结束;

另一个小改进是重写CreateParams过程,该过程修复了文本选择过程中的闪烁(鼠标左键按下时移动):


我同意添加自定义绘图支持是一个真正的PITA,因为它直接来自TWinControl,但是我已经证明了它是非常可行的。@用户-如果您的自定义绘图在插入符号位于控件中时工作,我会感到惊讶。是吗?@SertacAkyuz,说我迄今为止的尝试“有效”将是非常大胆的声明:-)但我不相信这是不可行的。@Mike W,编辑控件没有owner draw支持,但您可以通过对其进行子分类并处理
WM_PAINT
(以及许多其他消息)来自定义绘制它。“这是可行的,但那将是一个痛苦的世界。”科比克同意。我应该说“没有内置支持”,欢迎您分享您的“解决方案”,这样我们可以讨论它,并提供反馈(截图不是解决方案)。@kobik,可能有一系列简单的问题专门针对我偶然发现的特定问题。但这可能会在以后发生,目前我没有被卡住。谢谢,这个例子真的推动了我的研究,并指出了我完全忽略的许多细微差别(例如,CSCUSTOMPINT)。因为你没有使用控件自己的表面,你必须考虑所有可能的显示情况。例如,除了选择之外,您还必须考虑文本何时应该以第一个字符以外的其他字符开始显示-文本何时更大以适合控件,并且用户已将其滚动到底。实际上,您将要做的是开发编辑控件,而不是使用它@SertacAkyuz我刚刚使用了kobik提供的代码,只更改了文本的绘制方式,并且您提到的所有案例都得到了正确处理。虽然这是5年后的事了,而且是在不同的OS和Delphi版本上,但是作为参考,上面的代码对于我必须做的事情非常有用。
procedure TMyEdit.Paint;
var
  R: TRect;
  I: Integer;

  NewColor : TColor;
  NewBackColor : TColor;

  procedure DrawEx(S: String);
  begin
     if ((i-1)>=Self.SelStart) and ((i-1)<=(Self.SelStart+(Self.SelLength-1)))
        and (Self.SelLength>0) and (Self.focused)
       then begin
         Canvas.Font.Color  := clWhite;
         Canvas.Brush.Color := NewColor;
       end else begin
         Canvas.Font.Color  := NewColor;
         Canvas.Brush.Color := NewBackColor;
       end;
     Canvas.Brush.Style := bsSolid;
     DrawText(Canvas.Handle, PChar(S), -1, R, DT_LEFT or DT_NOPREFIX or
       DT_WORDBREAK or DrawTextBiDiModeFlagsReadingOnly);
  end;

begin
  R := ClientRect;
  Inc(R.Left, 1);
  Inc(R.Top, 1);
  Canvas.Brush.Assign(Self.Brush);
  Canvas.Font.Assign(Self.Font);

  if Self.Focused then begin
      NewBackColor       := clYellow;
      Canvas.Brush.Color := NewBackColor;
      Canvas.Brush.Style := bsSolid;
      Canvas.FillRect(ClientRect);
      Canvas.DrawFocusRect(ClientRect);
    end else NewBackColor := clWhite;

  for I:=1 to Length(Text) do begin
   if PasswordChar=#0 then begin
     if Text[I] in ['0'..'9'] then begin
       NewColor := clRed;
       DrawEx(Text[I]);
      end else begin
       NewColor := clGreen;
       DrawEx(Text[I]);
      end;
     Inc(R.Left,Canvas.TextWidth(Text[I]));
    end else begin //with passwordchar
       NewColor := clBlack;
       DrawEx(PasswordChar);
     Inc(R.Left,Canvas.TextWidth(PasswordChar));
    end;
  end;
end;
procedure TMyEdit.CreateParams(var Params: TCreateParams);
begin
    inherited;
    if csDesigning in ComponentState then
        exit;
    Params.ExStyle := Params.ExStyle or WS_EX_COMPOSITED;
end;