Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Установка границ для вновь создаваемых элементов управления

Если вы создаете в среде 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;

Проект Delphi World © Выпуск 2002 - 2004
Автор проекта: ___Nikolay