Установка границ для вновь создаваемых элементов управления
Если вы создаете в среде Delphi новый элемент управления, и вам нужно
контролировать или ограничить свойства Left, Top, Width и Height, то спешу вас
обрадовать: есть одно простое решение сделать это. Тем не менее, в документации
по Delphi я не увидел ни малейшего намека на данный способ (включая CWG).
Ключевой момент кроется в изменении Left, Top, Width, Height и каждого
BoundsRect в Delphi методом SetBounds() (доступного в TControl и во всех его
потомках). SetBounds() - виртуальная фунция, делающее установление позиции и
размера элемента управления делом легким и приятным. Тем не менее, о чем
умалчивается в документации, что TControl.SetBounds() вызывает методы TControl
SetLeft(), SetTop(), SetWidth() и SetHeight() при каждом изменении значений
свойств Left, Top, Width, Height и BoundsRect.
Таким образом, для того, чтобы ловить изменения этих свойств, просто
перекройте метод SetBounds(), сделайте все, что вам нужно с новыми значениями,
после чего передайте их унаследованному методу SetBounds().
В следующем примере мы имеем управление, которое автоматически изменяет свои
пользовательские свойства X & Y, с той целью, чтобы они ссылались на центр
элемента управления при изменении значений Left, Top, Width, Height или
BoundsRect. И наоборот, Left и Top будут изменяться всякий раз при изменении
свойств X & Y:
type
TMyControl = class(TControl)
private
FX, FY: integer;
{методы доступа к свойствам}
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
{Продолжаем, и позволяем SetBounds() сделать свое дело...}
inherited SetBounds(aLeft, aTop, aWidth, aHeight);
{Теперь "регулируем" FX и FY согласно нашим новым границам.}
FX := Width div 2;
FY := Height div 2;
end;
|
Также в документации не упоминается о том факте, что частные поля FLeft,
FTop, FWidth и FHeight, которые TControl использует для хранения внутренних
значений, используются в методах SetLeft(), SetTop() и пр. для сравнения с
текущими границами прямоугольника, при совпадении которых он не обновляется.
Фактически, эти переменные нигде, кроме как в методе TControl SetBounds(), не
корректируются (как в случае с FX и FY в приведенном выше примере).
Так, чтобы ограничить изменения размеров вашего элемента управления, вы
должны перекрыть SetBounds(), и проверять/изменять любые свойства перед
передачей значений унаследованному методу SetBounds().
В следующем примере мы имеем управление, которое ограничивает свою ширину и
высоту в 100 пикселей:
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;
|
|