--- ---

## Answer 1

Create a new component derived from TMemo and override its drawing. Something like this:

    type
      TMyMemo = class(TMemo)
      protected
        procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
      end;

    procedure TMyMemo.WMPaint(var Message: TWMPaint);
    var
      MCanvas: TControlCanvas;
      DrawBounds: TRect;
    begin
      inherited;
      MCanvas := TControlCanvas.Create;
      DrawBounds := ClientRect;
      try
        MCanvas.Control := Self;
        with MCanvas do
        begin
          Brush.Color := clBtnFace;
          FrameRect( DrawBounds );
          InflateRect( DrawBounds, - 1, - 1);
          FrameRect( DrawBounds );
          FillRect ( DrawBounds );
          MoveTo ( 33, 0 );
          Brush.Color := clWhite;
          LineTo ( 33, ClientHeight );
          PaintImages;
        end;
      finally
        MCanvas.Free;
      end;
    end;

The PaintImages procedure draws images on the TMemo's canvas.

    procedure TMyMemo.PaintImages;
    var
      MCanvas: TControlCanvas;
      DrawBounds: TRect;
      i, j: Integer;
      OriginalRegion: HRGN;
      ControlDC: HDC;
    begin
      MCanvas := TControlCanvas.Create;
      DrawBounds := ClientRect;
      try
        MCanvas.Control := Self;
        ControlDC := GetDC ( Handle );
        MCanvas.Draw(0, 1, Application.Icon);
      finally
        MCanvas.Free;
      end;
    end;

Tip author unknown

## Answer 2

Basically you will need to intercept WM_ERASEBKGND and WM_PAINT messages. Let's say you have a TImage control the same size as your TMemo holding a bitmap that you want to use as your background. Let's assume you have this hooked in a TImage field called FImage available in your memo component code. The following should give you a good start:

In your class definition for TMyMemo:

    procedure WMEraseBkGnd(var Message: TWMEraseBkGnd); message WM_ERASEBKGND;
    procedure WMPaint(var Message: TWMPaint); message WM_PAINT;

    {...}

    procedure TMyMemo.WMEraseBkGnd(var Message: TWMEraseBkGnd);
    begin
      {assuming we get a good DC in Message - you should check this of course}
      BitBlt(Message.dc, 0, 0, Width, Height, FImage.Canvas.Handle, 0, 0, SRCCOPY);
      Message.Result := - 1;
    end;

    procedure TMyMemo.WMPaint(var Message: TWMPaint);
    var
      bm: TBitmap;
      dc: HDC;
      hDummy: HWND;
      i: integer;
      tm: TEXTMETRIC;
      Y: integer;
    begin
      bm := TBitmap.Create;
      try
        bm.Width := Width;
        bm.Height := Height;
        Perform(WM_ERASEBKGND, bm.Canvas.Handle, 0); {always in this simple example}
        bm.Canvas.Font.Assign(Font);
        GetTextMetrics(bm.Canvas.Handle, tm);
        SetBkMode(bm.Canvas.Handle, TRANSPARENT);
        Y := 0;
        for i := 0 to Lines.Count - 1 do
        begin
          bm.Canvas.TextOut(0, Y, Lines[i]);
          Inc(Y, tm.tmHeight);
        end;
        dc := GetDeviceContext(hDummy);
        BitBlt(dc, 0, 0, Width, Height, bm.Canvas.Handle, 0, 0, SRCCOPY);
        ReleaseDC(hDummy, dc);
      finally
        bm.Free;
      end;
      Message.Result := 0;
    end;

Note that this is only good for displaying transparently. Editing is another story. What I do is call the inherited behavior when I'm editing (so no transparency while typing). Obviously this example has no error checking. Also, the Message parameter for WM_PAINT may contain a device context to use in lieu of GetDeviceContext. The text always draws at `X = 0` so it ignores the border style & width. Finally, you should check for clipping to improve performance (I did this last).

Tip by Jon T Camp