Рисунок 9.13. Компонент Panel заменил в форме компонент Bevel
Шаг 13. С помощью окна Object TreeView перенесите компоненты Image1, Label1 и Label2 на панель Panel1 (рисунок 9.14).
Рисунок 9.14. Компоненты Image1, Label1 и Label2 переносятся на панель Panel1
Теперь рельефная рамка заменена рельефной панелью и при ее перемещении перемещаются все надписи и рисунок (рисунок 9.15).
Рисунок 9.15. Компоненты Image1, Label1 и Label2 — теперь на панели Panel1
351
Будьте аккуратны при удалении панели! Вместе с ней всегда удаляются внутренние компоненты.
9.2.8. Выполнение диалога
Визуальное проектирование окна About закончено, осталось обеспечить его вызов при выборе пользователем команды Help | About... главного меню. Для этого нужно сделать следующее:
создать команду AboutAction в компоненте ActionList и связать ее с пунктом меню
About...;
в модуле MainUnit подключить модуль AboutUnit. Это обеспечит доступ к форме
AboutForm из главной формы PictureForm;
создать обработчик события OnExecute команды AboutAction и обеспечить в нем монопольное выполнение диалога.
Шаг 14. Как реализовать первый пункт плана вы уже знаете, поэтому мы не будем на нем останавливаться, и сразу перейдем ко второму пункту плана. Активизируйте PictureForm, а затем выберите в меню File команду Use Unit... . На экране появится окно (рисунок 9.16):
Рисунок 9.16. С помощью окна Use Unit модуль About подключается в модуле Main
Выберите в этом окне модуль AboutUnit и щелкните на кнопке OK. Модуль AboutUnit, содержащий определение формы AboutForm, подключится в модуле MainUnit, содержащем определение главной формы PictureForm. Чтобы в этом убедиться, перейдите к редактору кода. В разделе implementation модуля MainUnit вы обнаружите строку
uses AboutUnit;
Ее можно было бы набрать и вручную, но мы решили продемонстрировать вам еще одну возможность визуальной среды программирования.
Шаг 15. Выполните теперь второй пункт плана — создайте обработчик события OnExecute
для команды AboutAction компонента ActionList:
352
procedure TPictureForm.AboutActionExecute(Sender: TObject); begin
AboutForm.ShowModal; end;
Метод ShowModal запускает окно диалога в монопольном режиме и возвращает управление только после его завершения. В нашем примере метод вызывается как процедура, но в действительности это функция, которая возвращает код завершения диалога. Код берется у формы из свойства ModalResult. Напомним, что для выполнения диалога в немонопольном режиме его нужно вызвать с помощью метода Show, а не метода ShowModal.
Шаг 16. Выполните компиляцию и запустите программу, затем проверьте работу новоиспеченного окна диалога, выполнив команду меню Help | About... (рисунок 9.17).
Рисунок 9.17. Диалоговое окно в работе
Все работает правильно, остается только выяснить один вопрос: где, когда и кем конструируется объект AboutForm. Ведь никаких усилий мы для этого не предпринимали, и тем не менее использовали объект при вызове метода ShowModal как уже существующий.
Объект AboutForm создается при запуске программы и существует на протяжении всей ее работы. В этом можно убедиться, заглянув в главный файл программы с помощью команды меню View | Project Source. В главном программном блоке вы найдете оператор:
Application.CreateForm(TAboutForm, AboutForm);
Он-то и обеспечивает "автоматическое" создание объекта формы. Это удобно, но имеет и отрицательные стороны, так как память, выделенная объекту остается занятой даже тогда, когда форма невидима, т.е. до запуска диалога и после его завершения. Если программа имеет одну-две формы, это не так важно, а если много? В этом случае от автоматического создания всех форм, кроме главной, лучше отказаться.
Шаг 17. Чтобы исключить автоматическое создание формы AboutForm, откройте окно Project Options и на вкладке Forms отбуксируйте элемент AboutForm из списка Autocreate forms в список Available forms (рисунок 9.18):
353
Рисунок 9.18. Форма AboutForm исключена из списка автоматически создаваемых форм
В результате среда Delphi удалит приведенный выше оператор из главного файла программы, переложив заботу о создании формы на ваши плечи.
Шаг 18. Разумеется, что после сделанных действий метод AboutItemClick, из которого вызывается окно диалога, нужно переписать:
procedure TPictureForm.AboutActionExecute(Sender: TObject); begin
AboutForm := TAboutForm.Create(Self); try
AboutForm.ShowModal; finally
AboutForm.Free; end;
end;
Ну вот, теперь ресурс оперативной памяти используется более рационально. Кстати, обратите внимание, как обеспечивается защита объекта AboutForm от исключительных ситуаций, которые могут возникнуть в период его работы (это конечно маловероятно, но чего в этой жизни не бывает!). Если объект AboutForm успешно создается, то благодаря оператору try...finally...end он всегда корректно освобождается, даже в случае возникновения исключительной ситуации.
9.3. Компоненты для ввода данных
Вы получили первое представление об окнах диалога, научились создавать и выполнять простейшие из них. Но вы еще не знаете, как организовать диалог для получения данных от пользователя. Эта задача решается с помощью компонентов для ввода данных, к изучению которых мы сейчас приступаем.
Использование компонентов для ввода данных рассмотрим на примере приложения Alarms. Эта полезная программа позволит создать список будильников для уведомления о предстоящих событиях. По сигналу будильника в заданные время и день появится окно с сообщением и прозвучит сигнал. Список будильников будет отображаться в главном окне
354
программы, а установка их параметров будет выполняться в модальном окне диалога. В процессе разработки этого приложения вы познакомитесь с такими компонентами, как
CheckBox, RadioButton, ComboBox, ListBox, GroupBox, Edit, MaskEdit и некоторыми другими. Итак, приступим.
Шаг 1. Сначала приготовьте новый проект с пустой формой, выбрав команду меню File | New Application. Дайте форме идентификатор MainForm, скорректируйте ее размеры и установите следующие значения свойств:
Caption = Clock Alarms
BorderIcons = [biSystemMenu,biMinimize]
BorderStyle = bsSingle
Position = poDefaultPosOnly
Сохраните модуль формы под именем MainUnit.pas, а проект — под именем Alarms.dpr.
Шаг 2. В форме MainForm будет отображаться список будильников. Для управления списком нужны кнопки: New, Edit и Delete. Для быстрого и удобного закрытия формы нужна еще кнопка Close. Поэтому поместите в форму соответствующее число компонентов Button
(с идентификаторами NewButton, EditButton, DeleteButton, CloseButton) и задайте для них надписи, размеры и положение как на рисунке 9.19.
Рисунок 9.19. Кнопки для управления списком будильников
Шаг 3. Установите в компоненте NewButton свойство Default в значение True, чтобы кнопка срабатывала при нажатии клавиши Enter.
Шаг 4. Для компонента CloseButton создайте следующий обработчик события OnClick:
procedure TMainForm.CloseButtonClick(Sender: TObject); begin
Close; end;
Шаг 5. Необходимые подготовительные операции сделаны. Теперь перейдем к разработке окна диалога, предназначенного для ввода параметров будильника. Это окно будет вызываться при нажатии кнопок New и Edit. С этой целью добавьте в проект новую форму, дайте ей идентификатор AlarmDetailsForm, скорректируйте размеры и установите следующие значения свойств:
Caption = Alarm Details
355
BorderStyle = bsDialog
Position = poScreenCenter
Теперь сохраните модуль формы под именем AlarmDetailsUnit.pas.
Шаг 6. Добавьте в форму кнопки OK и Cancel и установите их свойства так, как показано на рисунке 9.20.
Рисунок 9.20. Стандартные кнопки OK и Cancel и их свойства
Шаг 7. Теперь займемся размещением компонентов для ввода данных. Прежде всего подумаем, какие параметры должны устанавливаться в диалоге. К ним относятся: текстовое сообщение, которое появится по сигналу будильника, время сигнала с точностью до минуты, признак того, нужно ли проигрывать звуковой сигнал, периодичность выдачи сигналов (ежедневно, в заданный день недели или в конкретный день). Учли все? Вроде бы, да. Тогда разместите в форме компоненты, обеспечивающие ввод перечисленных параметров (рисунок
9.21).
356
Рисунок 9.21. Эскиз окна для установки параметров будильника
Эскиз окна диалога создан (с помощью выносок на рисунке пояснены названия компонентов). Окинув его взором, вы обнаружите, что знакомых вам компонентов немного
— это Bevel, Label и Button. Зато новых — хоть отбавляй: CheckBox, RadioButton, Edit, MaskEdit, GroupBox, ComboBox, DateTimePicker. Однако не пугайтесь, мы обо всех расскажем, и вы убедитесь, что обращаться с ними вовсе не сложно.
9.3.1. Фокус ввода
Во время работы программы только один из компонентов принимает клавиатурный ввод в
текущий момент времени. Принято говорить, что такой компонент обладает фокусом ввода или просто — активен. Передача фокуса ввода осуществляется щелчками компонентов или нажатием клавиш Tab и Shift+Tab на клавиатуре. При использовании клавиатуры фокус ввода передается последовательно от одного компонента другому, причем клавиша Tab обеспечивает перебор элементов в прямом порядке, а сочетание клавиш Shift+Tab – в обратном.
Очередность, в которой компонент получает фокус ввода, задается его свойством TabOrder. Свойство TabOrder действует относительно содержащего компонента, например очередность перебора компонентов MessageEdit и TimeMaskEdit задается относительно формы, а очередность перебора компонентов WeeklyComboBox и DatePicker — относительно компонента GroupBox.
Если нужно исключить компонент из очереди на фокус ввода, установите свойство TabStop в значение False. Однако в этом случае фокус ввода можно насильно передать компоненту с помощью мыши или «горячей» клавиши.
Изначально порядок перебора соответствует порядку добавления компонентов в форму, но его можно изменить, устанавливая значения свойства TabOrder в компонентах. Если компонентов в окне диалога очень много, то это занятие может стать довольно утомительным. В этом случае удобнее пользоваться окном Edit Tab Order, которое открывается по команде меню Edit | Tab Order... (рисунок 9.22).
Рисунок 9.22. В окне Edit Tab Order выставляется порядок перебора компонентов формы
Шаг 8. В этом окне задайте порядок перебора компонентов формы AlarmDetailsForm таким, как показан на рисунке.
Ну хорошо, скажете вы, допустим, порядок перебора задан. А как управлять передачей фокуса ввода программно? Очень просто. Чтобы передать фокус ввода требуемому
357
компоненту, у него нужно вызвать метод SetFocus. Кстати при управлении фокусом ввода очень полезным может оказаться свойство формы ActiveControl, которое указывает активный компонент. Это свойство доступно в окне свойств и часто используется для указания компонента, который первым получит фокус ввода (в обход номера очереди). Если значение свойства не задано, то первым фокус ввода получает компонент, в котором значение свойства TabOrder равно нулю.
Шаг 9. Хотя окно диалога Alarm Details еще не готово, вам, наверное, не терпится его опробовать и убедиться, что перебор компонентов происходит в нужном порядке. Для этого нужно связать выполнение диалога с нажатием в главной форме кнопки New.... Поэтому подключите модуль AlarmDetails в модуле Main и определите следующий обработчик события OnClick для кнопки NewButton:
procedure TMainForm.NewButtonClick(Sender: TObject); begin
AlarmDetailsForm := TAlarmDetailsForm.Create(Self); try
AlarmDetailsForm.ShowModal; finally
AlarmDetailsForm.Free; end;
end;
Шаг 10. Теперь выполните компиляцию и запустите программу. В окне Clock Alarms нажмите кнопку New... . Вашему взору предстанет окно диалога Alarm Settings (рисунок
9.23).
Рисунок 9.23. Рабочий прототип окна для установки параметров будильника
Диалог запускается, фокус ввода перемещается в нужном порядке, но в целом компоненты работают не так, как надо. Ничего удивительного, ведь мы ими почти не занимались. Поэтому дальше мы приступаем к детальному изучению различных типов компонентов. На этом пути полигоном для испытаний нам послужит окно диалога Alarm Details.
9.3.2. Переключатели
Переключатели (check boxes) используются для установки параметров, характеризуемых двумя значениями – "Да" и "Нет" (True и False). Переключатели создаются с помощью
358
компонента CheckBox, расположенного в палитре компонентов на вкладке Standard (рисунок
9.24).
Рисунок 9.24. Компонент CheckBox
Характерные свойства этого компонента собраны в таблице 9.6.
Свойство Описание
Alignment Определяет, с какой стороны от переключателя находится текст: taRightJustify – справа, taLeftJustify – слева.
AllowGraye Если равно True, то переключатель имеет три состояния. d
Caption Текст рядом с переключателем.
Checked Определяет, включен ли переключатель.
State |
Содержит текущее состояние переключателя. |
WordWrap Если равно значению True, то работает перенос слов.
Таблица 9.6. Важнейшие свойства компонента CheckBox
Обычно переключатель имеет два состояния: включен или выключен. Текущее состояние определяется значением свойства Checked. Если оно равно значению True, то переключатель включен, иначе — выключен. Бывает, что переключатель имеет еще и третье состояние — неопределенное (grayed). В этом состоянии переключатель закрашивается серым цветом. Если переключатель имеет три состояния, то вместо свойства Checked используется свойство State, а в свойстве AllowGrayed (разрешает неопределенное состояние) устанавливается значение True.
Когда при работе программы пользователь щелкает переключатель, в нем изменяются значения свойств Checked и State, а также происходит событие OnClick. Обрабатывая это событие, можно установить любую зависимость между состоянием переключателя и состоянием других компонентов.
В нашем примере компонент CheckBox используется для установки параметра Play Sound, управляющего выдачей звукового сигнала (рисунок 9.25). Мы назвали его SoundCheckBox.
Рисунок 9.25. Переключатель Play Sound представлен компонентом CheckBox
Шаг 11. Чтобы при первом появлении окна диалога, режим Play Sound был включен, установите в компоненте SoundCheck свойство Checked в значение True.
359
9.3.3. Взаимоисключающие переключатели
Взаимоисключающие переключатели (radio buttons) служат для установки взаимоисключающих параметров. Они обычно объединяются в группы и позволяют пользователю выбрать одно значение из фиксированного (причем немногочисленного) набора вариантов. При включении одного такого переключателя остальные переключатели этой же группы выключаются.
Группа переключателей создается с помощью нескольких компонентов RadioButton. Компонент RadioButton находится в палитре компонентов на вкладке Standard (рисунок
9.26).
Рисунок 9.26. Компонент RadioButton
Характерные свойства компонента RadioButton описаны в таблице 9.7.
Свойство Описание
Alignment Определяет, с какой стороны от переключателя находится текст: taRightJustify — справа, taLeftJustify — слева.
Caption Текст рядом с переключателем.
Checked Определяет, включен ли переключатель.
WordWra Если равно значению True, то работает перенос слов. p
Таблица 9.7. Важнейшие свойства компонента RadioButton
В форму всегда помещаются несколько компонентов RadioButton, соответствующих возможным значениям устанавливаемого параметра. Например, в форме AlarmDetailsForm
содержится три таких компонента (EverydayRadioButton, WeeklyRadioButton и DateRadioButton), которые используются для выбора периодичности срабатываний будильника (рисунок 9.27).
Рисунок 9.27. Переключатели Everyday, Weekly и Date представлены компонентами
RadioButton
Внимание! Выбор положения переключателя осуществляется с помощью клавиш со стрелками.
360
