Contributor: MARK JOHNSON
{
If you are designing a new Delphi control and you need to catch
or limit changes to Left, Top, Width, or Height, there is one
simple way to do it. However, I have yet to see the slightest
hint of how to do it in the Delphi documentation (including
the CWG).
The key to catching changes to Left, Top, Width, Height, and
even BoundsRect in Delphi is the SetBounds() method (found
in TControl and all descendants). SetBounds() is a virtual
function used to set the position and size of a control
all in one easy step. However, what they do not tell you
in the documentation is that TControl.SetBounds() is called
by TControl's SetLeft(), SetTop(), SetWidth(), and SetHeight()
property access methods every time a value is assigned to
the Left, Top, Width, Height, and BoundsRect properties.
Thus, to catch changes to these properties, simply override
the SetBounds() method, do whatever you need with the new
values, and then pass them on to the inherited SetBounds()
method.
In the following example, I have a control that automatically
updates its X & Y custom properties to refer to the center
of the control whenever Left, Top, Width, Height, or BoundsRect
are changed. Conversely, Left and Top will be updated whenever
X & Y are changed: }
type
 TMyControl = class(TControl)
 private
 FX, FY : integer;
 {property access methods}
 procedure SetX(value : integer);
 procedure SetY(value : integer);
 ...
 public
 procedure SetBounds(aLeft, aTop, aWidth, aHeight : integer); override;
 ...
 property X : integer read FX write SetX;
 property Y : integer read FY write SetY;
 end;
...
procedure TMyControl.SetX(value : integer);
begin
 if FX  value then 
 SetBounds(value - Width div 2, Top, Width, Height);
end;
procedure TMyControl.SetY(value : integer);
begin
 if FY  value then
 SetBounds(Left, value - Height div 2, Width, Height);
end;
procedure TMyControl.SetBounds(aLeft, aTop, aWidth, aHeight : integer);
begin
 {Go ahead and let SetBounds() do its thing...}
 inherited SetBounds(aLeft, aTop, aWidth, aHeight);
 {Now adjust FX and FY according to our new bounds.}
 FX := Width div 2;
 FY := Height div 2;
end;
Also not mentioned in the documentation is the fact that the
FLeft, FTop, FWidth, and FHeight private fields that TControl
uses to keep track of its bounding rectangle are not updated
in the corresponding SetLeft(), SetTop(), etc. property access
methods. These variables, in fact, do not get updated anywhere
except in TControl's SetBounds() method (as with FX and FY in
the above example).
So, to limit changes to the bounds of your control, you can
override SetBounds() to check and modify any of the properties
before passing the values on to the inherited SetBounds()
method.
In the following example, I have a control that limits its
width and height to no more than 100 pixels:
type
 TMyControl = class(TControl)
 ...
 public
 procedure SetBounds(aLeft, aTop, aWidth, aHeight : integer); override;
 ...
 end;
...
procedure TMyControl.SetBounds(aLeft, aTop, aWidth, aHeight : integer);
begin
 if aWidth> 100 then
 aWidth := 100;
 if aHeight> 100 then
 aHeight := 100;
 inherited SetBounds(aLeft, aTop, aWidth, aHeight);
end;


AltStyle によって変換されたページ (->オリジナル) /