Link to home
Start Free TrialLog in
Avatar of erickenb
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.SizerControlExit (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;

 - - - - - -  - - - -  - - - - - - - - - - - - -
ASKER CERTIFIED SOLUTION
Avatar of Member_2_248744
Member_2_248744
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial