В своем блоге Александр Бондарь публикует своего рода методические пособие по RAD Studio. Дело это, безусловно, полезное с точки зрения популяризации Delphi, поэтому этот блог и включен в ленту новостей Delphifeeds.Ru. Хотя, наверняка, для большинства читателей сайта, работающих с Delphi/C++ Builder на практике, в этих постах интересного мало. В свое время у меня был некоторый педагогический опыт и опыт написания методических пособий. К сожалению, с тех пор минуло довольно много времени и найти их я не смог. Но на волне ностальгии, меня посетила мысль в своем блоге дополнить данное пособие, парочкой интересных, на мой взгляд, кейсов. Не думаю, что для профессионалов здесь будут какие-то откровения, но для “продвинутых” студентов это может быть интересно.
Этимология форм
Если говорить о формах, то весьма важно разобраться с их сущностью. Понятно, что речь идет об объекте, но объект этот не совсем обычный. Начальные значения его свойств хранятся в специальных файлах форм. В случае VCL они имеют расширение *.dfm, если речь идет о FireMonkey, то *.fmx. Данные файлы можно отредактировать, как с использованием IDE, так и в обычном текстовом редакторе. В первом случае, достаточно в редакторе форм из контекстного меню выбрать пункт View as Text. Во втором случае следует найти файл с именем модуля, содержащего форму и расширением *.dfm или *.fmx, и открыть его в текстовом редакторе. После этого, можно поменять какое-либо из свойств формы, например, Caption и, вернувшись в редактор формы, посмотреть как изменится внешний вид формы. Заодно и поэкспериментировать с кодировками.
object fMain: TfMain Left = 0 Top = 0 Caption = #1053#1086#1074#1099#1081' '#1079#1072#1075#1086#1083#1086#1074#1086#1082 ClientHeight = 299 ClientWidth = 635 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False PixelsPerInch = 96 TextHeight = 13 object btnStart: TButton Left = 520 Top = 256 Width = 75 Height = 25 Caption = 'Start' TabOrder = 0 OnClick = btnStartClick end object ButtonedEdit1: TButtonedEdit Left = 24 Top = 32 Width = 273 Height = 21 TabOrder = 1 Text = 'c:\change' end object Edit1: TEdit Left = 336 Top = 32 Width = 121 Height = 21 TabOrder = 2 Text = '2setup_v_11_0_19' end end Листинг 1.
Редактор кода IDE достаточно оригинально преобразовывает русские символы в *.dfm файлах.
Задание стартовой формы и структура приложения
Кроме файла форм, в проекте присутствует файл проекта. Его можно увидеть вызвав пункт меню Project | View Source.
Задать стартовую форму можно непосредственно в коде. Для этого, достаточно поменять последовательность создания форм. Та форма, которая создается первой и будет стартовой.
Здесь же нелишне упомянуть, что правильнее создавать формы динамически, а не использовать Auto-create forms. Соответственно, отключить создание по-умолчанию формы можно, как в коде проекта, так и в опциях проекта.
program setupCopy; uses Vcl.Forms, uMain in 'uMain.pas' {fMain}, uAdd in 'uAdd.pas' {Form1}; {$R *.res} begin Application.Initialize; Application.MainFormOnTaskbar := False; Application.CreateForm(TForm1, Form1); // Это форма будет главной Application.CreateForm(TfMain, fMain); // Если эту строку закомментировать, форма не попадет в список Auto-create в опциях Application.Run; end.
Листинг 2
События формы
Здесь, самое интересное, на мой взгляд, последовательность событий при загрузке формы. Для того, что бы наглядно отследить эту последовательность можно воспользоваться утилитой CodeSite, из-под пера Рея Конопки. В секции Uses главной формы приложения подключим модуль CodeSiteLogging, а в обработчик каждого из потенциально интересующих нас событий, впишем следующую строку
CodeSite.Send(<имя события>);
где укажем название обрабатываемого события. Примерно так:
procedure TForm1.FormActivate(Sender: TObject); begin CodeSite.Send('FormActivate' ); end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin CodeSite.Send('FormClose' ); end; procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin CodeSite.Send('FormCloseQuery' ); end; procedure TForm1.FormCreate(Sender: TObject); begin CodeSite.Send('FormCreate' ); end; procedure TForm1.FormHide(Sender: TObject); begin CodeSite.Send('FormHide' ); end; procedure TForm1.FormPaint(Sender: TObject); begin CodeSite.Send('FormPaint' ); end; procedure TForm1.FormResize(Sender: TObject); begin CodeSite.Send('FormResize' ); end; procedure TForm1.FormShow(Sender: TObject); begin CodeSite.Send('FormShow' ); end;
Результат будет выглядеть следующим образом:
FormCreate
FormShow
FormActivate
FormResize
FormPaint
FormCloseQuery
FormClose
FormHide
FormDestroy
Обратите внимание, что событие OnPaint вызывается последним при открытии формы, после этого, мы просто закрываем ее и наблюдаем вызов еще четырех обработчиков событий.
И здесь еще один любопытный пример, с которым часто сталкиваются новички.
Создадим, новое приложение, добавим еще одну форму. Обе формы будут создаваться автоматически, так, как это есть по-умолчанию. В секции Uses первой формы подключим вторую форму и в обработчике события onCreate попытаемся ее отобразить. В результате получим Access Violation. Иначе говоря, попытка обратиться к несуществующему объекту. Этот пример позволяет понять, в какой последовательности отрабатываются события в процессе запуска приложения.
Давайте еще раз посмотрим на код приложения (Листинг 2).
OnCreate главной формы вызывается, что совершенно логично, в момент создания формы. В это время вторая форма еще не создана. Однако, отображение главной формы происходит в результате вызова метода Run, объекта Application. К этому моменту вторая форма уже создана. Поэтому, если перенести вызов второй формы на обработчик события OnShow, все заработает.
И в заключение вопрос на сообразительность. Можно ли закрыть форму таким образом, что бы обработчик события OnClose не вызывался?
А можно я ещё вот такую ссылочку оставлю?
http://www.delphinotes.ru/2013/03/form-events.html
Там есть ссылка на exe-файл, я специально писал программку для того, чтобы легче осознать когда и какие события вызываются (ну кроме Resize и Paint, т.к. в них закладывать логику обработки ввода пользователя смысла нет).
Спасибо.
Знаете – ХОРОШО написано. С ТОЛКОМ. Мне – НРАВИТСЯ. Но НЕПОНЯТНО – зачем. Неужто это всё НЕЛЬЗЯ прочесть в документации? Я не “наезжаю”.. Я правда спрашиваю.
Я и про Бондаря могу сказать – он – МОЛОДЕЦ. НУЖНОЕ ДЕЛО делает. Но вот “уровень”. Правда ТАКОЙ нужен?
Опять же – “без наездов”. Я Попытался рассказать про DUnit и Unit-тестирование. На основе примера, который предложил Всеволод Леонов. Мне и этот-то пример показался “примитивным”. Но ведь “оказывается”, что и это – “сложно”, что “надо бы про DUnit написать”. Так скажем “для чайников”. А надо ли? Без чтения документации – далеко ли мы уйдём? Или я чего-то не понимаю?
Помнишь, я пытался в комментариях у тебя в блоге отстоять точку зрения, что такой уровень только вредит, так как крадет время у более серьезных вопросов. Помнишь, что мне было отвечено (не тобой, конечно)?
а вот про dunit твой я вот что скажу. Это ведь взаимосвязано. использование dunit сложно именно для тех, кого старательно учили именно на таком уровне: “сегодня мы изучаем TForm”… Тьфу.
Это я всё к чему? Я ведь “могу” многое рассказать.. Если интересно, но как Тепляков или GunSmoker – писать не умею. Я всё “нащупываю” так скажем “аудиторию”. И не могу понять “планку”.
“Сложно” писать – “не понимают”.
“Просто” – “тривиально”.
Или “забить”?
“О Формах” ведь тоже многое можно написать, один только вопрос мучает “а надо ли”?