При каких условиях TForm будет отображать OnResize?
Вопрос
В качестве расширения этот вопрос:
TForm.OnResize иногда запускается перед первым отображением формы, но не всегда.Например, если BorderStyle имеет значение bsDialog или bsNone, то OnResize не сработает.Для всех других значений BorderStyle (и для всех других свойств по умолчанию) OnResize срабатывает.
Есть ли другие факторы, влияющие на то, будет ли срабатывать OnResize перед отображением формы? Например, какие другие свойства или комбинации свойств могут на это повлиять?
Событие OnResize является результатом ShowWindow
Функция API, отправляющая WM_SIZE
сообщение в окно.Стоит повторить: сообщение приходит из Windows, а не из Delphi. Это функция Windows (ShowWindow
), который (иногда) отправляет сообщение, которое запускает событие, поэтому исходный код VCL в этом случае не очень полезен.
Бонусные баллы за исчерпывающие ответы, основанные на документированных ShowWindow
/ WM_SIZE
поведение, напримерссылки на документацию MSDN или книги Петцольда.
Решение
Возможно, это даже зависит от настроек дисплея пользователя, темы рабочего стола или версии Windows.Если бы OnResize вызывал у меня подобные проблемы, я бы построил свою программу так, чтобы она всегда ожидала этого и обрабатывала его в любой ситуации, независимо от того, что, по моему мнению, является причиной.
Другие советы
Я считаю, что OnResize будет снимать, когда событие отправляет сообщение, в котором говорится, что размер формы (слева, снизу, ширина, высота) будет изменен.
Поскольку вы уже обнаружили, какое сообщение запускает это событие, вам теперь нужно отследить, где сообщение отправляется в VCL.
Посмотрите исходный код vcl, чтобы узнать, сможете ли вы обнаружить эти операции.
Редактировать:пойдем на низкий уровень.Формы в Windows (грубо говоря) имеют то, что называется «класс окон» (это не тот класс, как мы его знаем OOP).Каждый раз, когда размер окна формы изменяется (и форма видна), отправляется WM_SIZE.
Таким образом, это будет происходить не каждый раз, когда отображается форма, а изменяются только ее размеры по сравнению с базовым классом окна.
Как вы заметили, многие свойства valuez меняют размеры формы (даже на несколько пикселей).
Это очень поверхностно объяснение, это масса других деталей - но я понимаю, как все работает «под капотом».
Ничто не заменит тестирование.Как насчет создания формы в коде, установки интересующих вас свойств и записи момента вызова события изменения размера.
Если вы извините за уродство кода, вот грубое доказательство концепции, которое тестирует все комбинации BorderStyle и Position без явного написания кода для каждой из них.Вы можете добавить больше свойств и использовать их так далеко, как захотите.Такой инструмент, как CodeSite, также сделает ведение журнала более понятным и простым.
Создайте приложение с двумя формами.Убедитесь, что второй не создается автоматически.
Во второй форме добавьте свойство и небольшой код регистрации в событие Resize формы:
private
FOnResizeFired: TNotifyEvent;
public
property OnResizeFired: TNotifyEvent read FOnResizeFired write FOnResizeFired;
end;
...
procedure TForm2.FormResize(Sender: TObject);
begin
if Assigned(FOnResizeFired) then
FOnResizeFired(self);
end;
В основной форме добавьте TypInfo в раздел Uses и поместите в форму кнопку и заметку.
Добавьте простую процедуру:
procedure TForm1.ResizeDetected(Sender: TObject);
begin
Memo1.Lines.Add(' *** Resize detected');
end;
Теперь добавьте в событие ButtonClick следующее:
procedure TForm1.Button1Click(Sender: TObject);
var
lBorderStyle: TFormBorderStyle;
lBorderStyleName: string;
lPosition: TPosition;
lPositionName: string;
lForm: TForm2;
begin
Memo1.Clear;
for lBorderStyle in [low(TFormBorderStyle) .. high(TFormBorderStyle)] do
begin
for lPosition in [low(TPosition) .. high(TPosition)] do
begin
lBorderStyleName := GetEnumName(TypeInfo(TFormBorderStyle), Integer(lBorderStyle));
lPositionName := GetEnumName(TypeInfo(TPosition), Integer(lPosition));
Memo1.Lines.Add(Format('Border: %s Position: %s', [lBorderStyleName, lPositionName]));
Memo1.Lines.Add(' Creating form');
lForm := TForm2.Create(self);
try
Memo1.Lines.Add(' Form Created');
lForm.OnResizeFired := ResizeDetected;
Memo1.Lines.Add(' Setting border style');
lForm.BorderStyle := lBorderStyle;
Memo1.Lines.Add(' Setting Position');
lForm.Position := lPosition;
Memo1.Lines.Add(' Showing form');
lForm.Show;
Memo1.Lines.Add(' Form Shown');
lForm.Close;
Memo1.Lines.Add(' Form Closed');
finally
FreeAndNil(lForm);
Memo1.Lines.Add(' Form Freed');
end;
end;
end;
end;
Вы заметите, что изменение размера срабатывает, когда некоторые свойства установлены до отображения формы, и я вижу, что в некоторых комбинациях изменение размера срабатывает дважды при отображении формы.Интересный.