Главная » Delphi » Диалог для установки таймера в SiideShow

0

Заново перенесем старый проект SiideShow а версии 1.20 из главы 4 (Glava4\2) в новую папку (Glava9\2), присвоим ему номер 1.21 и несколько изменим его: восстановим а модуле slide.pas для переменной mayciose значение False по умолчанию (в секции объявлений переменных) и удалим из основной программы строки:

CreateMyicon; {создаем иконку в Tray}

Application.ShowMainForm:=False; {не показываем главную форму}

Теперь наша программа будет запускаться сразу после демонстрации заставки, а не сворачиваться в иконку — для подобного приложения это логичнее.

Нам нужен диалог с возможностью ввода чисел. Установим на форму еще один компонент Panel (он получит имя Рапе12), а на него— Label, однострочный редактор Edit и компонент upDown (он находится на вкладке Win32 палитры компонентов), который пристыкуем к Editl справа. Кроме этого, установим на панель кнопку Button2 с заголовком ок. В свойство Caption компонента Label 1 впишем Установка интервала, с. В СВОЙСТВО Text компонента Editl поместим з, и свяжем между собой Edit и UpDown. Для этого в свойство Associate компонента upDown необходимо вставить Editl (через выпадающее меню)1. После подгонки размеров и положения компонентов наша панель должна выглядеть так, как показано на рис. 9.2, и располагаться посередине окна приложения.

Не забудем также установить для панели свойство visible в False — сначала при запуске она должна быть невидимой. А в компоненте upDowni установим минимальный (1) и максимальный (100) пределы изменений. Надо сказать, что в этом отношении Delphi несколько подкачала (точнее, не столько Delphi, сколько Windows)— обратной связи между компонентами Edi- и upoown нет, т. е. если вы вручную запишите в Edit число, большее максимума или меньшее минимума, установленного в UpDown, то программа это спокойно проглотит (спасибо уж и на том, что отслеживаются ошибки, связанные с вводом нечислового значения). По этой причине нам придется создать соответствующее ограничение вручную. Другой момент, связанный с компонентом Edit, мы уже упоминали в главе 8 — при его фокусировке текст, находящийся в нем по умолчанию, выделяется, и последующий ввод заменит данный текст. Это далеко не всегда удобно, не говоря уж о том, что выделенный текст плохо виден и его непросто прочитать (насколько это неудобно, вы можете видеть на примере обращения к полям Object Inspector в Delphi, да и вообще почти любого диалога в Windows). Как мы уже знаем, для отключения выделения Достаточно установить СВОЙСТВО AutoSelect в False.

Рис. 9.2. Заготовке панели диалоге для установки твймера

Теперь перейдем к реализации диалога. Для этого сначала в пункте главного меню (компонент MainMenul) Демонстрация, ниже имеющегося подпункта Запуск, создадим разделитель (для этого надо создать пункт с заголовком "-"), а потом еще ниже введем пункт Интервал. Назовем его intl и присвоим ему горячую клавишу <Shift>+<F9>. Обработчик события по обращению к этому пункту будет таким:

procedure TForml.IntlClick(Sender: TObject); begin

{обращение к пункту меню Интервал)

Panel2.Visible:=True; {показываем панель установки времени) Editl.SetFocus; {фокусируемся на редакторе/ end;

После ввода значения времени мы нажмем кнопку Ok (Button2), и для этого события нужно написать следующий обработчик:

procedure TForml.Button2Click(Sender: TObject); begin

{нажатие на кнопку Ок на Рапе12) if (StrToInt(Editl.Text)<1) then Editl.Text:=’1′; if (StrToInt(Editl.Text)>100) then Editl.Text:=’100′; Timerl.Interval:=StrToInt(Editl.Text)*1000;

{устанавливаем интервал таймера) Panel2.Visible:=False; {закрываем панель) end;

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

Но это еще далеко не все. Во-первых, если мы работаем с клавиатуры, го прямо нажать на клавишу <Enter>, чтобы закончить диалог, не получится — фокус находится на компоненте Edit и придется манипулировать с клавишей <ТаЬ> либо, как большинство и поступает, хвататься за мышь. Это и неудобно, и, если можно так выразиться, "неконцептуально". Поэтому придется делать отдельный обработчик, чтобы отследить нажатие клавиши <Enter>. Так как в фокусе при работе с клавиатурой находится компонент Editl, то обработчик мы сделаем для него:

procedure TForml.EditlKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);

