Delphi

Painting the background of TEdit

TEdit is a fairly low level component utilizing the standard windows edit window. How on earth do we get the background to be something other than a color.. Can we make it transparent or put a picture in. I don’t know if the following works in versions previous to Delphi 6 but I can’t see why it would not.

This unit is a transparent TEdit descendant.

If you want to put your own background in instead of it being transparent change the else clause of the if Transparent in WMEraseBkGnd.

unit Z9Edit;
interface
uses
  Windows, Messages, SysUtils, Classes, Controls, StdCtrls, Graphics;
type
  TZ9Edit = class(TEdit)
private
{ Private declarations }
    FAlignText: TAlignment;
    FTransparent: Boolean;
    FPainting: Boolean;
procedure SetAlignText(Value: TAlignment);
procedure SetTransparent(Value: Boolean);
protected
{ Protected declarations }
procedure RepaintWindow;
procedure CreateParams(var Params: TCreateParams); override;
procedure Change; override;
procedure SetParent(AParent: TWinControl); override;
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
procedure WMNCPaint (var Message: TMessage); message WM_NCPAINT;
procedure WMEraseBkGnd(var Message: TWMEraseBkGnd); message WM_ERASEBKGND;
procedure CNCtlColorEdit(var Message: TWMCtlColorEdit); message CN_CTLCOLOREDIT;
procedure CNCtlColorStatic(var Message: TWMCtlColorStatic); message CN_CTLCOLORSTATIC;
procedure CMParentColorChanged(var Message: TMessage); message CM_PARENTCOLORCHANGED;
procedure WMSize(var Message: TWMSize); message WM_SIZE;
procedure WMMove(var Message: TWMMove); message WM_MOVE;
procedure PaintParent(ACanvas: TCanvas);
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
{ Published declarations }
property Align;
property AlignText: TAlignment read FAlignText write SetAlignText default taLeftJustify;
property Transparent: Boolean read FTransparent write SetTransparent default false;
end;
implementation
{ TZ9Edit }
uses
  Forms;
type
  TParentControl = class(TWinControl);
const
  BorderRec: array[TBorderStyle] of Integer = (1, -1);
constructor TZ9Edit.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
  FAlignText := taLeftJustify;
  FTransparent := false;
  FPainting := false;
end;
destructor TZ9Edit.Destroy;
begin
inherited Destroy;
end;
procedure TZ9Edit.SetAlignText(Value: TAlignment);
begin
if FAlignText <> Value then
begin
    FAlignText := Value;
    RecreateWnd;
     Invalidate;
end;
end;
procedure TZ9Edit.SetTransparent(Value: Boolean);
begin
if FTransparent <> Value then
begin
    FTransparent := Value;
    Invalidate;
end;
end;
procedure TZ9Edit.WMEraseBkGnd(var Message: TWMEraseBkGnd);
var
  DC: hDC;
  i: integer;
  p: TPoint;
  canvas : TCanvas;
begin
if FTransparent and not(csDesigning in componentstate) then
begin
    canvas := TCanvas.create;
try
      canvas.handle := message.dc;
      PaintParent(Canvas);
finally
      canvas.free;
end;
end
else
begin
    canvas := TCanvas.create;
try
      canvas.handle := message.dc;
      canvas.brush.color := Color;
      canvas.brush.style := bsSolid;
      canvas.fillrect(clientrect);
finally
      canvas.free;
end;
end;
end;
procedure TZ9Edit.WMPaint(var Message: TWMPaint);
begin
inherited;
if FTransparent then
if not FPainting then RepaintWindow;
end;
procedure TZ9Edit.WMNCPaint(var Message: TMessage);
begin
inherited;
end;
procedure TZ9Edit.CNCtlColorEdit(var Message: TWMCtlColorEdit);
begin
inherited;
if FTransparent then SetBkMode(Message.ChildDC, 1);
end;
procedure TZ9Edit.CNCtlColorStatic(var Message: TWMCtlColorStatic);
begin
inherited;
if FTransparent then SetBkMode(Message.ChildDC, 1);
end;
procedure TZ9Edit.CMParentColorChanged(var Message: TMessage);
begin
inherited;
if FTransparent then Invalidate;
end;
procedure TZ9Edit.WMSize(var Message: TWMSize);
var
  r : TRect;
begin
inherited;
  r := ClientRect;
  InvalidateRect(handle,@r,false);
end;
procedure TZ9Edit.WMMove(var Message: TWMMove);
var
  r : TRect;
begin
inherited;
  Invalidate;
  r := ClientRect;
  InvalidateRect(handle,@r,false);
end;
procedure TZ9Edit.RepaintWindow;
var
  DC: hDC;
  TmpBitmap, Bitmap: hBitmap;
begin
if FTransparent then
begin
    FPa
inting := true;
    HideCaret(Handle);
    DC := CreateCompatibleDC(GetDC(Handle));
    TmpBitmap := CreateCompatibleBitmap(GetDC(Handle), Succ(ClientWidth), Succ(ClientHeight));
    Bitmap := SelectObject(DC, TmpBitmap);
    PaintTo(DC, 0, 0);
    BitBlt(GetDC(Handle), BorderRec[BorderStyle] + BorderWidth, BorderRec[BorderStyle] + BorderWidth, ClientWidth, ClientHeight, DC, 1, 1, SRCCOPY);
    SelectObject(DC, Bitmap);
    DeleteDC(DC);
    ReleaseDC(Handle, GetDC(Handle));
    DeleteObject(TmpBitmap);
    ShowCaret(Handle);
    FPainting := false;
end;
end;
procedure TZ9Edit.CreateParams(var Params: TCreateParams);
const
  Alignments: array [TAlignment] of DWord = (ES_LEFT, ES_RIGHT, ES_CENTER);
begin
inherited CreateParams(Params);
  Params.Style := Params.Style or ES_MULTILINE or Alignments[FAlignText];
end;
procedure TZ9Edit.Change;
begin
  RepaintWindow;
inherited Change;
end;
procedure TZ9Edit.SetParent(AParent: TWinControl);
begin
inherited SetParent(AParent);
end;
procedure TZ9Edit.PaintParent(ACanvas: TCanvas);
var
  I, Count, X, Y, SaveIndex: integer;
  DC: cardinal;
  R, SelfR, CtlR: TRect;
  Control : TControl;
begin
  Control := Self;
if Control.Parent = nil then Exit;
  Count := Control.Parent.ControlCount;
  DC := ACanvas.Handle;
  SelfR := Bounds(Control.Left, Control.Top, Control.Width, Control.Height);
  X := -Control.Left; Y := -Control.Top;
// Copy parent control image
  SaveIndex := SaveDC(DC);
  SetViewportOrgEx(DC, X, Y, nil);
  IntersectClipRect(DC, 0, 0, Control.Parent.ClientWidth, Control.Parent.ClientHeight);
  TParentControl(Control.Parent).Perform(WM_ERASEBKGND,DC,0);
  TParentControl(Control.Parent).PaintWindow(DC);
  RestoreDC(DC, SaveIndex);
//Copy images of graphic controls
for I := 0 to Count – 1 do begin
if (Control.Parent.Controls[I] <> nil) then
begin
if Control.Parent.Controls[I] = Control then break;
with Control.Parent.Controls[I] do
begin
        CtlR := Bounds(Left, Top, Width, Height);
if Bool(IntersectRect(R, SelfR, CtlR)) and Visible then
begin
          SaveIndex := SaveDC(DC);
          SetViewportOrgEx(DC, Left + X, Top + Y, nil);
          IntersectClipRect(DC, 0, 0, Width, Height);
          Perform(WM_ERASEBKGND,DC,0);
          Perform(WM_PAINT, integer(DC), 0);
          RestoreDC(DC, SaveIndex);
end;
end;
end;
end;
end;
end.