Заставка, заставочка...

С чего начинается программа - не для разработчика, а для пользователя, который ее запускает? Очень часто именно с заставки, окна, которое выводится на экран еще до появления главного окна программы. Какие цели при этом преследуются?

Во-первых, "тяжеловесные" программы загружаются довольно продолжительное время, так что заставка информирует пользователя о том, что программа "жива" и происходит процесс ее загрузки. Часто при этом используется анимация - либо ничего не значащая и просто отражающая осуществление процесса инициализации, либо отображающая информацию о том, что же именно происходит в процессе загрузки (наименование выполняемой в данный момент операции, процент выполнения, время прошедшее/оставшееся).

Во-вторых, в окне заставки выводится некоторая информация - о названии продукта, версии, копирайте и т.п.

В-третьих, выводится изображение - один из логотипов, что создает благоприятное впечатление у пользователя, который, как обычно, встречает программу "по одежке", способствует ассоциативному запоминанию продукта.

Можно сказать, что все цели обусловлены работой на публику, т.е. продвижением программы. Трудно сказать, какая из них более важная. Ранее, видимо, большее значение имела первая - сопровождение длительной загрузки. В настоящее время, учитывая современные гигагерцы и гигабайты, важность сместилась ко второй и, скорее, даже в большей степени, к третьей. Впрочем, все зависит от каждого конкретного случая.

С точки зрения реализации, заставка - это обычно окно без заголовка, выводящееся поверх остальных окон приложения, содержащее изображение (bmp, jpeg и т.п.). Рассмотрим, как это осуществить в проекте, реализуемом с помощью Delphi.

В примерах самого Delphi есть проект, который с некоторыми изменениями идет от первой версии, демонстрирующий использование заставки ({Delphi PATH}\Demos\Db\MastApp\mastapp.dpr). Его, в первую очередь, и рассмотрим.

Загрузив файл проекта, можно увидеть, что все окна приложения создаются при старте программы. Естественно, на это уходит некоторое время, в течение которого на экране "висит" заставка. Все окна создаются с помощью метода Application.CreateForm(...), за исключением самого окна заставки, которое создается самым первым с помощью конструктора класса TSplashForm.Create(...). Это связано с тем, что первое окно, созданное с помощью метода приложения, становится главной формой, а заставка как раз ею быть не должна. После создания окна заставки вызываются его методы Show, а затем Update для его немедленной прорисовки на экране (поскольку цикл обработки сообщений в данном месте еще не запущен, он запускается с помощью Application.Run). После создания всех форм заставка скрывается и ликвидируется (Free).

Среди особенностей самой формы заставки следует отметить отсутствие заголовка (BorderStyle=bsNone) и вывод в центре экрана (Position=poScreenCenter).

Теперь следует сказать, что далеко не всегда приложение имеет много форм, а даже если и имеет, то создаются они не одновременно при старте приложения, а по мере необходимости, а после того, как необходимость отпадет, ликвидируются. Так что при старте создается главная форма, и время этого создания может быть так мало, что окно заставки в лучшем случае просто промелькнет на экране. Для того, чтобы оно было воспринято пользователем, нужно вводить задержки. Как это сделать?

Раз уж зашел разговор о задержке, то проще всего использовать таймер (TTimer). Поместим его на главную форму приложения, задав интервал, например, в 2 секунды (Interval=2000) и запретим отсчет (Enabled=False). В обработчике OnShow главной формы запустим отсчет таймера (Timer.Enabled=True). Ну а в обработчик таймера OnTimer перенесем сокрытие и разрушение формы-заставки (а создаваться она будет так же, как и в предыдущем случае). В результате окно заставки будет отображаться на экране еще две секунды после появления главной формы. Однако для того, чтобы появившееся главное окно не спрятало под собой заставку, нужно последнюю выводить поверх всех окон (FormStyle=fsStayOnTop).

Для того, чтобы сопроводить процесс загрузки программы некоторой информацией и придать динамичность длительной загрузке, можно разместить в окне заставки индикатор (Progress Bar) и метку (Label), в которых выводить требуемую информацию.

