2012-03-18 88 views
3

我想繪製一段TEdit.Text使用Font.Color不同於默認。有沒有例子如何做到這一點?我如何自定義繪製的TEdit控制文本?

我試圖做這樣的事情:

注:這張截圖的圖片是什麼僅僅是一個毛茸茸的草案,但它使我相信有什麼問題可以解決。

+6

歡迎你分享你的「解決方案」,所以我們可以討論,並提供飼料中後衛(截圖是不是一個解決方案)。 – kobik 2012-03-19 14:49:46

+0

@ kobik,可能會有一系列簡單的問題致力於解決我偶然發現的特定問題。但是這可能會在稍後發生,目前我沒有被卡住。 – OnTheFly 2012-03-19 15:22:13

回答

13

Edit控件沒有所有者繪製支持,但由子類它和處理WM_PAINT(許多其他消息中),您可以自定義繪製。這是可行的,但實際上實現100%是一個痛苦的世界。從文檔:Developing Custom Draw Controls in Visual C++

注意,所有者繪製將大部分控制工作。但是,它不適用於編輯控件;與問候列表控件,它僅適用於報告視圖風格

我也有興趣瞭解兔子洞有多深,所以,
下面是使用一箇中介類代碼示例(還需要落實的選擇,但是當插入符號是自定義繪製工作在控制):

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; 

+0

謝謝,這個例子實際上推動我在我的研究,並指出了我無數的細微差別我完全錯過了(例如,csCustomPaint)。 – OnTheFly 2012-03-19 20:37:49

+2

由於您沒有使用控件本身的表面,因此必須考慮所有可能的顯示情況。例如,除了選擇之外,還必須考慮何時應該以不同於第一個字符的字符顯示文本 - 當文本較大以適合控件並且用戶已將其滾動通過末尾時。實際上,你要做的是開發你的編輯控件,而不是使用一個! – 2012-03-19 21:16:36

+0

@SertacAkyuz我剛剛使用了kobik提供的代碼,只改變了文本的繪製方式,並且您提到的所有情況都得到了正確處理。當然,這是5年後,在不同的操作系統和Delphi版本中,但作爲參考,上面的代碼對我所要做的事情非常有用。 – 2017-08-23 20:14:13

9

號標準TEDIT不具有自定義繪製或文本有多種顏色的支持。作爲替代,你可以使用tRichEdit和WantReturns = False。

+0

我同意添加自定義繪圖支持是一個真正的PITA給定它從TWinControl直接下降,但我已經證明它是非常可行的。 – OnTheFly 2012-03-18 20:30:02

+5

@user - 如果您的自定義繪圖工作時插入符號在控件中,我會感到驚訝。可以? – 2012-03-19 02:22:52

+0

@SertacAkyuz,這將是非常大膽的聲明說些什麼我嘗試「作品」到目前爲止:-)但我不相信這是不可行的。 – OnTheFly 2012-03-19 13:57:10

2

一些改進,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;