Ключевой момент кроется в изменении 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; |
[001594]