Ну а теперь остановимся на особенности использования заставки в приложении, работающем с базой данных. Главная отличительная особенность этого случая - необходимость аутентификации пользователя. Аутентификация пользователя производится с помощью модального окна (приостанавливающего работу потока до завершения его работы), по результатам выполнения которого делается вывод о том, продолжать ли программе работу или выгрузить ее по причине неудачной аутентификации. Как логически и технически совместить появление заставки и аутентификацию? Сначала выводить заставку, затем поверх нее окно аутентификации, дальше прятать окно аутентификации, создавать главное окно, потом прятать заставку? Или проводить аутентификацию, а затем выводить заставку? А если после старта программы надо вывести какое-то сообщение? Не слишком ли много окон и неприятная путаница для пользователя? Поразмыслив над этой задачей, мне пришла в голову мысль о том, чтобы совместить окна заставки и аутентификации в одном окне. Вырисовался следующий сценарий:

  • при старте программы появляется заставка;
  • выполняются действия по загрузке программы с отображением комментариев о ходе этих действий в заставке;
  • заставка переходит в модальный режим, в ней появляются элементы управления для ввода информации пользователем (аутентификации);
  • по окончании аутентификации заставка переходит в немодальный режим и происходит дозагрузка программы с учетом введенных данных, появлением главного окна и, опять-таки, с отображением комментариев об этом процессе в заставке.

Трудность реализации этой последовательности действий состояла в том, что в VCL нельзя сделать модальным видимое окно. Или оно модальное, или видимое - так реализован метод ShowModal класса TCustomForm. Что же делает ShowModal? По большому счету, он выполняет следующее: делает окно видимым; активизирует его; организует цикл обработки сообщений; по выходе из цикла деактивирует окно; затем делает его невидимым. Следовательно, для выполнения поставленной задачи нужно сделать примерно то же самое. Попробуем.

Поскольку метод ShowModal виртуальный, переопределим его для окна заставки, реализовав внутри свой цикл обработки сообщений.

function TSplashForm.ShowModal:Integer;
begin
 AutentificationPanel.Visible:=True;
 Update;
 FTerminated:=False;
 repeat
  Application.HandleMessage;
 until FTerminated;
 AutentificationPanel.Visible:=False;
 Update;
 Result:=0;
end;

где FTerminated - переменная класса формы.

Как видно, этот цикл действует до тех пор, пока FTerminated = False. Следовательно, достаточно этой переменной присвоить значение True в обработчике нажатия на кнопку (считая, что нажатие на нее завершает процесс ввода данных), чтобы завершить модальность формы-заставки.

Вызов метода Update обусловлен тем, что показ и гашение панели происходит вне цикла обработки сообщений.

Ну вот и готово, осталось только сделать вызов SplashForm.ShowModal из конструктора главной формы или из одного из ее обработчиков, например, OnCreate, OnShow. При использовании других обработчиков следует иметь в виду, что они могут вызываться по несколько раз (например, OnActivate), а поскольку для организации обработки сообщений используется цикл repeat...until, то тело цикла выполняется хотя бы один раз. Это может привести к потере сообщений уже запущенного цикла обработки сообщений приложения, поэтому первой строкой в теле метода ShowModal следует поставить проверку:

if FTerminated then exit;

Этого всего достаточно для решения поставленной задачи. Я решил добавить программе оригинальности и сделал панель с элементами для аутентификации не просто появляющейся, а всплывающей от нижнего края окна заставки, а после завершения аутентификации "съезжающей" обратно. Аналогично ведет себя панель задач (TaskBar) при установке параметра "автоматически убирать с экрана" (Auto hide). Могу сказать: смотрится неплохо:). Появляется заставка, бежит прогресс-бар, затем выезжает панель аутентификации, производится ввод данных о пользователе, панель съезжает вниз, прогресс-бар рисует дальше, появляется главное окно, заставка скрывается.

В заключение следует отметить, что заставку обычно делают прямоугольной (и даже в пропорциях "золотого сечения"). Другие формы (круг, эллипс или вообще произвольной формы) должны быть оправданы, скажем, категорией программы (например, мультимедиа). Иначе фамильярность заставки может прийти в противоречие с серьезными задачами, решаемыми программой. Здесь уже вступают в силу подходы, которые обусловлены задачами продвижения продукта.

Юрий А. СМАНЦЕР,
georgesman@mail.ru

Версия для печатиВерсия для печати

Номер: 

29 за 2003 год

Рубрика: 

Азбука программирования
Заметили ошибку? Выделите ее мышкой и нажмите Ctrl+Enter!