我希望能够使用不同于默认值的字体颜色来绘制TEdit.Text。是否有任何示例可以展示如何实现?
我试图做类似于这样的事情:
注:这张截图仅仅是一个草图,但它使我相信问题是可以解决的。
我试图做类似于这样的事情:
注:这张截图仅仅是一个草图,但它使我相信问题是可以解决的。
Edit
控件不支持自定义绘制,但是你可以通过子类化并处理WM_PAINT
消息来实现它。这是可行的,但是要完全正确地实现它将会很麻烦。根据文档:在Visual C++中开发自定义绘制控件:
请注意,对于大多数控件,所有者绘制都适用。然而,对于编辑控件,它不起作用;而对于列表控件,仅适用于报表视图样式。
我也很想知道兔子洞有多深,因此,以下是使用interposer类的示例代码(尚需实现选择,但当插入符在控件中时,自定义绘制会起作用):
type
TEdit = class(StdCtrls.TEdit)
private
FCanvas: TCanvas;
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
protected
procedure WndProc(var Message: TMessage); override;
procedure Paint; virtual;
procedure PaintWindow(DC: HDC); override;
property Canvas: TCanvas read FCanvas;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
...
constructor TEdit.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FCanvas := TControlCanvas.Create;
TControlCanvas(FCanvas).Control := Self;
end;
destructor TEdit.Destroy;
begin
FCanvas.Free;
inherited Destroy;
end;
procedure TEdit.Paint;
var
R: TRect;
I: Integer;
S: String;
begin
R := ClientRect;
Inc(R.Left, 1);
Inc(R.Top, 1);
Canvas.Brush.Assign(Self.Brush);
Canvas.Font.Assign(Self.Font);
for I := 1 to Length(Text) do
begin
if Text[I] in ['0'..'9'] then
Canvas.Font.Color := clRed
else
Canvas.Font.Color := clGreen;
S := Text[I];
DrawText(Canvas.Handle, PChar(S), -1, R, DT_LEFT or DT_NOPREFIX or
DT_WORDBREAK or DrawTextBiDiModeFlagsReadingOnly);
Inc(R.Left,Canvas.TextWidth(S));
end;
end;
procedure TEdit.PaintWindow(DC: HDC);
begin
FCanvas.Lock;
try
FCanvas.Handle := DC;
try
TControlCanvas(FCanvas).UpdateTextFlags;
Paint;
finally
FCanvas.Handle := 0;
end;
finally
FCanvas.Unlock;
end;
end;
procedure TEdit.WMPaint(var Message: TWMPaint);
begin
ControlState := ControlState+[csCustomPaint];
inherited;
ControlState := ControlState-[csCustomPaint];
end;
procedure TEdit.WndProc(var Message: TMessage);
begin
inherited WndProc(Message);
with Message do
case Msg of
CM_MOUSEENTER, CM_MOUSELEAVE, WM_LBUTTONUP, WM_LBUTTONDOWN,
WM_KEYDOWN, WM_KEYUP,
WM_SETFOCUS, WM_KILLFOCUS,
CM_FONTCHANGED, CM_TEXTCHANGED:
begin
Invalidate;
end;
end;
end;
标准的tEdit不支持自定义绘制或者使用多个颜色展示文本。作为替代方案,您可以使用WantReturns=False的tRichEdit。
WM_PAINT
(以及许多其他消息)来进行自定义绘制。这是可行的,但需要花费大量精力。 - kobikprocedure 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;
通过重写CreateParams过程来进行另一个小的改进,解决了在文本选择期间(鼠标移动时左键按下)出现的闪烁问题:
procedure TMyEdit.CreateParams(var Params: TCreateParams);
begin
inherited;
if csDesigning in ComponentState then
exit;
Params.ExStyle := Params.ExStyle or WS_EX_COMPOSITED;
end;