Но самое интересное происходит, если свойство WindowState
во время проектирования получило значение wsMaximized
, а свойство Position
— значение poDefault
или poDefaultSizeOnly
. Тогда размеры и положения визуальных компонентов на форме будут адаптированы к размеру, который не совпадает ни с размером развернутой формы, ни с размером, заданным во время проектирования. Если такой форме отменить развертывание на весь экран, то визуальные компоненты получат размеры и положения, установленные в режиме проектирования.
Нельзя сказать, что разработчики Delphi не знакомы с этой проблемой, они даже что-то делают, чтобы ее решить. Начиная с BDS 2006 можно устанавливать значение свойства WindowState
в режиме проектирования, и визуальные компоненты на такой форме будут вести себя интуитивно ожидаемым образом, т.е. адаптироваться к размеру формы, растянутой на весь экран. Правда, с двумя существенными оговорками. Во-первых, свойство Position формы не должно быть равно poDefault
или poDefaultSizeOnly
. Во-вторых, это относится только к главной форме приложения, для всех остальных форм проблема сохраняется. Поэтому пример WrongAnchors будет работать одинаково и в новых версиях Delphi, и в старых — там на весь экран разворачиваются не главные формы.
3.4.8. Ошибка при сравнении указателей на метод
Процедурные типы в Delphi делятся на обычные (унаследованные от Turbo Pascal) и указатели на методы. Первые — что указатели на простые процедуры и функции, вторые — на методы объектов. Чтобы вызвать метод объекта недостаточно знать, где его код располагается в памяти, нужно еще иметь ссылку на конкретный экземпляр класса, к которому относится данный метод (т.е. необходимо значение указателя Self
, который будет передан в данный метод). Поэтому указатели на методы называются указателями лишь условно: на самом деле это не один указатель, а два (на код и на объект). Размер переменных такого типа равен 8 байтам, в чем нетрудно убедиться с помощью функции SizeOf
.
Очевидно, что два указателя на метод равны тогда и только тогда, когда указывают на один и тот же метод одного и того же объекта, т.е. входящие в них указатели попарно равны. Однако компилятор сравнивает указатели на методы неправильно, и пример MethodPtrCmp
на компакт-диске демонстрирует это. На форме этого примера расположены две кнопки класса TButton
. Обработчик нажатия на первую из них выглядит так, как в листинге 3.60.
Листинг 3.60. Пример неправильного сравнения указателей на метод
procedure TForm1.ButtonlClick(Sender: TObject);
var
P1, P2: procedure of object;
begin
P1 := Button1.Update;
P2 := Button2.Update;
// Здесь компилятор сравнивает указатели на методы неверно,
// давая ошибочный результат "равно"
if @Р1 = @Р2 then Label1.Caption := 'Равно'
else Label1.Caption := 'Не равно';
end;
Здесь мы получаем указатели на один и тот же метод разных объектов (для примера взяты класс TButton
и метод Update
, но подошел бы любой класс и любой метод). Сравнение указателей в этом примере дает ошибочный результат Равно, хотя эти указатели не равны между собой. Просмотр кода, который генерирует компилятор, показывает, что здесь сравниваются только указатели на код метода, а указатели на объекты игнорируются. Так как у нас метод один и тот же, различаются только объекты, то и получается ошибочный результат.
Сравнить указатели на методы правильно можно с помощью типа TMethod
из модуля SysUtils
, объявленного следующим образом:
TMethod = record
Code, Data: Pointer;
end;
Так можно получать доступ к отдельным указателям, входящим в указатель на метод. Сравнение указателей на метод с помощью этого типа иллюстрирует листинг 3.61.
Листинг 3.61. Правильный способ сравнения указателей на метод
procedure TForm1.Button2Click(Sender: TObject);
var
P1, P2: procedure of object;
begin
P1 := Button1.Update;
P2 := Button2.Update;
// Правильный способ сравнения указателей на методы
if (TMethod(P1).Data = TMethod(P2).Data) and
(TMethod(P1).Code = TMethod(P2).Code) then
Label1.Caption := 'Равно'
else Label1.Caption := 'He равно';
end;
Здесь мы явным образом заставляем компилятор сравнивать оба указателя, поэтому получаем правильный результат Не равно.
3.4.9. Возможность получения адреса свойства
Пусть у нас есть класс, описанный следующим образом (листинг 3.62).
Листинг 3.62. Класс со свойствами, читаемыми из переменной и из функции
TSomeClass = class private
Читать дальше
Конец ознакомительного отрывка
Купить книгу