erickenb
asked on
After reading Slick812's code for Run Ttime Component Design...
Thnx for Slick812's code for that CtrlSizer Unit at first; And there is a issue keeping me puzzled that after calling TCtrlSizer.repaint method, it loses its tranparent effect. Since i can not use this method, how to refresh the TCtrlSizer control after its value of Canvas.Brush(Pen).Color changed?
---Here is the code for this CtrlSizer Unit - -
unit CtrlSizer;
interface
uses
Classes, Windows, Messages, Controls, StdCtrls;
type
TCtrlSizer = class (TCustomControl)
private
FControl: TControl;
{FControl is set to the Control that will be moved and sized by this}
NoSize: Boolean;
FRectAry: array [1..8] of TRect;
FPosAry: array [1..8] of Integer;
public
constructor Create (AOwner: TComponent; AControl: TControl);
procedure CreateParams (var Params: TCreateParams); override;
procedure CreateHandle; override;
procedure NcHitTest (var Msg: TWmNcHitTest); message WM_NCHITTEST;
procedure WmSize (var Msg: TWmSize); message WM_SIZE;
procedure LButtonDown (var Msg: TWmLButtonDown); message WM_LBUTTONDOWN;
procedure WmMove (var Msg: TWmMove); message WM_MOVE;
procedure Paint; override;
procedure SizerControlExit (Sender: TObject);
end;
implementation
uses
Graphics;
constructor TCtrlSizer.Create (AOwner: TComponent; AControl: TControl);
var
Rec: TRect;
begin
inherited Create (AOwner);
FControl := AControl;
if AControl is TComboBox then
NoSize := True else
NoSize := False;
// assign an OnExit
OnExit := SizerControlExit;
// set the size and position
Rec := FControl.BoundsRect;
InflateRect (Rec, 2, 2);
BoundsRect := Rec;
// set the parent to FControl parent
Parent := FControl.Parent;
// create an array of positions
FPosAry [1] := htTopLeft;
FPosAry [2] := htTop;
FPosAry [3] := htTopRight;
FPosAry [4] := htRight;
FPosAry [5] := htBottomRight;
FPosAry [6] := htBottom;
FPosAry [7] := htBottomLeft;
FPosAry [8] := htLeft;
end;
procedure TCtrlSizer.CreateHandle;
begin
inherited CreateHandle;
{as soon as this window is created, give it focus}
SetFocus;
end;
procedure TCtrlSizer.CreateParams (var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.ExStyle := Params.ExStyle + WS_EX_Transparent;
{the WS_EX_Transparent allows the control under this (FControl)
to be Painted first and change the pixels on this control, ,
then does not do an Erase Background}
end;
procedure TCtrlSizer.SizerControlExi t (Sender: TObject);
begin
{when this control looses focus, Free it}
Free;
end;
procedure TCtrlSizer.LButtonDown (var Msg: TWmLButtonDown);
begin
{to mouse move this control use the Caption Hit Test
message SC_DRAGMOVE, which is Hex $F012}
Perform(wm_SysCommand, $F012, 0);
end;
procedure TCtrlSizer.Paint;
var
i: Integer;
begin
{this will paint 8 small black sixing rectangles}
Canvas.Brush.Color := clBlack;
{if NoSize then I do Not draw the Top and Bottom Rects}
for i := 1 to 8 do
if not(NoSize and ((i = 2) or (i = 6))) then
Canvas.Rectangle(FRectAry [i].Left, FRectAry [i].Top,
FRectAry [i].Right, FRectAry [i].Bottom);
end;
procedure TCtrlSizer.NcHitTest(var Msg: TWmNcHitTest);
var
Pt1: TPoint;
i: Integer;
begin
Pt1 := Point(Msg.XPos, Msg.YPos);
Pt1 := ScreenToClient(Pt1);
Msg.Result := 0;
{the NoSize is True for TComboBoxes, because the Height
is NOT Changable in Design or Run Time,
So I change the HitTest to Only give Left and Right side Hits}
if NoSize then
begin
for I := 1 to 8 do
if PtInRect(FRectAry[i], Pt1) then
case i of
1: Msg.Result := FPosAry[8];
2: Msg.Result := 0;
3..5: Msg.Result := FPosAry[4];
6: Msg.Result := 0;
7..8: Msg.Result := FPosAry[8];
end;
end else
for i := 1 to 8 do
if PtInRect (FRectAry[i], Pt1) then
Msg.Result := FPosAry[i];
// if the return value was not set
if Msg.Result = 0 then
inherited;
end;
procedure TCtrlSizer.WmSize (var Msg: TWmSize);
var
Rect1: TRect;
begin
Rect1 := BoundsRect;
InflateRect (Rect1, -2, -2);
FControl.BoundsRect := Rect1;
// setup Rectangle sizes
FRectAry[1] := Rect(0, 0, 5, 5);
FRectAry[2] := Rect(Width div 2 - 3, 0, Width div 2 + 2, 5);
FRectAry[3] := Rect(Width - 5, 0, Width, 5);
FRectAry[4] := Rect(Width - 5, Height div 2 - 3, Width, Height div 2 + 2);
FRectAry[5] := Rect(Width - 5, Height - 5, Width, Height);
FRectAry[6] := Rect(Width div 2 - 3, Height - 5, Width div 2 + 2, Height);
FRectAry[7] := Rect(0, Height - 5, 5, Height);
FRectAry[8] := Rect(0, Height div 2 - 3, 5, Height div 2 + 2);
end;
procedure TCtrlSizer.WmMove (var Msg: TWmMove);
var
Rect1: TRect;
begin
Rect1 := BoundsRect;
InflateRect (Rect1, -2, -2);
FControl.Invalidate; // repaint the control
FControl.BoundsRect := Rect1; // move the control
end;
end.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
to use this add the CtrlSizer to your uses clause, and then put a SizerAttach procedure in your forms Class Defintion, and add the SizerAttach Procedure to your code - -
TForm1 = class(TForm)
but_Exit: TButton;
procedure but_ExitClick(Sender: TObject);
procedure SizerAttach(Sender: TObject);
private
{ Private declarations }
CtrlSizerHandle: Cardinal;
CSizer1: TCtrlSizer;
- - - -
procedure TForm1.SizerAttach(Sender: TObject);
begin
CSizer1 := TCtrlSizer.Create(self, Sender as TControl);
CtrlSizerHandle := CSizer1.Handle;
end;
procedure TForm1.FormClick(Sender: TObject);
begin
if CtrlSizerHandle = windows.GetFocus then
FreeAndNil(CSizer1);
end;
- - - - - - - - - - - - - - - - - - - - - - -
---Here is the code for this CtrlSizer Unit - -
unit CtrlSizer;
interface
uses
Classes, Windows, Messages, Controls, StdCtrls;
type
TCtrlSizer = class (TCustomControl)
private
FControl: TControl;
{FControl is set to the Control that will be moved and sized by this}
NoSize: Boolean;
FRectAry: array [1..8] of TRect;
FPosAry: array [1..8] of Integer;
public
constructor Create (AOwner: TComponent; AControl: TControl);
procedure CreateParams (var Params: TCreateParams); override;
procedure CreateHandle; override;
procedure NcHitTest (var Msg: TWmNcHitTest); message WM_NCHITTEST;
procedure WmSize (var Msg: TWmSize); message WM_SIZE;
procedure LButtonDown (var Msg: TWmLButtonDown); message WM_LBUTTONDOWN;
procedure WmMove (var Msg: TWmMove); message WM_MOVE;
procedure Paint; override;
procedure SizerControlExit (Sender: TObject);
end;
implementation
uses
Graphics;
constructor TCtrlSizer.Create (AOwner: TComponent; AControl: TControl);
var
Rec: TRect;
begin
inherited Create (AOwner);
FControl := AControl;
if AControl is TComboBox then
NoSize := True else
NoSize := False;
// assign an OnExit
OnExit := SizerControlExit;
// set the size and position
Rec := FControl.BoundsRect;
InflateRect (Rec, 2, 2);
BoundsRect := Rec;
// set the parent to FControl parent
Parent := FControl.Parent;
// create an array of positions
FPosAry [1] := htTopLeft;
FPosAry [2] := htTop;
FPosAry [3] := htTopRight;
FPosAry [4] := htRight;
FPosAry [5] := htBottomRight;
FPosAry [6] := htBottom;
FPosAry [7] := htBottomLeft;
FPosAry [8] := htLeft;
end;
procedure TCtrlSizer.CreateHandle;
begin
inherited CreateHandle;
{as soon as this window is created, give it focus}
SetFocus;
end;
procedure TCtrlSizer.CreateParams (var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.ExStyle := Params.ExStyle + WS_EX_Transparent;
{the WS_EX_Transparent allows the control under this (FControl)
to be Painted first and change the pixels on this control, ,
then does not do an Erase Background}
end;
procedure TCtrlSizer.SizerControlExi
begin
{when this control looses focus, Free it}
Free;
end;
procedure TCtrlSizer.LButtonDown (var Msg: TWmLButtonDown);
begin
{to mouse move this control use the Caption Hit Test
message SC_DRAGMOVE, which is Hex $F012}
Perform(wm_SysCommand, $F012, 0);
end;
procedure TCtrlSizer.Paint;
var
i: Integer;
begin
{this will paint 8 small black sixing rectangles}
Canvas.Brush.Color := clBlack;
{if NoSize then I do Not draw the Top and Bottom Rects}
for i := 1 to 8 do
if not(NoSize and ((i = 2) or (i = 6))) then
Canvas.Rectangle(FRectAry [i].Left, FRectAry [i].Top,
FRectAry [i].Right, FRectAry [i].Bottom);
end;
procedure TCtrlSizer.NcHitTest(var Msg: TWmNcHitTest);
var
Pt1: TPoint;
i: Integer;
begin
Pt1 := Point(Msg.XPos, Msg.YPos);
Pt1 := ScreenToClient(Pt1);
Msg.Result := 0;
{the NoSize is True for TComboBoxes, because the Height
is NOT Changable in Design or Run Time,
So I change the HitTest to Only give Left and Right side Hits}
if NoSize then
begin
for I := 1 to 8 do
if PtInRect(FRectAry[i], Pt1) then
case i of
1: Msg.Result := FPosAry[8];
2: Msg.Result := 0;
3..5: Msg.Result := FPosAry[4];
6: Msg.Result := 0;
7..8: Msg.Result := FPosAry[8];
end;
end else
for i := 1 to 8 do
if PtInRect (FRectAry[i], Pt1) then
Msg.Result := FPosAry[i];
// if the return value was not set
if Msg.Result = 0 then
inherited;
end;
procedure TCtrlSizer.WmSize (var Msg: TWmSize);
var
Rect1: TRect;
begin
Rect1 := BoundsRect;
InflateRect (Rect1, -2, -2);
FControl.BoundsRect := Rect1;
// setup Rectangle sizes
FRectAry[1] := Rect(0, 0, 5, 5);
FRectAry[2] := Rect(Width div 2 - 3, 0, Width div 2 + 2, 5);
FRectAry[3] := Rect(Width - 5, 0, Width, 5);
FRectAry[4] := Rect(Width - 5, Height div 2 - 3, Width, Height div 2 + 2);
FRectAry[5] := Rect(Width - 5, Height - 5, Width, Height);
FRectAry[6] := Rect(Width div 2 - 3, Height - 5, Width div 2 + 2, Height);
FRectAry[7] := Rect(0, Height - 5, 5, Height);
FRectAry[8] := Rect(0, Height div 2 - 3, 5, Height div 2 + 2);
end;
procedure TCtrlSizer.WmMove (var Msg: TWmMove);
var
Rect1: TRect;
begin
Rect1 := BoundsRect;
InflateRect (Rect1, -2, -2);
FControl.Invalidate; // repaint the control
FControl.BoundsRect := Rect1; // move the control
end;
end.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
to use this add the CtrlSizer to your uses clause, and then put a SizerAttach procedure in your forms Class Defintion, and add the SizerAttach Procedure to your code - -
TForm1 = class(TForm)
but_Exit: TButton;
procedure but_ExitClick(Sender: TObject);
procedure SizerAttach(Sender: TObject);
private
{ Private declarations }
CtrlSizerHandle: Cardinal;
CSizer1: TCtrlSizer;
- - - -
procedure TForm1.SizerAttach(Sender:
begin
CSizer1 := TCtrlSizer.Create(self, Sender as TControl);
CtrlSizerHandle := CSizer1.Handle;
end;
procedure TForm1.FormClick(Sender: TObject);
begin
if CtrlSizerHandle = windows.GetFocus then
FreeAndNil(CSizer1);
end;
- - - - - - - - - - - - - - - - - - - - - - -
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.