begin

(нажатие на Enter после редактирования интервала}

if key=vk_Return then

begin

if (StrToInt(Editl.Text)<1) then Editl.Text:=’1′; if (StrToInt (Editl.Text) >100) then Editl.Text: = 400′; Timerl.Interval:-StrToInt(Editl.Text)*1000;

lустанавливаем интервал таймера I Panel2.Visible:=False; {закрываем панель! end; end;

Но и это еще не все! Если пользователь работает не с клавиатурой, а с мышью через компонент upDown, то нажать на кнопку Ok ему ничего не стоит, но еще лучше дать ему возможность также выйти из диалога по двойному щелчку просто на редакторе или на панели — это будет совсем грамотно (компонент Panel не отслеживает события клавиатуры, но события мыши отслеживают все без исключения визуальные компоненты)- Казалось бы, кнопку Ok вообще можно было бы тогда не вводить, но это рассуждение справедливо только теоретически — выход из ситуации должен быть указан явно (и мы почти нарушаем данное положение, когда не вводим в меню специальный пункт для выхода из программы — просто его никто не станет искать, т. к. кнопка-крестик всегда перед глазами).

Для того чтобы сделать, как написано, придется создать еще два обработчика— процедуры EditiDbiciick и Panei2Dbiciick. Таким образом, у нас получится целых три идентичных процедуры — уже есть процедура Button2Ciick (процедура по нажатию клавиши <Enter> отличается от них). Нельзя ли как-нибудь упростить и сократить это дело? Запросто: надо в закладке Events для соответствующего компонента (Editl и Рапе12) выбрать нужное событие (onDblciick) и через выпадающий список по кнопочке справа выбрать процедуру из имеющихся — в нашем случае Button2Ciick. Тогда по двойному щелчку на панели или в поле редактора будет выполняться та же самая процедура, что и по нажатию кнопки. Этот фокус типа "один обработчик — много действий" не пройдет, если процедуры разного типа— так, назначить событию нажатия клавиши обработчик щелчка мышью не получится. Это ограничение все же можно преодолеть, если использовать невизуальный компонент TActionList, но, на мой вкус, предлагаемый механизм там слишком сложен, чтобы имело смысл его использовать в таких простых случаях.

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

Panel2.Visible:=False; (закрываем панель)

В том числе надо добавить эту строку и в обработчик события onDeactivate формы Formi — тогда у нас диалог будет пропадать и при сворачивании формы в иконку. Причем учтем, что самое естественное действие в случае, если диалог вызван по ошибке— щелкнуть вне его на поле окна. Поэтому мы не поленимся, и специально на этот случай создадим обработчик события onclick для компонента imagel (он у нас занимает большую часть площади окна и расположен как раз под панелькой):

procedure TForml.ImagelClick(Sender: TObject); begin

Panel2.Visib.l.e:=False; (закрываем панель/ end;

А почему бы не создать точно такой же обработчик для щелчка по Panel 1 или, к примеру, по самой форме (рамке вокруг нашего "экрана")— вдруг пользователь промахнется? Проделаем тот же фокус, что и раньше— перейдем к закладке Events нужного компонента (Paneii и Forml), выберем событие onclick и в выпадающем списке укажем нужный обработчик (теперь уже imageiciick). Проверьте — все работает!

Источник: Ревнч Ю. В.  Нестандартные приемы программирования на Delphi. — СПб.: БХВ-Петербург, 2005. — 560 е.: ил.

По теме:

  • Комментарии