2012-03-18 2 views
3

Я хотел бы нарисовать кусок TEdit.Text, используя Font.Color, отличный от значения по умолчанию. Есть ли примеры, как это сделать?Как я могу нарисовать текст управления TEdit?

Я пытаюсь сделать что-то вроде этого:

ПРИМЕЧАНИЕ: что это скриншот фотографии является просто волосатые проект, но он убеждает меня, что проблема разрешима.

+6

Вы можете поделиться своим «решением», чтобы мы могли обсудить его и предоставить обратную связь (скриншот не является решением). – kobik

+0

@kobik, может быть серия простых вопросов, посвященных конкретным проблемам, на которые я наткнулся. Но это может произойти позже, в настоящее время я не застрял. – OnTheFly

ответ

13

Edit управления не имеют владелец привлечь поддержку, но вы можете заказ рисовать его по суб-причислять ее и обработки WM_PAINT (среди многих других сообщений). Это выполнимо, но это был бы мир боли, чтобы фактически реализовать 100% правильно. Из документов: Developing Custom Draw Controls in 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; 

+0

Спасибо, этот пример действительно продвигает меня в моем исследовании и указывает мне на многочисленные нюансы, которые я пропустил полностью (например, csCustomPaint). – OnTheFly

+2

Поскольку вы не используете собственную поверхность элемента управления, вам необходимо учитывать все возможные витрины. Например, помимо выбора, вам также необходимо учитывать, когда текст должен отображаться, начиная с символа, отличного от первого, - когда текст больше, чтобы соответствовать элементу управления, и пользователь прокрутил его до конца. На самом деле то, что вы будете делать, - это разработка вашего элемента управления редактированием, а не использование его! .. –

+0

@SertacAkyuz Я только что использовал код, предоставленный kobik, только с изменениями в том, как текст нарисован, и все случаи, о которых вы упоминаете, обрабатываются должным образом. Предоставлено это через 5 лет и в разных версиях ОС и Delphi, но, как ссылка, вышеприведенный код отлично поработал для того, что я должен был сделать. –

9

№ Стандарт tEdit не поддерживает пользовательский чертеж или имеет текст с несколькими цветами. В качестве альтернативы вы можете использовать tRichEdit с WantReturns = False.

+0

Я согласен с тем, что добавление поддержки пользовательских чертежей - настоящая PITA, учитывая то, что она происходит непосредственно от TWinControl, однако я доказал, что это довольно выполнимо. – OnTheFly

+5

@user - Я был бы удивлен, если ваш пользовательский чертеж будет работать, когда карет находится в элементе управления. Имеет ли это? –

+0

@SertacAkyuz, было бы действительно смелым заявлением, чтобы сказать, что моя попытка «работает» до сих пор :-) Тем не менее, я не уверен, что это вообще невозможно. – OnTheFly

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; 
Смежные вопросы