I have tried a lot of code over the year but nothing work 100% I just need to be able to put an image as the background of my main form, and be able to tile it.
I am using DELPHI 2007.
I have tried a lot of code over the year but nothing work 100% I just need to be able to put an image as the background of my main form, and be able to tile it.
I am using DELPHI 2007.
By background I am assuming you mean the client region of the main MDI frame window.
This area of the screen is handled by the MDI Client window so one way to do this would be to subclass the MDI Client window and then process the *WM_PAINT* message.
I am not sure if it's going to work, but I found Change MDI parent background.
The decision consists in interception of the
WM_ERASEBKGND
,WM_VSCROLL
andWM_HSCROLL
messages and carry out draw of area by usingDrawImage
procedure orInvalidateRect
procedure.CreateWnd
procedure usesSetWindowLong
procedure for installation of new procedure of a window. Don't forget to remove lineApplication.CreateForm(TForm2, Form2)
from project file and linevar Form2: TForm
2 from unit2.pas file.
// This procedure tiles the image on the form's client area
procedure TForm1.DrawImage;
var
i, j: Integer;
WndRect, ImageRect: TRect;
Rows, Cols: Integer;
begin
GetWindowRect(ClientHandle, WndRect);
ImageRect:=Image1.ClientRect;
Rows:=WndRect.Bottom div ImageRect.Bottom;
Cols:=WndRect.Right div ImageRect.Right;
with Image1 do
for i:=0 to Rows+1 do
for j:=0 to Cols+1 do
BitBlt(MyDC, j*Picture.Width, i*Picture.Height, Picture.Width,
Picture.Height, Picture.Bitmap.Canvas.Handle, 0, 0, SRCCOPY);
end;
You can do the following, in the MDI forms OnPaint procedure add the following
Canvas.Lock;
try
Canvas.Brush.Bitmap := MyImg.Picture.Bitmap;
Canvas.FillRect(Rect(0,0,ClientWidth,ClientHeight));
finally
Canvas.Unlock;
end;
But it still flickers when you manually re-size the form, due to the excessive repaints. There are windows messages saying that a form is been resized that you could hook into, and not update until the form has finished resizing.
These windows messages would do the trick :
I have a component that I wrote years ago, as a part of my freeware component collection, called TrmMDIBackground. rmControls v1.92 or the D2009 version.
It can display the image as Tiled, Stretched, Centered or display a single solid color. It would be easy enough to add support for gradient colors, I just haven't done that.
I've provided most of the important pieces of the code here, but looking at the component code in it's entirety would be better as hook window procs looking for specific messages and all of the glue code to make it work.
As to how the drawing goes, I believe that the flicker it not bad (if even visible). It also only currently supports Bitmap images.
I've added the entire component unit here:
{================================================================================
Copyright (C) 1997-2002 Mills Enterprise
Unit : rmMDIBackground
Purpose : To allow an image to be placed with in the workspace area of an
MDI Form. Background colors are also available.
Date : 04-24-2000
Author : Ryan J. Mills
Version : 1.93
================================================================================}
unit rmMDIBackground;
interface
{$I CompilerDefines.INC}
uses
Windows, Messages, Classes, Forms, graphics;
type
TrmBMPDisplayStyle = (dsTiled, dsStretched, dsCentered, dsNone) ;
TrmMDIBackground = class(TComponent)
private
OldWndProc: TFarProc;
NewWndProc: Pointer;
OldMDIWndProc: TFarProc;
NewMDIWndProc: Pointer;
fBitmap: TBitmap;
fstyle: TrmBMPDisplayStyle;
fColor: TColor;
fBuffer: TBitmap;
fLastRect: TRect;
procedure SetBitmap(const Value: tBitmap) ;
procedure SetDStyle(const Value: TrmBMPDisplayStyle) ;
procedure SetMDIColor(const Value: TColor) ;
{ Private declarations }
protected
{ Protected declarations }
procedure HookWndProc(var AMsg: TMessage) ;
procedure HookWnd;
procedure UnHookWnd;
procedure HookMDIWndProc(var AMsg: TMessage) ;
procedure HookMDIWin;
procedure UnhookMDIWin;
procedure PaintImage;
public
{ Public declarations }
constructor Create(AOwner: TComponent) ; override;
destructor Destroy; override;
published
{ Published declarations }
property Bitmap: tBitmap read fBitmap write SetBitmap;
property DisplayStyle: TrmBMPDisplayStyle read fstyle write SetDStyle default dsNone;
property Color: TColor read fColor write SetMDIColor default clappWorkspace;
end;
implementation
uses rmGlobalComponentHook;
{ TrmMDIBackground }
constructor TrmMDIBackground.create(AOwner: TComponent) ;
begin
inherited;
NewWndProc := nil;
OldWndProc := nil;
OldMDIWndProc := nil;
NewMDIWndProc := nil;
fBitmap := tBitmap.create;
fbuffer := tbitmap.create;
fColor := clAppWorkSpace;
fstyle := dsNone;
fLastRect := rect(0, 0, 0, 0) ;
HookWnd;
end;
destructor TrmMDIBackground.destroy;
begin
UnHookWnd;
fBitmap.free;
fbuffer.free;
inherited;
end;
procedure TrmMDIBackground.HookMDIWin;
begin
if csdesigning in componentstate then exit;
if not assigned(NewMDIWndProc) then
begin
OldMDIWndProc := TFarProc(GetWindowLong(TForm(Owner) .ClientHandle, GWL_WNDPROC) ) ;
{$ifdef D6_or_higher}
NewMDIWndProc := Classes.MakeObjectInstance(HookMDIWndProc) ;
{$else}
NewMDIWndProc := MakeObjectInstance(HookMDIWndProc) ;
{$endif}
SetWindowLong(TForm(Owner) .ClientHandle, GWL_WNDPROC, LongInt(NewMDIWndProc) ) ;
end;
end;
procedure TrmMDIBackground.HookMDIWndProc(var AMsg: TMessage) ;
begin
with AMsg do
begin
if msg <> WM_ERASEBKGND then
Result := CallWindowProc(OldMDIWndProc, TForm(Owner) .ClientHandle, Msg, wParam, lParam)
else
result := 1;
if (msg = WM_NCPaint) or (msg = wm_Paint) then
PaintImage;
end;
end;
procedure TrmMDIBackground.HookWnd;
begin
if csdesigning in componentstate then exit;
if TForm(Owner) .formstyle <> fsMDIForm then exit;
if not assigned(NewWndProc) then
begin
OldWndProc := TFarProc(GetWindowLong(TForm(Owner) .handle, GWL_WNDPROC) ) ;
{$ifdef D6_or_higher}
NewWndProc := Classes.MakeObjectInstance(HookWndProc) ;
{$else}
NewWndProc := MakeObjectInstance(HookWndProc) ;
{$endif}
SetWindowLong(TForm(Owner) .handle, GWL_WNDPROC, LongInt(NewWndProc) ) ;
PushOldProc(TForm(Owner) , OldWndProc) ;
HookMDIWin;
end;
end;
procedure TrmMDIBackground.HookWndProc(var AMsg: TMessage) ;
begin
case AMsg.msg of
WM_DESTROY:
begin
AMsg.Result := CallWindowProc(OldWndProc, Tform(Owner) .handle, AMsg.Msg, AMsg.wParam, AMsg.lParam) ;
UnHookWnd;
exit;
end;
wm_EraseBKGND:
begin
aMsg.Result := 1;
exit;
end;
end;
AMsg.Result := CallWindowProc(OldWndProc, Tform(Owner) .handle, AMsg.Msg, AMsg.wParam, AMsg.lParam) ;
case aMsg.Msg of
WM_PAINT, // WM_ERASEBKGND,
WM_NCPaint: PaintImage;
end;
end;
procedure TrmMDIBackground.PaintImage;
var
DC: HDC;
Brush: HBrush;
cx, cy: integer;
wRect: TRect;
x, y: integer;
begin
if csdesigning in componentstate then exit;
if TForm(Owner) .FormStyle <> fsMDIForm then exit;
GetWindowRect(TForm(Owner) .ClientHandle, wRect) ;
DC := GetDC(TForm(Owner) .clienthandle) ;
try
case fstyle of
dsTiled, dsStretched, dsCentered:
begin
case fStyle of
dsTiled:
begin
cx := (wRect.right - wRect.left) ;
cy := (wRect.bottom - wRect.top) ;
y := 0;
while y < cy do
begin
x := 0;
while x < cx do
begin
bitBlt(DC, x, y, fBitmap.width, fBitmap.height,
fBitmap.canvas.Handle, 0, 0, srccopy) ;
inc(x, fBitmap.width) ;
end;
inc(y, fBitmap.Height) ;
end;
end;
dsStretched:
begin
cx := (wRect.right - wRect.left) ;
cy := (wRect.bottom - wRect.top) ;
StretchBlt(DC, 0, 0, cx, cy, fBitmap.Canvas.Handle, 0, 0, fBitmap.width, fBitmap.height, srccopy) ;
end;
dsCentered:
begin
fBuffer.width := wRect.right - wRect.left;
fBuffer.height := wRect.bottom - wRect.top;
Brush := CreateSolidBrush(ColorToRGB(fcolor) ) ;
try
FillRect(fBuffer.canvas.handle, rect(0, 0, fBuffer.width, fBuffer.height) , brush) ;
finally
DeleteObject(Brush) ;
end;
cx := (fBuffer.width div 2) - (fBitmap.width div 2) ;
cy := (fBuffer.height div 2) - (fbitmap.height div 2) ;
bitBlt(fBuffer.Canvas.handle, cx, cy, fBitmap.width, fBitmap.height,
fBitmap.Canvas.Handle, 0, 0, srccopy) ;
bitBlt(DC, 0, 0, fBuffer.width, fBuffer.height,
fBuffer.Canvas.Handle, 0, 0, srccopy) ;
end;
end;
end;
dsNone:
begin
Brush := CreateSolidBrush(ColorToRGB(fcolor) ) ;
try
FillRect(DC, TForm(Owner) .ClientRect, brush) ;
finally
DeleteObject(Brush) ;
end;
end;
end;
fLastRect := wRect;
finally
ReleaseDC(TForm(Owner) .clienthandle, DC) ;
end;
end;
procedure TrmMDIBackground.SetBitmap(const Value: tBitmap) ;
begin
fBitmap.assign(Value) ;
end;
procedure TrmMDIBackground.SetDStyle(const Value: TrmBMPDisplayStyle) ;
begin
if fstyle <> Value then
begin
fstyle := Value;
PaintImage;
end;
end;
procedure TrmMDIBackground.SetMDIColor(const Value: TColor) ;
begin
if fColor <> Value then
begin
fColor := Value;
PaintImage;
end;
end;
procedure TrmMDIBackground.UnhookMDIWin;
begin
if csdesigning in componentstate then exit;
if assigned(NewMDIWndProc) then
begin
SetWindowLong(TForm(Owner) .ClientHandle, GWL_WNDPROC, LongInt(OldMDIWndProc) ) ;
if assigned(NewMDIWndProc) then
{$ifdef D6_or_higher}
Classes.FreeObjectInstance(NewMDIWndProc) ;
{$else}
FreeObjectInstance(NewMDIWndProc) ;
{$endif}
NewMDIWndProc := nil;
OldMDIWndProc := nil;
end;
end;
procedure TrmMDIBackground.UnHookWnd;
begin
if csdesigning in componentstate then exit;
if assigned(NewWndProc) then
begin
SetWindowLong(TForm(Owner) .handle, GWL_WNDPROC, LongInt(PopOldProc(TForm(Owner) ) ) ) ;
if assigned(NewWndProc) then
{$ifdef D6_or_higher}
Classes.FreeObjectInstance(NewWndProc) ;
{$else}
FreeObjectInstance(NewWndProc) ;
{$endif}
NewWndProc := nil;
OldWndProc := nil;
end;
UnHookMDIWin;
end;
end.
EDIT: Added the image drawing code.
EDIT: Fixed a blinking refresh problem in the first WindProc Handler
EDIT: Added the corrected unit code here