Articles::A Cool and Easy Method for Resizing and Moving
Controls at Run Time
Whilst browsing the newsgroups I came across this
very useful article by Brent Eagles describing how to enable your
own components to be resized and moved around at run time (like when
you design your forms in the Delphi IDE). If you find this useful I
am sure Brent would appreciate any feedback. I think that is enough
said by me so read and enjoy.
I was hacking at one of my
software projects and was trying to come up with a way to allow the
user to resize my controls onscreen with the mouse. I knew the way
to code it, but didn't care for it very much. While I was eating my
supper (PIZZA!) I was flipping through a couple of TI's I had
downloaded from Borland's sight. TI2909 caught my eye, it described
a way to make a control moveable at run time by using a magic number
as a WPARAM to a WM_SYSCOMMAND message. The value was a
variation on the standard SC_MOVE parameter (SC_MOVE+2). I tried it
and it worked. I said to myself "Cool! But what would make it really
neat is if I could resize it too."
In the WinAPI help file I
noticed that there was a standard SC_SIZE parameter. I thought to
myself "Wouldn't it be something if I could make the control
resizeable just by using SC_SIZE+n?" Guess What! You CAN! Now this
may be documented somewhere or even common knowledge but I didn't
know about it and couldn't find it anywhere so I figured it is
undocumented, unknown and too cool to keep to myself.
If
people want to pass it on, that's great, but I would like them to
show who it came from. I am little known programmer in Atlantic
Canada trying to make his way to fame.
Here are the
parameters and a piece of source showing how I used them:
TAnalysisControl = class( TCustomControl
) public procedure MouseDown(
Button : TMouseButton; Shift :
TShiftState;
X, Y : integer ); override; procedure
MouseMove( Shift :
TShiftState;
X, Y : Integer );override; procedure
Paint; override; end;
implementation uses
Winprocs, Messages, Graphics; const sizeBorder =
2;
sc_SizeLeft
= $F001; { these are the variations on the }
sc_SizeRight
= $F002; { SC_SIZE value }
sc_SizeTop
= $F003;
sc_SizeTopLeft =
$F004; sc_SizeTopRight =
$F005;
sc_SizeBottom =
$F006; sc_SizeBottomRigh = $F008;
sc_SizeBottomLeft = $F007;
sc_DragMove =
$F012;
procedure TAnalysisControl.MouseDown( Button :
TMouseButton;
Shift :
TShiftState;
X, Y : integer ); begin if Button = mbLeft
then begin
WinProcs.ReleaseCapture; if ( X >= Width -
sizeBorder ) And NOT(( Y
<= sizeBorder ) or ( Y >= Height -sizeBorder ))
then Self.Perform(
WM_SysCommand, sc_SizeRight , 0 )
else if Not( ( X <= sizeBorder ) or ( X
>= Width -sizeBorder ) )
And ( Y <= sizeBorder
) then Self.Perform(
WM_SysCommand, sc_SizeTop , 0 )
else if ( X <= sizeBorder ) And ( Y <=
sizeBorder ) then
Self.Perform( WM_SysCommand, sc_SizeTopLeft, 0
) else if ( X >=
Width -sizeBorder ) and ( Y <= sizeBorder )
then Self.Perform(
WM_SysCommand, sc_SizeTopRight , 0 )
else if Not( ( X <= sizeBorder ) or ( X
>= Width -sizeBorder ) )
And ( Y >= Height -
sizeBorder ) then
Self.Perform( WM_SysCommand, sc_SizeBottom , 0
) else if ( Y >=
Height -sizeBorder ) And ( X <= sizeBorder )
then Self.Perform(
WM_SysCommand, sc_SizeBottomLeft , 0 )
else if ( Y >= Height -sizeBorder ) and ( X
>= Width - sizeBorder
) then Self.Perform(
WM_SysCommand, sc_SizeBottomRight , 0 )
else if Not( ( Y <= sizeBorder ) or ( Y
>= Height -sizeBorder ) )
And ( X <= sizeBorder
) then Self.Perform(
WM_SysCommand, sc_SizeLeft , 0 )
else
begin Self.Perform(
WM_SysCommand, SC_DragMove, 0 );
end; end; end;
procedure
TAnalysisControl.Paint; begin With Canvas
do begin
Brush.Color := clRed; Brush.Style
:= bsSolid; FillRect(
GetClientRect ); end; end;
procedure
TAnalysisControl.MouseMove( Shift :
TShiftState;
X, Y : Integer );
begin if ( X <=
sizeBorder ) or ( X >= Width -sizeBorder ) then
begin if ( Y >= Height -
sizeBorder ) then
begin if ( X >=
Width - sizeBorder )
then
Cursor := crSizeNWSE
else
Cursor := crSizeNESW;
end
else if ( Y <= sizeBorder )
then
begin if ( X >=
Width -sizeBorder )
then
Cursor := crSizeNESW
else
Cursor := crSizeNWSE;
end
else Cursor :=
crSizeWE; end else
if ( Y <= sizeBorder ) or ( Y >= Height - sizeBorder )
then begin Cursor
:= crSizeNS; end
else Cursor :=
crDefault; end;
Thanks again Brent for providing this very
useful tip. |