Типы форм в приложении и их взаимодействие

реклама
Модуль_5. Типы форм в приложении и их взаимодействие.
1. Понятие формы
Форма — это главный компонент приложения, который, как и менее значительные
компоненты, имеет свойства. При создании новой формы среда Delphi сама задает начальные
значения свойствам формы, но их можно изменить. Это можно сделать во время
проектирования формы (в окне свойств) или во время выполнения приложения (с помощью
операторов языка Delphi).
Создадим новое приложение.
Выберите в меню команду File | New | Application. Среда Delphi автоматически создаст в
новом проекте чистую форму и поместит ее исходный текст в редактор кода (рисунок).
Рисунок. Форма на экране и ее описание в редакторе кода
Сразу сохраните проект и его форму, чтобы дать им осмысленные имена. Выберите в
меню команду File | Save All и дайте модулю имя Main.pas, а проекту — имя FormTest.dpr.
2. Имя и заголовок формы
Главное свойство, с которого начинается настройка формы, — это свойство Name —
имя. Оно содержит идентификатор, используемый для обращения к форме из программы
(рисунок). Первой же форме нового проекта автоматически назначается имя Form1.
Оптимальнее всегда его изменять, чтобы имя формы отражало ее роль в приложении.
Например, главную форму приложения можно назвать MainForm.
Рисунок. Программный идентификатор формы
Каждая форма приложения должна иметь понятный заголовок, говорящий
пользователю о ее назначении. Заголовок задается в свойстве Caption. Дадим заголовок
Main, говорящий о том, что это просто главная форма (рисунок).
Рисунок. Заголовок формы
1
3. Стиль формы
Настраивая форму, нужно принимать во внимание, какой пользовательский
интерфейс будет иметь приложение: многодокументный интерфейс MDI (от англ. Multiple
Document Interface) или обычный одно-документный интерфейс SDI (от англ. Single
Document Interface). За это отвечает свойство формы FormStyle, которое может принимать
следующие значения:
• fsMDIChild — дочернее окно MDI-приложения;
• fsMDIForm — главное окно MDI-приложения;
• fsNormal — обычное окно (значение по умолчанию);
• fsStayOnTop — окно, всегда расположенное поверх других окон на экране.
Многие приложения имеют пользовательский интерфейс MDI. Они состоят из
основного окна, которое включает одно или несколько внутренних окон. Внутренние окна
ограничены областью основного окна и не могут выходить за его границы. Для главной
формы, соответствующей основному окну MDI-приложения, значение свойства FormStyle
должно быть равно fsMDIForm. Для всех второстепенных форм, соответствующих
внутренним окнам, значение свойства FormStyle равно fsMDIChild. Для окон диалога,
выполняющихся в монопольном режиме, свойство FormStyle равно значению fsNormal, что
дает возможность выносить их за пределы основной формы.
Если программа имеет пользовательский интерфейс SDI, то каждая форма существует
в виде отдельного независимого окна. Одно из окон является главным, однако оно не
содержит другие окна. В SDI-приложении значение свойства FormStyle равно fsNormal и для
главной формы, и для второстепенных форм. В некоторых случаях допускается установка
значения fsStayOnTop для того, чтобы форма всегда отображалось поверх других форм.
4. Размеры и местоположение формы на экране
Теперь определимся с размерами формы и ее местоположением на экране. Установить
размеры и положение формы проще всего во время проектирования с помощью мыши.
Другой способ — обратиться к окну свойств и задать размеры формы с помощью свойств
Width и Height, а местоположение — с помощью свойств Left и Top (значения задаются в
пикселах). Смысл свойств поясняет рисунок.
Рисунок. Размеры и местоположение формы на экране
Кроме того, с помощью свойства Position можно организовать автоматическое
размещение формы на экране, выбрав одно из следующих возможных значений:
• poDefault — размеры и положение формы подбираются автоматически исходя из
размеров экрана.
• poDefaultPosOnly — положение формы подбирается автоматически, а ширина и
высота определяются значениями свойств Width и Height соответственно.
• poDefaultSizeOnly
— размеры формы устанавливаются автоматически, а
местоположение определяется значениями свойств Left и Top.
2
poDesigned — размеры и положение формы определяются значениями свойств Left,
Top, Width, Height.
• poDesktopCenter — форма размещается в центре рабочего стола (т.е. экрана, из
которого исключена панель задач). Размеры формы определяются значениями свойств
Width и Height.
• poMainFormCenter — форма центрируется относительно главной формы. Размеры
формы определяются значениями свойств Width и Height.
• poOwnerFormCenter — форма центрируется относительно формы-владельца. Размеры
формы определяются значениями свойств Width и Height.
• poScreenCenter — форма размещается в центре экрана. Размеры формы определяются
значениями свойств Width и Height.
Иногда размеры формы рассчитываются исходя из размеров ее внутренней рабочей
области (client area), на которой размещаются компоненты. Как известно, в рабочую область
не входят рамка и заголовок. Размеры рабочей области хранятся в свойствах ClientWidth и
ClientHeight. При их установке значения свойств Width и Height автоматически
пересчитываются (и наоборот).
Бывает, что при выборе размеров формы учитываются размеры экрана. Поскольку
современные видео-адаптеры поддерживают множество режимов с различными
разрешениями, встает вопрос: как обеспечить одинаковую пропорцию между формой и
экраном независимо от разрешающей способности дисплея. На этот случай в форме
предусмотрено свойство Scaled. Если оно установлено в значение True, то форма будет
автоматически масштабироваться в зависимости от разрешающей способности дисплея.
При перемещении по экрану, форма может слегка прилипать к краям экрана, если
края формы находятся в непосредственной близости от них. Это происходит в том случае,
если свойство ScreenSnap содержит значение True. Расстояние формы до краев экрана, при
котором форма прилипает, задается в свойстве SnapBuffer и измеряется в пикселях.
Работая с приложением, пользователь может свернуть форму или развернуть ее на
всю рабочую область экрана с помощью соответствующих кнопок рамки. Состояние формы
(свернута или развернута) определяется свойством WindowState, которое принимает
следующие значения:
• wsNormal — форма находится в нормальном состоянии (ни свернута, ни развернута
на весь экран);
• wsMinimized — форма свернута;
• wsMaximized — форма развернута на весь экран.
Если при проектировании вы измените значение свойства WindowState на
wsMinimized или wsMaximized, то получите форму, которая при первом появлении будет
автоматически либо свернута в панель задач, либо развернута на весь экран.
На компьютере с двумя и более мониторами существует возможность выбрать для
формы монитор, на котором она отображается. Для этого следует установить свойство
DefaultMonitor в одно из следующих значений:
• dmDesktop — форма отображается на текущем мониторе; никаких попыток
разместить форму на каком-то конкретном мониторе не делается;
• dmPrimary — форма отображается на первом мониторе в списке Monitors объекта
Screen;
• dmMainForm — форма отображается на том мониторе, на котором находится главная
форма;
• dmActiveForm — форма отображается на том мониторе, на котором находится
активная в данный момент форма.
Свойство DefaultMonitor учитывается лишь в том случае, если в программе
существует главная форма.
5. Цвет рабочей области формы
•
3
Изменение стандартного цвета фона формы происходит с помощью свойства Color.
Для этого следует обратиться к окну свойств. Перейдите к свойству Color, откройте
выпадающий список, и выберите любой цвет из набора базовых цветов. Базовые цвета
представлены в списке именованными константами. Вы можете также выбрать цвет из всей
цветовой палитры, выполнив двойной щелчок мыши в поле значения свойства. На экране
появится стандартное диалоговое окно выбора цвета.
Рисунок. Стандартное диалоговое окно выбора цвета
Когда вы установите цвет в окне свойств, изменение немедленно отразится на форме.
Можно работать с самыми разными цветами, но хорошим тоном считается использовать
стандартную цветовую гамму. Поэтому лучшее значение для свойства Color — clBtnFace
(цвет такой, как у кнопок).
6. Рамка формы
Во внешнем виде формы очень важную роль играет рамка и расположенные на ней
кнопки "Свернуть", "Развернуть", "Закрыть" (рисунок). Стиль рамки задается с помощью
свойства BorderStyle, которое может принимать следующие значения:
• bsNone — у окна вообще нет ни рамки, ни заголовка;
• bsDialog — неизменяемая в размерах рамка, свойственная диалоговым окнам;
• bsSingle — неизменяемая в размерах рамка для обычного окна;
• bsSizeable — изменяемая в размерах рамка для обычного окна;
• bsToolWindow — аналогично значению bsSingle, но окно имеет слегка уменьшенный
заголовок, что свидетельствует о его служебном назначении;
• bsSizeToolWin — аналогично значению bsSizeable, но окно имеет слегка
уменьшенный заголовок, что свидетельствует о его служебном назначении.
Обычно свойство BorderStyle имеет значение bsSizeable. В этом случае форма имеет
стандартную изменяемую в размерах рамку (как при проектировании), заголовок, меню
управления, кнопки "Свернуть", "Развернуть", "Закрыть" и, иногда, "Справка". Для указания
того, какие именно из этих элементов отображать, используется свойство BorderIcons.
Список его возможных значений следующий:
• biSystemMenu — рамка формы содержит меню управления, которое вызывается
щелчком правой кнопки мыши по заголовку формы;
• biMinimize — рамка формы имеет кнопку "Свернуть";
• biMaximize — рамка формы имеет кнопку "Развернуть";
• biHelp — рамка формы имеет кнопку "Справка". При нажатии кнопки "Справка",
курсор мыши превращается в стрелку со знаком вопроса. Выбирая таким курсором
нужный элемент формы, пользователь получает по нему справку во всплывающем
окне.
Рисунок. Рамка формы и ее контекстное меню
4
7. Значок формы
Если разрабатывается коммерческое приложение, а не тестовый пример, следует
позаботиться о том, чтобы форма имела в своем левом верхнем углу собственный значок.
Для разработки значков существует множество средств, на которых мы не будем
останавливаться. Когда значок готов и сохранен в файле, его нужно просто установить в
качестве значения свойства Icon (рисунок).
Рисунок. Установка значка формы
Для этого откройте окно Picture Editor нажатием кнопки с многоточием (рисунок).
Нажмите кнопку Load... и выберите какой-нибудь файл из стандартной коллекции значков
(как правило, каталог C:\Program Files\Common Files\Borland Shared\Images). После этого
закройте диалоговое окно с помощью кнопки OK.
Рисунок. Окно выбора значка для формы
Среда Delphi сразу же подставит выбранный значок в левый верхний угол формы
(рисунок).
Рисунок. Новый значок формы
8. Невидимая форма
Сценарий решения задачи может потребовать, чтобы в некоторый момент форма
стала невидимой, т.е. исчезла с экрана. За "видимость" формы отвечает булевское свойство
Visible. Установка ему значения False скроет форму, а установка значения True покажет ее.
9. Прозрачная форма
Некоторые части формы можно сделать прозрачными (рисунок). Причем щелчок
мыши по прозрачной области формы будет приводить к активизации окон (форм),
находящихся за формой. Это достигается установкой свойства TransparentColor в значение
True и выбором цвета прозрачности в свойстве TransparentColorValue. Все пиксели формы
с цветом TransparentColorValue будут прозрачными.
5
Рисунок. Прозрачная форма
Например, рисунок был получен следующим образом. Мы положили на форму
компонент Shape, превратили его в эллипс (Shape = stEllipse), растянули до размеров формы
(Align = alClient), в форме установили свойство TransparentColor в значение True и
уравняли в форме значение свойства TransparentColorValue со свойством Brush.Color
компонента Shape. После сборки и запуска программы получили "дырявую" форму.
10. Полупрозрачная форма
Форма может быть полупрозрачной (рисунок). За полупрозрачность формы отвечают
свойства AlphaBlend и AlphaBlendValue. Первое свойство включает и выключает эффект
полупрозрачности, а второе определяет силу прозрачности.
Рисунок. Полупрозрачная форма
Например, рисунок был получен следующим образом. Мы положили на форму
компонент Image, загрузили в него картинку (свойство Picture), затем в форме установили
свойство AlphaBlend в значение True и свойство AlphaBlendValue — в значение 150. После
сборки и запуска программы получили эффект полупрозрачности.
11. Недоступная форма
Иногда бывает нужно просто запретить доступ к форме, не убирая ее с экрана. Для
этого служит другое булевское свойство Enabled. Обычно оно равно значению True, но
стоит ему присвоить противоположное значение, и после запуска приложения вы не сможете
сделать форму активной.
Все описанные выше свойства доступны не только в окне свойств, но и в редакторе
кода, т.е. в тексте программы. При работе с формой на уровне исходного кода вы также
получаете доступ к некоторым дополнительным свойствам, которые не видны в окне
свойств.
12. События формы
OnCreate — происходит сразу после создания формы. Обработчик этого события может
установить начальные значения для свойств формы и ее компонентов, запросить у
операционной системы необходимые ресурсы, создать служебные объекты, а также
выполнить другие действия прежде, чем пользователь начнет работу с формой. Парным для
события OnCreate является событие OnDestroy.
OnDestroy — происходит непосредственно перед уничтожением формы. Обработчик
этого события может освободить ресурсы, разрушить служебные объекты, а также
выполнить другие действия прежде, чем объект формы будет разрушен.
OnShow — происходит непосредственно перед отображением формы на экране. Парным
для события OnShow является событие OnHide.
6
OnHide — происходит непосредственно перед исчезновением формы с экрана. Парным
для события OnHide является событие OnShow.
OnActivate — происходит, когда пользователь переключается на форму, т.е. форма
становится активной. Парным для события OnActivate является событие OnDeactivate.
OnDeactivate — происходит, когда пользователь переключается на другую форму, т.е.
текущая форма становится неактивной. Парным для события OnDeactivate является
OnActivate.
OnCloseQuery — происходит при попытке закрыть форму. Запрос на закрытие формы
может исходить от пользователя, который нажал на рамке формы кнопку "Закрыть", или от
программы, которая вызвала у формы метод Close. Обработчику события OnCloseQuery
передается по ссылке булевский параметр CanClose, разрешающий или запрещающий
действительное закрытие формы.
OnClose — происходит после события OnCloseQuery, непосредственно перед закрытием
формы.
OnContextPopup — происходит при вызове контекстного меню формы.
OnMouseDown — происходит при нажатии пользователем кнопки мыши, когда
указатель мыши наведен на форму. После отпускания кнопки мыши в компоненте
происходит событие OnMouseUp. При перемещении указателя мыши над формой
периодически возникает событие OnMouseMove, что позволяет отслеживать позицию
указателя.
OnMouseWheelUp — происходит, когда колесико мыши проворачивается вперед (от
себя).
OnMouseWheelDown — происходит, когда колесико мыши проворачивается назад (на
себя).
OnMouseWheel — происходит, когда колесико мыши проворачивается в любую из
сторон.
OnStartDock — происходит, когда пользователь начинает буксировать стыкуемый
компонент.
OnGetSiteInfo — происходит, когда стыкуемый компонент запрашивает место для
стыковки.
OnDockOver — периодически происходит при буксировке стыкуемого компонента над
формой.
OnDockDrop — происходит при стыковке компонента (см. гл. 10).
OnEndDock — происходит по окончании стыковки компонента.
OnUnDock — происходит, когда пользователь пытается отстыковать компонент.
OnDragDrop — происходит, когда пользователь опускает в форму буксируемый объект.
OnDragOver — периодически происходит при буксировке объекта над формой.
OnCanResize — происходит при попытке изменить размеры формы. Запрос на
изменение размеров может исходить от пользователя. Обработчику события OnCanResize
передается по ссылке булевский параметр Resize, разрешающий или запрещающий
действительное изменение размеров формы.
OnResize — происходит при изменении размеров формы.
OnConstrainedResize — происходит при изменении размеров формы и позволяет на лету
изменять минимальные и максимальные размеры формы.
OnShortCut — происходит, когда пользователь нажимает клавишу на клавиатуре (до
события OnKeyDown). Позволяет перехватывать нажатия клавиш еще до того, как они
дойдут до стандартного обработчика формы.
13. Несколько форм в приложении
Рассмотрим, как добавить в проект новую форму, выбрать главную форму
приложения, переключаться между формами
13.1. Добавление новой формы в проект
7
Добавить в проект новую форму: выберите команду меню File | New | Form и на
экране сразу появиться вторая форма. При этом в окне редактора кода автоматически
появится соответствующий новой форме программный модуль. Только что созданной форме
дайте имя SecondaryForm (свойство Name) и заголовок Secondary (свойство Caption) —
рисунок.
Рисунок. Две формы в проекте
Сохраните модуль с новой формой под именем Second.pas.
13.2. Добавление новой формы из Хранилища Объектов
Существует и второй способ создания форм. Он основан на использовании готовых
форм, существующих в Хранилище Объектов среды Delphi. Хранилище Объектов (Object
Repository) содержит заготовки форм, программных модулей и целых проектов, которые
можно либо скопировать в свой проект, либо унаследовать, либо вообще использовать
напрямую. Чтобы взять новую форму из Хранилища объектов, выберите в меню команду
File | New | Other.... Среда Delphi откроет окно, показанное на рисунке:
Рисунок. Окно создания новой формы или другого элемента проекта
Если на вкладке New диалогового окна выбрать значок с подписью Form, то в проект
добавится обычная пустая форма, как по команде меню File | New Form. Если интересуют
формы с "начинкой", обратитесь к вкладкам Forms и Dialogs (рисунок).
Рисунок. Быстрое создание формы с "начинкой"
На вкладках Forms и Dialogs существует переключатель, указывающий, что нужно
сделать с формой-заготовкой: копировать (Copy), наследовать (Inherit) или использовать
(Use). Отличие между ними состоит в следующем:
8
Copy — означает, что в проект помещается полная копия формы-заготовки.
Inherit — означает, что добавляемая в проект форма создается методом наследования
от формы-заготовки, находящейся в Хранилище Объектов;
• Use — означает, что в проект добавляется сама форма-заготовка; изменение формы в
проекте означает изменение формы-заготовки в Хранилище Объектов.
Какой из режимов использовать — зависит от условия задачи. Режим Copy хорош
просто тем, что не с нуля начинает разработку новой формы. Режим Inherit полезен, когда в
проекте существует несколько форм, у которых совпадают некоторые части. В этом случае
все похожие между собой формы порождаются от какой-то одной формы, реализующей
общую для всех наследников часть. Режим Use позволяет подкорректировать формузаготовку прямо в Хранилище Объектов.
13.3. Переключение между формами во время проектирования
Для просмотра списка всех форм и их переключения необходимо открыть окно View
Form, для вызова которого служит команда меню View | Forms... (рисунок).
•
•
Рисунок. Окно для переключения на другую форму
Выберите в этом окне форму, с которой собираетесь работать, и щелкните по кнопке
OK. Выбранная форма сразу же станет активной.
14. Выбор главной формы приложения
Когда в проекте несколько форм, возникает вопрос: какая из них главная. Следует
обратиться к диалоговому окну Project Options и посмотреть на вкладке Forms, какая форма
выбрана в выпадающем списке Main form (рисунок).
Рисунок. Главная форма в проекте записана в поле Main form
Выбрана форма MainForm, которая была добавлена в проект первой (среда Delphi
создает ее автоматически при создании нового проекта). Можно выбрать другую форму — и
тогда она будет отображаться при запуске приложения. В данном случае этого делать не
надо, поскольку главная форма уже установлена правильно.
15. Вызов формы из программы
После загрузки приложения отображается только главная форма. Остальные формы
хотя и создаются вслед за ней автоматически, на экране сразу не показываются, а ждут пока
их вызовут. Форму можно вызвать для работы двумя разными способами:
9
вызвать для работы в обычном режиме с помощью метода Show. В этом режиме
пользователь может работать одновременно с несколькими формами, переключаясь
между ними;
• вызвать для работы в монопольном режиме с помощью метода ShowModal. В этом
режиме пользователь не может переключиться на другую форму, пока не завершит
работу с данной формой;
Покажем, как реализуются эти способы на примере вызова формы SecondaryForm из
формы MainForm.
Чтобы форма SecondaryForm была доступна для использования формой MainForm,
необходимо подключить модуль формы SecondaryForm к модулю формы MainForm.
1. Активизируйте форму MainForm и выберите в главном меню команду File | Use
Unit.... В появившемся диалоговом окне выберите модуль Second (так называется модуль
формы SecondaryForm) и нажмите кнопку OK (рисунок).
•
Рисунок. Окно для выбора подключаемого модуля
На экране не произойдет видимых изменений, но в секции implementation
программного модуля Main добавится строка
uses Second;
Теперь обеспечим вызов формы SecondaryForm из формы MainForm. В большинстве
случаев формы вызываются при нажатии некоторой кнопки. Добавим такую кнопку на
форму MainForm.
2. Отыщите в палитре компонентов на вкладке Standard значок с подсказкой Button,
щелкните по нему, а затем щелкните по форме MainForm. На форме будет создана кнопка
Button1 и в окне свойств отобразится список ее свойств. Перейдите к свойству Caption и
замените текст Button1 на текст Secondary (рисунок).
Рисунок. Текст на кнопке записывается в свойстве Caption
Чтобы при нажатии кнопки отображалась форма SecondaryForm, необходимо для
этой кнопки определить обработчик события OnClick.
3. Активизируйте в окне свойств вкладку Events и сделайте двойной щелчок в поле
события OnClick. Среда Delphi определит для кнопки обработчик события, поместив
программную заготовку в исходный текст модуля Main. Вставьте в тело обработчика
оператор SecondaryForm.Show, в результате метод обработки события примет следующий
вид:
10
procedure TMainForm.Button1Click(Sender: TObject);
begin
SecondaryForm.Show;
end;
4. Выполните компиляцию и запустите приложение. Когда на экране покажется форма
MainForm, нажмите кнопку Secondary. На экране покажется еще одна форма —
SecondaryForm. Вы можете произвольно активизировать любую из двух форм (рисунок).
Рисунок. Приложение с двумя формами на экране
Таким образом, при использовании метода Show пользователь может работать
одновременно с несколькими формами, переключаясь между ними.
Форма MainForm является главной, а форма SecondaryForm — второстепенной.
Если вы закроете форму MainForm, то форма SecondaryForm тоже закроется, и приложение
завершится. Если же вы закроете форму SecondaryForm, то форма MainForm на экране
останется.
Ситуация, когда пользователю предлагается для работы сразу несколько доступных
форм, встречается редко. Поэтому для показа формы в основном применяется метод
ShowModal. Он обеспечивает работу формы в монопольном режиме, не возвращая
управление до тех пор, пока пользователь не закроет форму.
5. Посмотрим, что произойдет, если в предыдущем примере заменить вызов метода Show
на ShowModal.
procedure TMainForm.Button1Click(Sender: TObject);
begin
SecondaryForm.ShowModal;
end;
6. После компиляции и запуска приложения нажмите на форме MainForm кнопку
Secondary. После появления формы SecondaryForm попробуйте активизировать форму
MainForm. У вас ничего не выйдет, поскольку на этот раз форма SecondaryForm
отображается в монопольном режиме (рисунок).
Рисунок. Вторая форма работает в монопольном режиме
Только закрыв форму SecondaryForm, вы вернетесь к форме MainForm. Теперь
понятно и назначение метода ShowModal. С его помощью организуется пошаговый
(диалоговый) режим взаимодействия с пользователем.
11
Форма является основным «строительным блоком». Любая программа имеет как
минимум одну связанную с пен форму, которая называется главной, — эта форма появляется
на экране в момент старта программы. Однако программа может иметь сколько угодно форм,
каждая из которых может решать ту или иную локальную задачу и появляться на экране по
мере надобности.
Разновидности форм
Разновидности форм определяются значениями их свойства TFormStyle, а также
разнообразием форм-заготовок в хранилище объектов. Стиль формы задается одним из
значений следующего свойства:
TFormStyle = (fsNormal, fsMDIChild, fsMDIForm, fsStayOnTop) ;
property FormStyle: TFormStyle;
Стиль fsNormal определяет обычную форму, использующуюся для решения самых
разных задач, в том числе для общего управления всей программой (главная форма).
Стили fsMDIChild и fsMDIForm используются при создании так называемых
многодокументных приложений в стиле MDI (Multi Document Interface). Этот немодный
сегодня стиль предполагает создание главного окна MDI (его обычно называют рамочным),
внутри которого по мере надобности появляются дочерние окна. Дочерние окна, подобно
дочерним элементам контейнера, не могут выходить за границы своего владельца —
рамочного окна. В MDI-приложениях есть специальные средства управления
взаимодействием рамочного окна с дочерними окнами. Например, каждое дочернее окно в
момент активизации может нужным образом настроить главное меню рамочного окна
(дочерние MDI-окна не имеют собственного главного меню). В Delphi для создания
рамочного окна используется стиль fsMDIForm, а для создания дочернего MDI-окна - стиль
fsMDIChild.
Стиль FormStyle предназначен для окон, которые всегда должны располагаться над
всеми другими окнами программы («окно-поплавок» или «всплывающее окно»). В момент
активизации окна оно обычно становится видимым на экране, даже если перед этим его
загораживали другие раскрытые окна. Стиль fsStayOnTop препятствует перекрытию окна
другими окнами, даже если оно становится неактивным и теряет фокус ввода (так сказано в
документации, однако на самом деле это не так). Понятно, что этот стиль используется в
исключительных случаях, когда окно содержит что-то, требующее повышенного внимания
пользователя.
Как показывает практика, объявление окна со стилевым признаком fsStayOnTop еще
не решает проблему создания всплывающего окна, то есть окна, которое невозможно
перекрыть другими окнами. Более того, несложные эксперименты убедят вас. что этот
признак вообще не играет никакой роли! Чтобы создать всплывающее окно, нужно
обратиться к АРI-функции SetWindowPos. Например:
SetWindowPos(fmAlarmForm.Handle, hwnd_TopMost, 300, 300, 250, 70, swp_noActivate)
Первым параметром обращения к функции является дескриптор окна, которое должно
стать всплывающим. Дескриптор формы содержится в ее свойстве Handle, поэтому для
формы fmAlarmForm параметр вызова имеет вид fmAlarmForm.Handle. Второй параметр
определяет расположение окна относительно других окон в так называемом Z-порядке их
расположения. Константа hwnd_TopMost указывает, что окно должно стать самым верхним и
впредь до его закрытия не может перекрываться другими (обычными) окнами. Четыре
следующие параметра определяют координаты левого верхнего угла окна, его ширину и
высоту. Все параметры указываются в пикселах, координаты угла задаются относительно
левого верхнего угла экрана. Последним указывается один или несколько битовых флагов,
уточняющих поведение окна. В нашем примере использован флаг swp_noActivate,
означающий, что окно не получает фокуса ввода в момент своего появления на экране. На
практике часто используются всплывающие окна, чтобы сообщить пользователю, например,
о необходимости обновить набор данных, которые он видит в настоящий момент, так как эти
данные были изменены другими пользователями клиент-серверной базы данных. Такое окно,
12
в отличие от модальною окна, не должно отнимать активность (фокус ввода) у окна, с
которым работает пользователь.
И последнее замечание. Всплывающим окном может стать и обычное окно (со
значением стиля FormStyle = fsNormal). Однако всплывающее окно действительно появится
на экране, только если в его свойстве Visible содержится значение True. Иными словами,
если пользователь закроет такое окно, оно не появится в результате вызова функции
SetWindowPos — его предварительно нужно сделать видимым методом Show. Поскольку
всплывающее окно может вызываться в разных местах программы, удобно поместить вызов
функции SetWindowPos в его обработчик события OnActivate. Однако, если вы попытаетесь
создать такой обработчик для окна со стилем FormStyle = FormStyle, то компилятор выдаст
сообщение об ошибке и поместит заготовку метода в тексте модуля после ограничителяточки (.). В этом случае определяйте окно со стилем fsNormal.
Современные многооконные приложения чаще всего строятся в стиле SDI (Single
Document Interface). который в противоположность интерфейсу MDI не накладывает
ограничений на положение и размеры вспомогательных форм, каждая из которых при
необходимости может иметь свое главное меню (в стиле SDI реализована, например, среда
Delphi). Для создания форм в этом случае используется стиль fsNormal. В рамках SDIприложений могут использоваться рамочные MDI-формы со своими дочерними окнами, так
что термин SDI носит весьма условный характер и применяется в основном для
противопоставления термину MDI.
В хранилище объектов Delphi хранится множество стандартных форм-заготовок.
предназначенных для решения конкретных задач (доступ к хранилищу объектов открывает
команда File - New - Other). Помимо универсальной пустой формы Form (вкладка New
хранилища объектов) хранилище содержит специализированные формы, некоторые из
которых перечислены в табл.
Таблица. Специализированные формы в хранилище объектов
Название
About box
Dual list box
Вкладка
Forms
Forms
Quick Report Labels
Forms
Quick Report List
Forms
Quick Report
Master/Detail
Tabbed Pages
Forms
Forms
Dialog with Help
Dialogs
Password Dialog
Dialogs
Reconcile Error
Dialog
Dialogs
Standard Dialog
Dialogs
Dialog Wizard
Database Form Wizard
Quick Report Wizard
Dialogs
Business
Business
Описание
Окно 0 программе
Диалоговое окно с двумя компонентами List box.
Используется для гибкого управления списками, в
том числе, для перемещения элементов из одного
списка в другой
Используется в приложениях баз данных для печати
наклеек
Используется в приложениях баз данных для
создания обычных отчетов
Используется в приложениях баз данных для
создания отчетов типа главный-детальный
Заготовка для многостраничного диалогового окна
с вкладками и кнопками ОК, Саnсеl и Неlр
Заготовка для диалогового окна с кнопками ОК,
Саnсеl и Неlр. Имеются варианты с вертикальным и
горизонтальным расположением кнопок
Диалоговое окно с однострочным полем TEdit для
ввода паролей, а также кнопками ОК и Саnсеl
Используется в приложениях баз данных для
пояснения обнаруженной ошибки при изменении
таблицы
Заготовка для диалогового окна с кнопками ОК,
Саnсеl. Имеются варианты с вертикальным и
горизонтальным расположением кнопок
Мастер создания диалоговых окон
Мастер создания форм для доступа к базам данных
Мастер создания отчетов для баз данных
13
TeeChart Wizard
Business
Мастер форм для доступа к компоненту Chart
Компонент TForm
Свойства формы представлены в табл.
Свойство
Описание
property Active: Boolean;
Содержит значение True. если окно
активно (имеет фокус ввода)
property ActiveControl:
Определяет дочернин элемент, содержащий фокус ввода
TWinControl;
property ActiveMDIChild: TForm;
Определяет дочернее MDI-окно с фокусом ввода
property AlphaBlend: Boolean;
Если содержит значение True, форма определяет
полупрозрачное окно (только для Windows 2000 и выше)
property AlphaBlendValue: Byte;
Указывает степень прозрачности окна
Определяет наличие кнопок в заголовке окна:
TBorderIcon = (biSystemMenu,
biSystemMenu — кнопка вызова системного меню;
biMinimize, biMaximize, biHelp);
biMinimize — кнопка свертывания; biMaximize — кнопка
TBorderIcons
развертывания; biHelp — кнопка вызова справочной
= set of
службы
TBorderIcon;
property Borderlcons:
TBorderIcons;
TFormBorderStyle = (bsNone,
Определяет стиль рамки окна: bsNone — окно не имеет
bsSingle, bsSizeable, bsDialog,
рамки и заголовка и не может перемешаться и изменять
bsToolWindow, bsSizeToolWin);
свои размеры; bsSingle — рамка толщиной в 1 пиксел,
property BorderStyle:
такое окно не может изменять свои размеры; bsSizeable —
TFormBorderStyle;
обычная рамка; bsDialog — рамка диалогового окна. окно
не может изменять свои размеры; bsToolWindow —
подобно bsSingle, но с уменьшенным по высоте
заголовком; bsSizeToolWin — подобно bsSizeable, по с
уменьшенным по высоте заголовком
Property Canvas: TCanvas;
Канва для прорисовки фона окна. Это свойство могут
использовать неоконные дочерние элементы
property ClientHeight: Integer;
Высота клиентской части окна
property ClientRect: TRect;
Прямоугольник клиентской части окна
property ClientWidth: Integer;
Ширина клиентской части окна
type TDefaultMonitor =
Определяет монитор, на котором появляется форма:
(dmDesktop, dmPrimary,
dmDesktop — для формы неуказан монитор; dmPrimary —
dmMainForm, dmActiveForm);
форма появляется на первом мониторе списка Monitors
property DefaultMonitor:
глобального объекта Screen; dmMainForm — форма
TDefaultMonitor;
появляется на том же мониторе, что и главное окно
программы: dmActiveForm — форма появляется на том же
мониторе, что и текущее активное окно
property DropTarget: Boolean;
Если содержит значение True, форма поддерживает
перетаскивание (Drag&Drop)
property Floating: Boolean ;
Если содержит значение False, окно причалено к другому
окну, в противном случае оно «плавает»
type TFormState = set of
Определяет текущее состояние формы: fsCreating — окно
(fsCreating, fsVisible,
создается; fsVisible — окно видно на экране (это
fsShowing, fsModal,
состояние используется для обновления свойства Visible);
fsCreatedMDIChild, fsActivated) ;
fsShowing — свойство FormState изменяется; fsModal —
property FormState: TFormState;
создано модальное окно; fsCreatedMDIChild — форма
представляет собой рамочное MDI-окно (устанавливается
в момент создания дочернего окна); fsActivated — форма
получила сообщение СМ_АСТIVАТЕ, но еще не возникло
событие OnActivate
type TFormStyle = (fsNormal,
Определяет стиль окна: fsNormal — обычное окно;
fsMDIChild, fsMDIForm,
fsMDIChild - дочернее MDI-окно; fsMDIForm — рамочное
14
fsStayOnTop) ;
property FormStyle: TFormStyle;
property HelpFile: String;
property Icon: TIcon;
property KeyPreview: Boolean;
property MDIChildCount: Integer;
property MDIChildren[N: Integer]:
TForm;
property Menu: TMainMenu;
TModalResult = Low(Integer)..
High(Integer) ;
property ModalResult:
TModalResult;
property Monitor: TMonitor;
property PixelsPerInch: Integer;
TPosition = (poDesigned,
poDefault, poDefaultPosOnly,
poDefaultSizeOnly,
poScreenCenter);
property Position: TPosition;
TPrintScale = (poNone,
poProportional, poPrintToFit);
property PrintScale: TPrintScale;
property Scaled: Boolean;
TileMode = (tbHorizontal,
tbVertical) ;
property TileMode: TTileMode;
property TransparentColor:
Boolean;
property TransparentColorValue:
TColor;
property WindowMenu:
TMenuItem;
TWindowState == (wsNormal,
MDI-окно; fsStayOnTop — всплывающее окно
Каждая форма может иметь индивидуальный файл
помощи, имя которого содержит это свойство. Если имя
не указано, используется файл помощи приложения
Содержит значок окна. Для главной формы это свойство
определяет также значок программы
Если имеет значение True, форма получает события от
клавиатуры, перед тем как они поступят в элемент с
фокусом ввода
В рамочном MDI-окне определяет количество связанных
с ним дочерних MDI-окон
В рамочном MDI-окне открывает доступ к дочернему
окну под номером N
Содержит главное меню окна
Для модального окна содержит результат диалога с
пользователем
Содержит ссылку на монитор, на котором отображается
окно
Определяет разрешающую способность окна в пикселах
на один линейный дюйм для этапа конструирования
формы
Определяет положение и размеры окна в момент его
появления на экране: poDesigned — такие же, как на этапе
конструирования окна; poDefault: — положение и
размеры определяет Windows; poDefaultPosOnly —
положение, как на этапе конструирования, размеры
определяет Windows; poDefaultSizeOnly — размеры, как
на этапе конструирования, положение определяет
Windows poScreenCenter - в центре экрана с размерами,
как на этапе конструирования
Определяет масштабирование окна при его печати на
принтере: poNone — нет масштабирования; каждый
пиксел окна воспроизводится одной точкой на бумаге;
poProportional — форма масштабируется так, чтобы ее
образ на бумаге был максимально похож на се
изображение на экране; poPrintToFit - форма печатается с
такими же пропорциями, как на экране, но с размерами,
заполняющими лист бумаги
Разрешает/запрещает масштабировать форму, если
значение ее свойства PixelPerInch отличается от текущего
разрешения экрана
Определяет стиль расположения дочерних окон MDIприложения при их упорядочении мозаикой
Если содержит значение True, свойство
TransparentColorValue определяет цвет прозрачности
формы, сквозь который будут видны нижележащие окна
(только для Window 2000 и выше)
Содержит цвет прозрачности формы (игнорируется, если
TransparentColor=False)
Определяет пункт главного меню рамочного MDI-окна, к
которому добавляются пункты меню дочернего окна
Определяет состояние окна в момент его появления на
15
wsMinimized, wsMaximized);
property WindowState:
TWindowState;
экране: wsNormal — обычное окно; wsMinimized —
свернуто до кнопки; wsMaximized — развернуто на весь
экран
Два свойства AlphaBlend и AlphaBlendValue впервые введены в версии 6 и позволяют
регулировать степень прозрачности окна формы. Если AlphaBlend = True, то значение
свойства AlphaBlendValue задает степень прозрачности: 0 — окно полностью прозрачно, 255
— окно совершенно непрозрачно. Свойства TransparentColorValue и TransparentColo
определяют цвет прозрачности и возможность его использования. Однако указанные
свойства работают только под управлением Windows 2000/ХР и на процессорах Pentium с
тактовой частотой не ниже 90 МГц.
Результат изменения значения AlphaBlendValue проявляется только в том случае, если
видеокарта компьютера способна отображать больше 256 цветов, то есть использует два
(High Color)) или более (True Color) байта для кодирования цвета одного пиксела. Свойства
TransparentColorValue и TransparentColor игнорируются, если цвет не относится к основной
16-цветной палитре или если свойство AlphaBlend содержит значение True.
Показываемое окно действительно прозрачно — сквозь него видны не только значки
рабочего стола, но на них даже можно щелкать мышью и вызывать программы. После
щелчка на верхней кнопке начинается плавное изменение значения AlphaBlendValue от 255
до 0 и обратно. В результате окно «растворяется» на экране, а затем появляется вновь.
Если в множестве свойства BorderIcon убрать кнопки biMinimize и biMaximize, а в
свойство WindowState поместить значение wsMaximized, форма займет вес пространство
экрана, включая панель задач.
Методы формы перечислены в табл.
Метод
procedure Arrangelcons;
procedure Cascade;
procedure Close;
function CloseQuery: Boolean
procedure DefocusControl
(Control: TWinControl;
Removing: Boolean) ;
procedure CreateParams (var
Params: TCreateParams);
override ;
procedure FocusControl
(Control: TWinControl);
function GetFormImage: TBitmap;
procedure Next;
procedure Hide;
procedure MakeFullyVisible
(AMonitor: TMonitor nil) ;
procedure MouseWheelHandler (var
Message: TMessage); override;
procedure Previous;
procedure Print;
procedure Release;
procedure SendCancelMode
(Sender: TControl) ;
procedure SetFocus;
Описание
Упорядочивает значки закрытых дочерних окон MDIприложения
Располагает дочерние MDI-окна каскадом
Закрывает окно. Для главного окна завершает работу
программы
Возвращает значение Тrue, если можно закрыть окно
Отбирает фокус ввода у дочернего элемента Control. Если при
этом Removing = Тrue. фокус ввода получает форма
Создает структуру Params для указания стилевых признаков
создаваемого окна
Передаст фокус ввода дочернему элементу Control
Содержит текущее изображение окна формы
Делает активным следующее MDI-окно
Скрывает окно
Проверяет, полностью ли умещается форма на мониторе, и.
при необходимости, изменяет ее положение так, чтобы у нее
не было частей на других мониторах
Вызывается автоматически при получении сообщения от
колесика мыши. По умолчанию ничего не делает
Делает активным предыдущее MDI -окно
Печатает окно на принтере
Ожидает окончания обработки всех событий формы и ее
дочерних элементов, после чего удаляет окно и освобождает
всю связанную с ним память
Восстанавливает начальное состояние окна: освобождает
мыть, прекращает прокрутку и закрывает меню
Передаст фокус ввода форме. Форма при этом должна быть
16
function SetFocusedControl
(Control: TWinControl):
Boolean; virtual;
procedure Show;
function ShowModal: Integer;
procedure Tile;
function WantChildKey(Child:
TControl; var Message: TMessage):
Boolean; virtual;
активной и видимой
Передает фокус ввода указанному элементу
Показывает форму в немодальном режиме
Показывает форму в модальном режиме и возвращает
результат диалога с пользователем
Располагает дочерние MDI-окна мозаикой
Этот метод вызывается любым размещенным па форме
компонентом в момент, когда он получает фокус ввода. Если
функция возвращает значение True, весь клавиатурный ввод
переназначается форме. По умолчанию возвращает значение
False
Структура Params в методе CreateParams описывается следующим типом:
type
TCreateParams = record
Caption: PChar;
Style: DWORD;
ExStyle: DWORD;
X, Y: Integer;
Width, Height: Integer;
WndParent: HWND;
Param: Pointer;
//Заголовок окна
// Стилевые флаги
// Дополнительные стилевые флаги
// Координаты левого верхнего угла
// Размеры
// Дескриптор владельца
// Указатель на параметры
// для сообщения
WindowClass: TWndClass;
// Класс окна
WinClassName: array[0..63] of Char; // Имя оконного класса
end;
Этот метод следует перекрыть, если вы хотите создать окно нестандартного типа.
Например, набор возможных значений свойства BorderStyle не предполагает создания окна с
«толстой» рамкой, но без заголовка. Однако если в свойство Params.Style поместить значение
WS_THICKFRAME or WS_POPUP, такое окно будет создано. В проекте создается окно без
заголовка, которое, тем не менее, можно перетаскивать мышью:
unit Unit1;
interface
uses
SysUtils, Windows, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls, Buttons;
type
TFormI = class(TForm)
BitBtnl: TBitBtn;
private
{ Private declarations }
protected
// Перехват сообщения WM__NCHITTEST для перемещения
// окна без заголовка:
procedure WMNCHitTest(var Message: TWMNCHitTest);
message WM_NCHITTEST;
public
{ Public declarations )
procedure CreateParams(var Params: TCreateParams);
override;
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
17
procedure TForm1.WMNCHitTest(var Message: TWMNCHitTest);
begin
// Результат HTCAPTION означает, что указатель мыши
// находится над заголовком. Это заставит Windows
// перемещать окно:
Message.Result := HTCAPTION;
end;
procedure TFormI.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
// Окно с рамкой (WS_THICKFRAME) , но без заголовка
// (WS_ POPUP) :
Params.Style := WS_THICKFRAME or WS_POPUP;
end;
end.
Сообщение WM_NCHITTEST посылает Windows в момент создания окна при любом
изменении его нерабочей области (заголовка, рамки, полос прокрутки и т. п.), а также при
перемещении на нем указателя мыши. Обычно программы его не обрабатывают, но в нашем
случае обработчик этого события «обманывает» Windows и сообщает операционной системе,
что указатель перемещается на области заголовка.
События формы перечислены в табл.
Событие
property OnActivate: TNotifyEvent;
type TCanResizeEvent = procedure
(Sender: TObject; var NewWidth,
NewHeight: Integer; var Resize:
Boolean) of object;
property OnCanResize:
TCanResizeEvent;
TCloseAction = (caNone, caHide,
caFree, caMinimize);
TCloseEvent = procedure (Sender:
TObject; var Action:
TCloseAction) of objects; property
OnClose: CloseEvent;
TCloseQueryEvent = procedure
(Sender: TObject; var CanClose:
Boolean) of object;
property OnCloseQuery:
TCloseQueryEvent;
property OnDblClick: TNotifyEvent;
Описание
Возникает в момент активизации окна (при получении им
фокуса ввода)
Возникает при изменении размеров окна. Обработчик может
указать новые размеры или запретить их изменение, поместив
в свойство Resize значение False
Возникает перед закрытием окна. Параметр Action уточняет
необходимые действия: caNone — не закрывать окно; caHide
— спрятать окно; caFree — удалить окно: caMinimize —
свернуть окно
Возникает перед закрытием окна. В параметре CanClose
обработчик сообщает о возможности закрытия окна
Возникает при двойном щелчке на любом расположенном на
форме компоненте
property OnDeactivate:
Возникает при передаче активности (фокуса ввода) другому
TNotifyEvent;
окну
property OnDestroy: NotifyEvent;
Возникает перед удалением окна
property OnHide: NotifyEvent;
Возникает перед исчезновением окна
property OnPaint: NotifyEvent;
Возникает при необходимости прорисовки окна
property OnResize: NotifyEvent
Возникает при изменении размеров окна
TShortCutEvent = procedure (var Возникает до события OnKeyDown и предназначено для
перекрытия стандартной обработки нажатия клавиш быстрого
Msg: TWMKey; var Handled:
вызова
Boolean) of object;
property OnShortCut:
TShortCutEvent;
property OnShow: TNotifyEvent;
Возникает при появлении окна на экране
18
Создание и использование форм
Для подключения новой формы к проекту достаточно обратиться к хранилищу
объектов и выбрать нужную разновидность формы. Менеджер проекта автоматически
подключает новую форму к списку используемых форм и обеспечивает все необходимые
действия по ее инициализации. Самая первая подключенная к проекту форма (стандартное
имя формы — Form1) становится главным окном программы. Окно этой формы
автоматически появляется па экране в момент старта программы. Впрочем, программист
может указать любую форму, окно которой станет главным. Для этого нужно обратиться к
команде Project - Options, в открывшемся окне перейти на вкладку Forms и в списке Main
Form выбрать нужную форму.
Каждое следующее окно становится видимым только после обращения к его методу
Show или ShowModal. Чтобы обратиться к этим методам, нужно сослаться на объект-окно,
который автоматически объявляется в интерфейсном разделе связанного с окном модуля.
Для этого, в свою очередь, главное окно должно знать о существовании другого окна, что
достигается ссылкой на модуль окна в предложении Uses. Если, например, в ходе
выполнения одного из методов главного окна программист захочет вызвать окно с именем
fmForm, связанное с модулем FormUnit, он должен сослаться на этот модуль в предложении
Uses главного окна:
implementation
Uses FormUnit;
После этого можно вызвать окно на экран, добавив в программу один из следующих
операторов:
fmForm.Show;
fmForm.ShowModal;
Delphi автоматизирует вставку ссылки на модуль в предложение Uses. Для этого на
этапе разработки нужно активизировать главное окно, щелкнув на нем мышью, после чего
обратиться к команде File - Uses Unit.. В появившемся диалоговом окне нужно выбрать
модуль и щелкнуть на кнопке ОК. Вставляется ссылка в предложение, стоящее за
зарезервированным словом Implementation, так как обычно главное окно в своей
интерфейсной части не ссылается на элементы интерфейсной части второго окна. Точно так
же можно при необходимости сослаться в модуле второго окна на модуль главного окна:
активизируйте второе окно и вновь выберите команду File - Uses Unit. Если программист
забудет сослаться на модуль, подключенный к проекту, Delphi при первой же трансляции
программы сообщит об этом и предложит вставить недостающую ссылку.
При вызове метода Show второе окно появляется на экране и работает вместе с
первым, поэтому управление сразу передается оператору, стоящему за обращением к этому
методу. Такие окна называются немодальными, они всегда открываются в одном методе, а
закрываются в другом. В отличие от этого обращение к методу ShowModal создает
модальное окно, которое полностью берет на себя дальнейшее управление программой,
поэтому оператор, расположенный следом за обращением к методу ShowModal в
вызывающей части программы, получит управление только после закрытия модального
окна.
Модальные окна часто требуют от пользователя принятия какого-либо решения. С их
помощью реализуется диалог с пользователем или создается информационное окно, которое
пользователь должен закрыть после ознакомления с содержащейся в нем информацией. Если
от пользователя требуется принятие решения, в модальное окно вставляются флажки,
переключатели, кнопки и другие интерфейсные элементы, с помощью которых пользователь
может сообщить программе о принятом решении. В момент завершения диалога модальное
окно должно поместить число, соответствующее решению пользователя, в свое свойство
ModalResult. Некоторые стандартные кнопки (OK, Yes, No, Cancel и т. п.) автоматически
выполняют эти действия: помещают нужное число в свойство ModalResult и закрывают
окно. В других случаях об этом должен позаботиться программист. Вызывающая программа
19
получает значение свойства ModalResult как возвращаемое значение функции ShowModal и
может тут же его проанализировать:
if Form2.ShowModal = mrXXX then ...
Возможен и такой вариант:
Form2.ShowModal;
if Form2.ModalResult = mrXXX then ...
Для закрытия окна (модального или немодалыюго) используется метод Hide или
Close. Следует учесть, что метод Close всегда помещает в свойство ModalResult значение 2
(mrCancel), в то время как метод Hide не меняет значения этого свойства, поэтому, если
программист хочет передать в вызывающую программу нестандартный модальный
результат, следует ввести в программу следующие операторы:
ModalResult := MyResult;
Hide; // Но ни в коем случае Close!
По умолчанию среда Delphi настроена так, что при подключении нового окна к проекту
менеджер проекта размещает его имя в списке автоматически создаваемых окон (это список
Auto-Create forms). В этом случае программист может не заботиться об инициализации
соответствующего объекта окна. Однако если в программе используется множество окон, их
автоматическое создание в момент старта программы может существенно затянуть процесс
ее загрузки. В то же время немедленное создание всех окон вовсе не обязательно, так как
вряд ли вам понадобится одновременно показывать их на экране в немодальном режиме.
Профессиональные программисты никогда не создают все оконные объекты в момент старта
программы, но используют их по мере надобности. Для этого снимается флажок Auto create
forms & data modules на вкладке Designer окна Environment Options (открывается командой
Tools - Environment Options) или в окне менеджера проекта ссылки на эти формы
переносятся в список Available forms, а обращение к окну реализуется так:
if not Assigned (Form2) then
// Проверяем, создан ли
// оконный объект
Form2 := TForm2.Create(Self);
// Нет — создаем его
if Form2. ShowModal = mrXXX then //и используем
Примеры
1. Запрещение комбинации клавиш Аlt+F4
По умолчанию нажатие комбинации клавиш Аlt+F4 завершает работу любого
приложения под Windows. Сделаем так, что в приложении эта комбинация клавиш работать
не будет. Решим эту задачу простейшим способом — используя событие OnKeyDown. Оно
генерируется для объекта, имеющего фокус, при нажатии любой клавиши на клавиатуре.
Обработчику этого события система передает параметры: Кеу, позволяющий определить,
какая именно клавиша нажата, и Shift, содержащий сведения о нажатых одновременно с ней
клавишах-модификаторах (Shift, Аlt, Ctrl).
Создайте новое приложение и обработайте событие OnKeyDown главной формы. Если
нажата клавиша F4 (проверим значение аргумента Кеу) и, одновременно с ней, модификатор
Аlt (проверим аргумент Shift). то заменим клавишу на другую, чтобы предотвратить
завершение работы приложения:
Procedure TForm1.FormKeyDown (Sender:TObject; vаr Кеу: Word; Shift: ТShiftState) ;
begin
if (Кеу = VК_F4) аnd (Alt in Shift) then Кеу := 0;
еnd;
Сейчас па форме пет никаких элементов управления, но что произойдет, если вы
добавите, например, поле ввода? Когда оно будет в фокусе, то события от клавиатуры будут
поступать именно ему. Поскольку для объекта Edit обработчик нажатия Аlt+F4 не написан,
это событие вызовет реакцию но умолчанию, то есть закрытие приложения.
Чтобы этого не произошло, нужно дать свойству главной формы КеуРrеview значение
Тruе. После этого форма будет получать события клавиатуры первой, до того, как они
попадут к элементу интерфейса, находящемуся в фокусе.
20
2. Приложение с двумя окнами. Модальное окно
Следующее приложение будет содержать две формы. Одна из них (Form1) будет
главным окном приложения, а другая (Form2) будет реализовать вспомогательное окно,
служащее для ввода параметров. Вспомогательное окно будет модальным, то есть, не
закрыв этого окна, переключиться на главное окно будет невозможно.
В приложении используем следующие компоненты:
• 3 х Label (две надписи на форме Form1 и одна на форме Form2);
• 4 х Button (две кнопки в главном окне и две во вспомогательном);
• 1 х Edit (поле ввода на форме Form2).
Обрабатывать будем события OnClick всех четырех кнопок и события OnCreate обеих форм.
По команде создания нового приложения (File - New - Аррliсаtion) создается одна
форма, которой дается имя по умолчанию Form1. Вторую форму необходимо создать
вручную: File - New - Form. Эта команда добавит в приложение не только форму (с именем
по умолчанию Form2), но и второй модуль исходного кода — Unit2.раs. Чтобы в одном
модуле было возможно использовать идентификаторы, определенные в другом модуле
(иными словами, чтобы из одной формы можно было бы работать с компонентами,
находящимися в другой форме), необходимо немного изменить исходный код обоих модулей
- Unit1.раs и Unit2.раs. Найдите в начале модуля Unit1 секцию uses, которая содержит список
модулей, используемых данным модулем. Добавьте в нее (через запятую) имя модуля Unit2.
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Unit2;
Во втором модуле (Unit2) найдите ключевое слово implementation и после него
допишите: Uses Unit1;
var
Form2: TForm2;
implementation
uses Unit1;
{$R *.dfm}
Чтобы экземпляр формы Form2 мог быть создан во время выполнения приложения,
вызовите диалоговое окно Project — Options, перейдите на вкладку Forms и переместите
форму Form2 из списка Auto-Create Forms в список Available Forms.
В результате форма Form2 будет создаваться не при запуске приложения, а тогда,
когда она понадобится, то есть когда пользователь нажмет кнопку Button1 («Изменить
текст»), вызывающую вспомогательное окно. Обработчик нажатия на эту кнопку будет
выглядеть так:
procedure TForm1.Button1Click(Sender: TObject);
var
Form2: TForm2;
begin
// создаем форму
21
Form2 := ТForm2.Create (Self);
// конструкция try предназначена для перехвата ошибок
try
// отобразим форму как модальное окно и проверим
// возвращаемое значение
If Form2.ShowModal = mrOk then
// если нажата кнопка «Готово», то изменим текст метки
Label2.Caption := Form2.Edit1.Техt;
finally
// уничтожаем форму для освобождения памяти
Form2.Free;
end;
end;
Обратите внимание, что, пока вспомогательное окно открыто, вы можете
переключиться на окно любого другого приложения, но не на главное окно текущего
приложения. Это и есть модальное поведение.
Элементы интерфейса в главном окне создадим, как обычно, в обработчике события
OnCreate первой формы:
procedure TForm1.FormCreate(Sender: TObject);
begin
Form1.Caption := 'Пример приложения с двумя формами';
Label1.Font.Size := 18;
Label2.Font.Size:= 18;
Label1.Caption := 'ЭТА надпись постоянна';
Label1.Caption:= 'Текст ЭТОЙ надписи можно изменить во
вспомогательном окне';
//У кнопок есть клавиши быстрого доступа
Button1.Caption := '&Изменить текст';
Button2.Caption:= '&Выход';
end;
Нажатие на кнопку «Выход» завершает работу приложения:
procedure TForm1.Button2Click(Sender: TObject);
begin
// закрытие главной формы = завершение приложения
Close;
end;
Обработчики событий компонентов второй формы находятся и модуле Unit2:
Unit Unit2;
…
procedure TForm2.FormCreate(Sender: TObject);
begin
Caption := 'Модальное окно';
Label1.Caption := 'Введите новый текст’;
Button1.Caption := '&Готово';
Button2.Caption:= '&Отмена ';
// помещаем в поле ввода текущий текст надписи в главном окне
Edit1.Text := Form1.Label2.Caption;
end;
procedure TForm2.Button1Click(Sender: TObject);
begin
// чтобы закрыть модальное окно, устанавливаем значение ModalResult
ModalResult := mrOk;
end;
22
procedure TForm2.Button2Click(Sender: TObject);
begin
ModalResult := mrCancel;
end;
Снова подчеркнем, что установка всех важных
свойств компонентов всегда происходит после создания
формы, то есть и обработчике события OnCreate. Открытое
модальное окно закрывается, когда свойство ModalResult
получает значение. Это значение возвращается в функцию,
открывавшую модальное окно (в нашем случае — в
обработчик Form1.Button1Click), где его можно проверить и
выяснить, каким способом, то есть нажатием какой кнопки,
окно было закрыто.
3. Приложение с двумя окнами. Немодальное окно
Немодальным называется вспомогательное окно, из
которого можно переключиться в другое окно того же
приложения.
За основу нового приложения возьмите предыдущий пример.
Компоненты:
• 2 х Form
• 3 х Label (две надписи на форме Form1 и одна на форме Form2);
• 4 х Button (две кнопки в главном окне и две во вспомогательном);
• 1 х Edit (поле ввода на форме Form2).
События компонентов:
• Form1.Create
• Form1.Create , OnDestroy
• Button1, Button2, Button3, Button4 : OnClick
Отличие от предыдущего примера следует из различии между модальными и
немодальными окнами: если из модального окна можно выйти только путем его закрытия,
для немодального окна это не так. Немодальное окно нельзя создавать просто «по
требованию», потому что пользователь может вернуться в главное окно, не закрывая
вспомогательного, и попытаться создать его еще раз. Поэтому необходимо проверить, не
существует ли уже экземпляр второго окна, и, если существует, не создавать его, а только
отобразить.
Еще одна трудность состоит в том. что при выводе модального окна (вызове метода
ShowModal) вызывающая программа приостанавливается и ожидает его закрытия, а после
вызова метода Show ее выполнение продолжается.
Чтобы проверка существования окна стала возможной, переменная, ссылающаяся на
его экземпляр, должна быть глобальной. Это означает, что ее необходимо объявить в начале
исходного кода модуля, но ни в коем случае не в одном из методов:
Unit Unit1;
…
var
23
Form1: TForm1; Form2: TForm2;
implementation
Таким образом, реализацию метода, открывающего вспомогательное окно (то есть
обработчика события OnClick кнопки Button1) нужно заменить следующим кодом:
procedure TForm1.Button1Click(Sender: TObject);
begin
// создаем форму, только если ее еще не существует
If Form2 = nil then
Form2 := ТForm2.Create (Self);
// отображаем форму в немодальном режиме
Form2.Show;
end;
Остаются две проблемы, которые необходимо решить: как закрыть вспомогательное
окно и как передать введенное значение обратно в вызывающую функцию. Оба действия
реализуются в модуле Unit2, то есть в обработчиках событий компонентов второго окна.
В модуле Unit2 замените заголовок вспомогательного окна:
Unit Unit2;
implementation
uses Unit1;
…
procedure TForm2.FormCreate(Sender: TObject);
begin
Caption := ' Немодальное окно';
Label1. Caption := 'Введите новый текст’;
Button1.Caption := '&Готово';
Button2.Caption:= '&Отмена ';
// помещаем в поле ввода текущий текст надписи в главном окне
Edit1.Text := Form1.Label2.Caption;
end;
Нажатие на любую из кнопок вспомогательного окна закрывает это окно; кнопка
«Готово», кроме того, копирует содержимое поля редактирования в надпись в основном
окне:
procedure TForm2.Button1Click(Sender: TObject);
begin
Form1.Label2.Caption := Edit1.Text;
end;
procedure TForm2.Button2Click(Sender: TObject);
begin
Close;
end;
Напомним, что закрытие окна вызовом метода Close только скрывает форму, но не
уничтожает ее экземпляр, и это окно можно снова отобразить в любой момент. Если вы
хотите, чтобы закрытое окно больше не занимало место в оперативной памяти, окно нужно
уничтожать отдельно.
Это делается в обработчике события OnClose, генерируемого при закрытии окна:
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
// значение caFree приводит к освобождению памяти
Action:= caFree;
end;
При уничтожении экземпляра окна с целью освобождения памяти генерируется
событие OnDestroy. Используем его для того, чтобы сбросить нашу глобальную переменную,
указывающую на экземпляр Form2, значение которой проверяется при попытке отобразить
вспомогательное окно:
24
procedure TForm2.OnDestroy (Sender: TObject);
begin
Form2 := nil;
end;
4. Многодокументное приложение
Хорошо известны приложения, позволяющие открывать несколько документов
(рисунков, файлов, таблиц) одновременно. Напишем простой просмотрщик рисунков,
позволяющий открывать несколько рисунков в одном окне.
Компоненты:
• 2 х Form
• 1 х Button на форме Form1
• 1 х OpenPictureDialog (компонент на вкладке Dialogs) на форме Form1
• 1 х Image (компонент на вкладке Additional) на форме Form2.
События компонентов:
• Form1 : Oncreate
• Form2 : Oncreate, OnClose
• Button1 : OnClick
Чтобы создать повое приложение тина MDI (MultiDocumentInterface), вызовите
диалог File — New - Other, перейдите на вкладку Projects и выберите MDI Application (рис).
Когда вы нажмете ОК, откроется следующее
диалоговое окно, в котором следует выбрать нанку, в
которую будет сохраняться проект. Затем, уже автоматически, будет создан очень сложный «скелет»
приложения, содержащий множество компонентов: строку
меню, диалоги открытия файлов и т.п. Таким способом
можно создать MDI-приложение за несколько минут.
Однако выполним все шаги но созданию MDI-приложения вручную.
Создайте обычное приложение (File — New - Application).
25
Поместите на форму кнопку Button и компонент
OpenPictureDialog. Затем создайте дочернюю форму (File —
New - Form). На эту форму поместите компонент Image.
Как и в предыдущем примере, в секцию uses модуля
Unit1 добавьте модуль Unit2 и отмените создание
экземпляра формы Form2 при запуске приложения (диалог
Project — Options, вкладка Forms, переместите форму Form2
из списка Auto-Create Forms в список Available Forms). Если
окно Form2 будет создаваться в начале работы приложения,
а не по требованию, то после запуска программы
отобразится некрасивое пустое окно.
Unit Unit1;
Interface
uses
..., Unit2 ;
procedure TForm1.FormCreate(Sender: TObject);
begin
// объявляем форму главным окном приложения MDI
FormStyle := fsMDIForm;
Caption := 'MDI просмотр рисунков';
Button1. Caption := 'Открыть';
end;
По нажатии кнопки «Открыть» в главном окне будет
отображен диалог выбора файла изображения (поведение
этого диалога уже запрограммировано в компоненте
OpenPictureDialog), а затем будет создан экземпляр
дочернего окна, в котором отобразится выбранный файл:
procedure TForm1.Button1Click(Sender: TObject);
begin
// запускаем диалог выбора рисунка
If OpenPictureDialog1.Execute then
// файл выбран: создаем дочернее окно
With TForm2.Create(Self) do
begin
// выводим в заголовок окна имя выбранного файла
Caption := OpenPictureDialog1.Filename;
// загружаем содержимое файла в компонент Image1
Image1.Picture.LoadFromFile(OpenPictureDialog1.Filename) ;
end;
end;
Обратите внимание, что в отличие от предыдущего примера мы не присваиваем
никакой переменной ссылку на созданный экземпляр дочернего окна TForm2.Create(Self),
потому что нам не требуется обращаться к этому окну.
Теперь нужно объявить окно Form2 дочерним. Дочернее окно нельзя перемещать за
пределы родительского; если его свернуть, то кнопка свернутого окна расположится на
нижнем краю родительского окна. Одновременно может быть открыто несколько дочерних
окон.
Unit Unit2;
...
procedure TForm2.FormCreate(Sender: TObject);
begin
// объявляем форму дочерним окном
FormStyle := fsMDIChild;
// значение alClient автоматически увеличивает размер объекта
//до клиентской области родительского компонента
26
Image1.Align := alClient;
end;
Стиль окна определяется свойством формы FormStyle. Для главною окна MDIприложения его значением должно быть fsMDIForm, а для дочернего окна — fsMDIChild.
Другие возможные значения этого свойства — fsNormal (обычное окно приложения SDI —
Single Document Interface и fsStayOnTop (для окон, которые должны быть всегда наверху).
Закрытие дочернего окна должно приводить к уничтожению его экземпляра и
освобождению памяти:
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
// значение caFree приводит к освобождению памяти
Action:= caFree;
end;
Запустите готовое приложение, откройте несколько рисунков в дочерних окнах и
попробуйте свернуть/восстановить/развернуть эти окна. Обратите внимание, что при
разворачивании дочернего окна во весь экран оно занимает всю площадь родительского окна
и его уже нельзя свернуть щелчком мыши, потому что у него нет строки заголовка и
системного меню. Для того. чтобы дочернее окно всегда имело строку заголовка с кнопками
управления размером, используется маленькая хитрость: достаточно поместить на форму
Form1 компонент MainMenu ( на вкладке Standart). Никаких пунктов добавлять в меню не
нужно.
5. Окно нестандартного внешнего вида.
Большинство приложении построены но одинаковой схеме: их интерфейс состоит из
прямоугольных окон. Но прямоугольная форма — дело исключительно удобства и
привычки: ничто не запрещает нам создавать окна произвольного внешнего вида н
программировать для них весьма оригинальное поведение. Мы создадим приложение с
главным окном в форме эллипса. Создайте новое приложение и поместите на форму две
кнопки. Нажатие одной из них вызовет изменение внешнего вида окна на эллиптический, а
по нажатии другой из окна исчезнет строка заголовка, а цвет фона изменится на красный.
Чтобы завершить работу приложения без строки заголовка, нажмите комбинацию Alt+F4.
procedure TForm1.FormCreate(Sender: TObject);
begin
Caption := 'Нестандартное окно';
Button1.Caption := 'Изменить форму';
Button2.Caption:= 'Скрыть заголовок';
end;
procedure TForm1.Button1Click(Sender: TObject);
var
// объявим вспомогательную переменную типа HRGN
Region : HRGN;
begin
27
// создаем эллиптическую область с высотой и шириной
// такими же, как у текущего окна
Region:= CreateEllipticRgn(0, 0, Self.Width, Self.Height) ;
// присваиваем эту область окну Form1
SetWindowRgn(Self.Handle, Region, True);
end;
procedure TForm1.Button2Click(Sender: TObject);
var
// объявим вспомогательную переменную типа HRGN
Region : HRGN;
begin
// стиль обрамления bsNone отключает строку заголовка
BorderStyle := bsNone;
Region:= CreateEllipticRgn(0, 0, Self.Width, Self.Height) ;
SetWindowRgn(Self.Handle, Region, True);
// устанавливаем цвет фона
Color := clRed;
end;
В примере использовались функции Windows API.
• Тин данных HRGN: переменная этого тина содержит дескриптор (handle) области экрана
произвольной формы.
• Функция CreateEllipticRgn создает область эллиптической формы. Аргументы этой
функции задают координаты прямоугольника (левый верхний угол х, у, правый нижний
угол х, у), в который вписан данный эллипс. Функция возвращает дескриптор созданной
области.
• Функция SetWindowRgn сопоставляет окну, заданному его дескриптором, область,
заданную ее дескриптором. Третий аргумент функции — логическое значение,
указывающее, нужно ли перерисовать окно сразу же после вызова функции. Если
перерисовка разрешена, то окно приобретает такую же форму, как указанная область.
Дескриптор окна хранится в свойстве Handle. Этим свойством класс TForm обладает
так же, как и все компоненты, созданные на базе TWinControl.
6. Запрет перемещения окна и отключение кнопки закрытия
Напишем приложение, окно которого будет «прикреплено» к экрану так, что
пользователь не сможет его переместить. Также покажем, как деактивировать кнопку с
крестиком в правом верхнем углу окна, чтобы пользователь не смог завершить работу
приложения щелчком мыши.
Поместите на форму четыре кнопки: Button1 и Button2 разрешают/запрещают перемещение,
Button3 и Button4 отключают/включают кнопку закрытия. Обработайте их события OnClick
следующим образом:
procedure TForm1.Button1Click(Sender: TObject);
begin
DeleteMenu(GetSystemMenu(Handle, False), SC_MOVE, MF_BYCOMMAND) ;
28
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
GetSystemMenu(Handle, True) ;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
EnableMenuItem(GetSystemMenu(Handle, False), SC_CLOSE, MF_DISABLED) ;
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
EnableMenuItem(GetSystemMenu(Handle, False), SC_CLOSE, MF_ENABLED) ;
end;
Для запрещения перемещения окна мы вызвали функцию Windows API —
DeleteMenu, удаляющую команды из системного меню. Нажмите кнопку «Запретить»,
откройте системное меню и убедитесь, что из него исчезла команда Переместить. Ссылку на
системное меню, передаваемую этой функции в качестве аргумента, мы получили при
помощи функции GetSystemMenu. Следующий аргумент — SC_MOVE, символическое имя
команды, подлежащей удалению.
Для отключения закрывающей кнопки снова
получаем ссылку на системное меню с помощью функции
GetSystemMenu, но передаем ее другой функции из
Windows API — EnableMenuItem, которая
включает/отключает команды системного меню. Мы
отключаем команду Закрыть (аргумент SC_CLOSE).
Последний аргумент - MF_DISABLED или MF_ENABLED указывает, что именно нужно сделать с командой меню:
отключить или включить.
Когда кнопка закрытия окна отключена, завершить работу приложения можно
комбинацией клавиш Alt+F4.
7. Отключение/включение анимации окна
Когда пользователь сворачивает окно приложения,
оно может превращаться в кнопку не мгновенно, а как бы
скользить в направлении панели задач, постепенно
уменьшаясь. Такой эффект называется анимацией окна.
Отключить или включить анимацию можно программно.
Поместите на форму компонент - CheckBox. Этот
флажок будет отображать текущее состояние анимации включена или выключена - и служить для смены его на
противоположное.
procedure TForm1.FormCreate(Sender: TObject);
var
Info : TAnimationInfo; // вспомогательная переменная
begin
Caption := 'Анимация окна';
CheckBox1.Caption := 'Анимация &включена';
Info.cbSize := Sizeof(TAnimationInfo); // Задаем размер переменной Info
// Вызываем функцию для определения системных параметров
29
SystemParametersInfo (SPI_GETANIMATION, Sizeof(Info), @Info, 0);
CheckBox1.Checked := Info.iMinAnimate = 1;
end;
procedure TForm1.CheckBox1Click(Sender: TObject);
var
Info : TAnimationInfo;
begin
Info.cbSize := Sizeof(TAnimationInfo);
Info.iMinAnimate :=Integer(CheckBox1.Checked);
SystemParametersInfo (SPI_SETANIMATION, Sizeof(Info), @Info, 0);
end;
За анимацию окон отвечает функция Windows API SystemParametersInfo, которой нужно передать ссылку на
заранее подготовленную структуру TAnimationInfo. Вызов
этой функции с аргументом SPI-SETANIMATION заполняет
структуру в соответствии с текущими параметрами, а с
аргументом SPI-SETANIMATION - меняет системные
параметры в соответствии со значениями полей структуры.
Анимацию включает/выключает атрибут этой структуры
iMinAnimate, который мы связали с логическим значением
CheckBox1. Checked при помощи преобразования типов.
Преобразование логического значения True к целому типу
дает 1, а значения False - 0.
8. Вывод надписи вне окна приложения
Создадим приложение, выводящее текст мимо своего
главного окна на рабочий стол Windows. Окно приложения
содержит компонент - кнопку Button, по нажатии которой
строка текста будет выписана на рабочем столе.
procedure TForm1.Button1Click(Sender: TObject);
var
DC: HDC;
Text: String;
begin
Text := 'Delphi круче всех!';
// получаем контекст устройства (Device Context)
DC := GetWindowDC (GetDesktopWindow) ;
// устанавливаем прозрачность
SetBkMode(DC, TRANSPARENT) ;
// выводим текст
TextOut(DC, 150, 150, Pchar(Text), Length(Text) ) ;
// освобождаем контекст устройства
ReleaseDC(GetDesktopWindow, DC) ;
end;
Сначала мы получили так называемый контекст устройства при помощи функции
GetWindowDC. Контекст устройства, в данном случае экрана, — это структура, с помощью
которой происходит взаимодействие программы с устройством.
Вызов функции SetBkMode устанавливает для выводимой строки прозрачный фон
(посмотрите, что изменится, если закомментировать эту строку кода). Следующая функция
TextOut выводит строковую переменную Техt на устройство с указанным контекстом DС
начиная с точки с указанными координатами (150. 150).
Надпись на экране не перерисовывается автоматически, то есть когда содержимое
экрана будет обновлено (например, в результате открытия нового окна, перекрывающего эту
надпись), она не сохранится.
30
9. Окно приветствия (SPLASH SCREEN)
Многие приложения, инициализация которых занимает заметное время, в это время
демонстрируют пользователю окно приветствия (splash screen) с каким-нибудь
изображением. Назначения этого окна — отвлечь пользователя и помочь ему смириться с
долгой загрузкой программы.
Создадим приложение, которое будет отображать такое окно в течение всей
инициализации, но не менее двух секунд.
Создайте новое приложение, добавьте к нему вторую форму (File — New - Form) и
отмените создание ее экземпляра при запуске приложения (Project — Options - Forms,
переместите Form2 из списка Auto-Create Forms в список Available Forms).
Теперь оформите окно приветствия — в обработчике события OnCreate формы Form2
или в Инспекторе объектов. Поместите на форму компонент Image и в свойство
Image1.Picture загрузите какой-нибудь рисунок. Чтобы окно приветствия не имело заголовка,
дайте свойству формы BorderStyle значение bsNone. Нельзя также забывать об установке
свойства FormStyle в значение fsStayOnTop, чтобы главное окно приложения не перекрывало
окна приветствия. Чтобы окно всегда отображалось в центре экрана, присвойте свойству
Position значение poScreenCenter.
Поместите на Form2 компонент Timer (на вкладке System). Теперь достаточно
обработать событие OnCreate главного окна Form1 и событие OnTimer формы окна
приветствия Form2:
procedure TForm1.FormCreate(Sender: TObject);
begin
Form2 := TForm2.Create (Self) ;
Form2.Show;
// устанавливаем таймер на 2 секунды
Form2.Timer1.Interval := 2000;
// запускаем таймер
Form2.Timer1.Enabled:= true;
{далее следует код инициализации приложения}
end;
procedure TForm2.Timer1Timer (Sender: TObject);
begin
Release;
end;
Мы настроили и запустили таймер до начала инициализации приложения. Через
2 секунды произойдет событие OnTimer, но его обработчик Timer1Timer будет
вызван только по завершении обработчика события OnCreate главной формы.
Таким образом, если инициализация займет и больше двух секунд, все это время
окно приветствия будет оставаться на экране.
Это окно уничтожается (освобождается намять) в обработчике Timer1Timer. Обратите
внимание, что вызывается метод формы Release; а не Free, как раньше. Использование
31
метода Free было бы грубой ошибкой. Дело в том. что на момент вызова Free в очереди
сообщений могут находиться сообщения, предназначенные для уничтожаемого окна. Метод
Release гарантирует, что сначала будут обработаны все сообщения для этого окна, стоящие в
очереди, и только потом начнется освобождение памяти.
13. Создание приложений SDI
Термин SDI (Single Document Interface) дословно означает одно-документный
интерфейс и описывает приложения, способные загрузить и использовать одновременно
только один документ. Программа Notepad, приведенная на рис. 1.12, является ярким
представителем такого класса программ.
Следует сказать несколько слов о термине документ. Приложения становятся все
более объекто-центричными, т.е. они работают с неким центральным объектом, в который
могут быть внедрены внешние объекты. В общем случае эти внешние объекты
обрабатываются другим специализированным приложением. Примером может служить
Wordpad (см. рис. 1.5), позволяющий внедрять любые OLE-объекты в свои файлы. Но он
остается при этом SDI-приложением, так как может работать только с одним объектом (или
документом в широком смысле этого слова) Wordpad.
Рис. 1.12. Программа Notepad как пример SDI-приложения
Способность одновременно работать только с одним объектом не мешает
приложению использовать дополнительные формы, например диалоговые окна, панели
инструментов и прочее (на рис. 1.13 показаны панели инструментов в окне Wordpad). Для
реализации этих возможностей в Delphi просто добавьте форму в ваше приложение и
установите ее свойство FormStyle равным fsSizeToolWin или fsToolWindow.
Еще одним примером может служить сама Delphi — огромное количество панелей
инструментов, меню, разнообразных библиотек компонентов, взаимодействующих между
собой форм... Но в целом она остается SDI-приложением, так как может загрузить и
использовать одновременно только один объект.
32
Рис. 1.13. Программа Wordpad — SDI-приложение со многими формами
Пример SDI-приложения
Для демонстрации SDI создадим простую программу просмотра изображения.
Построение интерфейса. Обычно первым шагом построения программы является создание
интерфейса. Выполним следующие действия.
1. Выберите команду File/New Application, и появится пустое приложение. Delphi по
умолчанию создает именно SDI-приложение. Однако хранилище объектов предоставляет
возможность назначить новый шаблон проекта по умолчанию.
2. Установите следующие свойства форм.
Свойство
Caption
Name
ShowHint
Значение
Image Viewer
frmMain
True
3. Поместите компонент TPanel в форму. Установите следующие его свойства.
Свойство
Align
Caption
Значение
alTop
-
4. Поместите три компонента TSpeedButton в TPanel и назовите их spbtnLoad, spbtnStretch и
spbtnCenter. Установите следующие их свойства.
Свойство
spbtnLoad.Hint
spbtnLoad.Left
spbtnLoad.Top
spbtnStretch.AllowAlIUp
spbtnStretch.Grouplndex
spbtnStretch.Hint
spbtnStretch.Left
spbtnStretch.Top
spbtnCenter.AllowAlIUp
spbtnCenter.Grouplndex
spbtnCenter.Hint
spbtnCenter.Left
spbtnCenter.Top
Значение
Load
8
8
True
1
Stretch
56
8
True
2
Center
104
8
5. Поместите еще одну TPanel в форму и установите следующие ее свойства.
Свойство
Align
Caption
Значение
alClient
-
6. Поместите компонент ТImage во вновь созданную ТPanel и установите следующие его
свойства.
Свойство
Align
Name
Значение
alClient
imgMain
7. Добавьте в форму TOpenDialog со следующими свойствами.
33
Свойство
Filter
Name
Options
Значение
Bitmaps (*.bmp)|*.bmp
opndlgLoad
[ofPathMustExist,ofFileMustExist]
Delphi предоставляет вам множество значков для компонента TSpeedButton; они
находятся в каталоге IMAGES\BUTTONS. Для нас вполне подойдут следующие установки
свойств Glyph.
Свойство
spbtnLoad.Glyph
spbtnStretch.Glyph
spbtnCenter.Glyph
Значение
FLDROPEN.BMP
FONTSIZE.BMP
PICTURE.BMP
Теперь самое время сохранить проект, выбрав в меню команду File/Save Project As.
Сохраните Unit1 как Main, а проект — как EgSDIApp.
Написание кода. Теперь, после создания интерфейса, перейдем к написанию исходного
текста вашего приложения. Сначала загрузите изображение следующим образом.
1. Дважды щелкните на компоненте spbtnLoad, и Delphi выведет окно редактора и
автоматически создаст обработчик события OnClick.
2. Введите код.
if opndlgLoad.Execute then
imgMain.Picture.LoadFromFile(opndlgLoad.FileName);
Метод opndlgLoad.Execute вызывает стандартное диалоговое окно открытия файла.
Если вы выбрали файл и щелкнули на ОК, метод возвращает True и загружает в свойство
FileName полный путь к имени файла. При щелчке на Cancel или нажатии клавиши <Esc>
метод вернет False.
Компонент TImage предоставляет свойство Picture, которое является экземпляром
класса TPicture. Этот класс обеспечивает работу с растровыми изображениями,
пиктограммами и метафайлами. Один из его методов, LoadFromFile, служит для загрузки
изображения по имени файла.
Выберите команду Run/Run для компиляции и запуска приложения и попытайтесь
открыть картинку. Теперь добавьте возможность растягивания изображения.
1. Дважды щелкните на компоненте spbtnStretch, и Delphi выведет окно редактора и
автоматически создаст обработчик события OnClick.
2. Введите код.
imgMain.Stretch:= spbtnStretch.Down;
Компонент TSpeedButton имеет свойство Down, которое равно True при нажатой
кнопке. Свойство Stretch класса TImage позволяет растянуть картинку.
Для выравнивания картинки по центру воспользуйтесь приведенной выше
инструкцией (только используйте компонент spbtnCenter) и введите следующий код:
imgMain.Center:= spbtnCenter.Down;
34
14. Создание приложения MDI
Термин MDI (Multiple Document Interface) дословно означает многодокументный
интерфейс и описывает приложения, способные загрузить и использовать одновременно
несколько документов или объектов. Примером такого приложения может служить
диспетчер файлов (File Manager).
Обычно MDI-приложения состоят минимум из двух форм — родительской и
дочерней. Свойство родительской формы FormStyle установлено равным fsMDIForm. Для
дочерней формы установите стиль fsMDIChild.
Родительская форма служит контейнером, содержащим дочерние формы, которые
заключены в клиентскую область и могут перемещаться, изменять размеры,
минимизироваться или максимизироваться. В вашем приложении могут быть дочерние
формы разных типов, например одна — для обработки изображений, а другая — для работы
с текстом.
Создание форм
В MDI-приложении, как правило, требуется выводить несколько экземпляров классов
формы. Поскольку каждая форма представляет собой объект, она должна быть создана перед
использованием и освобождена, когда в ней больше не нуждаются. Delphi может делать это
автоматически, а можно сделать вручную.
Автоматическое создание форм
По умолчанию при запуске приложения Delphi автоматически создает по одному
экземпляру каждого класса форм в проекте и освобождает их при завершении программы.
Автоматическое создание обрабатывается генерируемым Delphi кодом в трех местах.
Первое — раздел интерфейса в файле модуля формы.
type
TForm1 = class (TForm)
private
{Закрытые объявления.}
public
{Открытые объявления.}
end;
В данном фрагменте кода объявляется класс TForm1. Вторым является место, в
котором описывается переменная класса.
var Form1: TForm1;
Здесь описана переменная Form1, указывающая на экземпляр класса TForm1 и
доступная из любого модуля. Обычно она используется во время работы программы для
управления формой.
Третье место находится в исходном тексте проекта, доступ к которому можно
получить с помощью меню View/ Project Source. Этот код выглядит как:
Application.CreateForm(TForm1, Form1);
Процесс удаления форм обрабатывается с помощью концепции владельцев объектов:
когда объект уничтожается, автоматически уничтожаются все объекты, которыми он
35
владеет. Созданная описанным образом форма принадлежит объекту Application и
уничтожается при закрытии приложения.
Динамическое создание форм
Хотя автоматическое создание форм полезно при разработке SDI-приложений, при
создании MDI-приложении оно, как правило, неприемлемо.
Для создания нового экземпляра формы используйте конструктор Create класса
формы. Приведенный ниже код создает новый экземпляр TForm1 во время работы
программы и устанавливает его свойство Caption равным 'New Form'.
Form1:= TForm1.Create(Application);
Form1.Caption:= 'New Form';
Конструктор Create получает от вас в качестве параметра потомка TComponent,
который и будет владельцем вашей формы. Обычно в качестве владельца выступает
Application, чтобы все формы были автоматически закрыты по окончании работы
приложения. Вы можете также передать параметр Nil, создав форму без владельца (или
владеющую собой — как вам больше нравится), но тогда закрывать и уничтожать ее
придется вам. В случае возникновения необрабатываемой ошибки такая форма останется в
памяти, что не говорит о высоком профессионализме программиста...
В приведенном ниже коде Form1 указывает только на последнюю созданную форму.
Если вам это не нравится, воспользуйтесь приведенным ниже кодом — возможно, он более
точно отвечает вашим запросам:
with TFormI.Create(Application) do
Caption:= 'New Form';
Совет: При разработке MDI-приложения метод Show не нужен, так как Delphi
автоматически показывает все вновь созданные дочерние MDI-формы. В случае SDIприложения вы обязаны использовать метод Show.
Даже при динамическом создании форм Delphi попытается навязать вам свои услуги
по созданию экземпляра каждой формы. Чтобы отказаться от них, воспользуйтесь
диалоговым окном Project Options, изображенным на рис. 1.14, и удалите классы форм из
списка Auto-create forms.
Рис. 1.14. Диалоговое окно Project Options позволяет установить опции для текущего проекта
Если вы захотите получить доступ к отдельному дочернему экземпляру класса,
используйте свойство MDIChildren, описываемое в следующем разделе.
MDI-свойства TForm
Объект TForm имеет несколько свойств, специфичных для MDI-приложений.
ActiveMDIChild. Это свойство возвращает дочерний объект TForm, имеющий в
текущее время фокус ввода. Оно полезно, когда родительская форма содержит панель
инструментов или меню, команды которых распространяются на открытую дочернюю
форму.
Например, представим, что проект использует дочернюю форму, содержащую
элемент TMemo, названный memDailyNotes. Имя класса этой дочерней формы—
36
TfrmMDIChild. Родительская форма содержит кнопку Clear в панели инструментов, которая
удаляет содержимое memDailyNotes в активной дочерней форме. Вот как это реализуется.
procedure TfrmMDIParent.spbtnClearClick(Sender: TObject);
begin
if not (ActiveMDIChild = Nil) then
if ActiveMDIChild is TfrmMDIChild then
TfrmMDIChild(ActiveMDIChild).memDailyNotes.Clear;
end;
В первой строке проверяется, равен ли ActiveMDIChild значению Nil, так как в этом
случае обращение к объекту вызовет исключительную ситуацию.
Совет: ActiveMDIChild равен Nil, если нет открытых дочерних форм или свойство FormStyle
не равно fsMDIForm.
Поскольку ActiveMDIChild возвращает объект TForm, компилятор не имеет доступа к
memDailyNotes — объекту TfrmMDIChild. Вторая строка проверят соответствие типов, т.е.
действительно ли ActiveMDIChild указывает на объект TfrmMDIChild.
Третья строка выполняет преобразование типа и вызывает метод Clear компонента
memDailyNotes.
MDIChildren и MDIChildCount. Свойство MDIChildren является массивом объектов
TForm, предоставляющих доступ к созданным дочерним формам. MDIChildCount возвращает
количество элементов в массиве MDIChildren.
Обычно это свойство используется при выполнении какого-либо действия над всеми
открытыми дочерними формами. Вот код сворачивания всех дочерних форм командой
Minimize All.
procedure TFormI.mnuMinimizeAllClick(Sender: TObject);
var
iCount: Integers;
begin
for iCount:= MDIChildCount-1 downto 0 do
MDIChildren[iCount].WindowState:= wsMinimized;
end;
Если вы будете сворачивать окна в порядке возрастания элементов массива, цикл
будет работать некорректно, так как после сворачивания каждого окна массив MDIChildren
обновляется и пересортировывается, и вы можете пропустить некоторые элементы.
TileMode. Это — свойство перечислимого типа, определяющее, как родительская
форма размещает дочерние при вызове метода Tile. Используются значения tbHorizontal (по
умолчанию) и tbVertical для размещения форм по горизонтали и вертикали.
WindowMenu. Профессиональные MDI-приложения позволяют активизировать
необходимое дочернее окно, выбрав его из списка в меню. Свойство WindowMenu
определяет объект TMenuItem, который Delphi будет использовать для вывода списка
доступных дочерних форм. Для вывода списка TMenuItem должно быть меню верхнего
уровня. Это меню имеет свойство Caption, равное swindow.
MDI-события TForm. В MDI-приложении событие OnActivate запускается только
при переключении между дочерними формами. Если фокус ввода передается из не MDIформы в MDI-форму, генерируется событие OnActivate родительской формы, хотя ее
свойство Active никогда и не устанавливается равным True. Эта странность на самом деле
строго логична: ведь, если бы OnActivate генерировался только для дочерних форм, не было
бы никакой возможности узнать о переходе фокуса ввода от другого приложения.
MDI-методы TForm. Специфичные для MDI-форм методы перечислены ниже.
1. Arrangelcons выстраивает пиктограммы минимизированных дочерних форм в нижней
части родительской формы.
2. Cascade располагает дочерние формы каскадом, так что видны все их заголовки.
3. Next и Previous переходит от одной дочерней формы к другой, как будто вы нажали
<Ctrl+Tab> или <Ctrl+Shift+Tab>.
37
4. Tile выстраивает дочерние формы так, что они не перекрываются.
Пример MDI-приложения
В этом разделе мы расширим возможности созданной ранее программы просмотра
изображений.
Создание интерфейса
Интерфейс MDI-приложения очень похож на интерфейс разработанного ранее SDIприложения, но каждое изображение выводится в отдельной, а не в главной форме.
Выполните следующие действия для создания родительской формы.
1. Выберите команду File/New Application, и появится пустое приложение.
2. Установите следующие свойства.
Свойство
Caption
FormStyle
Name
ShowHint
Значение
Image Viewer
fsMDIForm
frmMDIParent
True
3. Поместите компонент TPanel в форму. Установите следующие его свойства.
Свойство
Значение
Align
alTop
Caption
4. Поместите три компонента TSpeedButton в TPanel и назовите их spbtnLoad, spbtnStretch и
spbtnCenter. Установите следующие их свойства.
Свойство
Значение
spbtnLoad.Hint
Load
spbtnLoad.Left
8
spbtnLoad.Top
8
spbtnStretch.AllowAlIUp
True
spbtnStretch.Grouplndex
1
spbtnStretch.Hint
Stretch
spbtnStretch.Left
40
spbtnStretch.Top
8
spbtnCenter.AllowAlIUp
True
spbtnCenter.Grouplndex
2
spbtnCenter.Hint
Center
spbtnCenter.Left
72
spbtnCenter.Top
8
Свойства Glyph установите те же, что и для SDI-приложения.
5. Добавьте в форму компонент TOpenDialog и установите следующие его свойства.
Свойство
Значение
Filter
Bitmaps (*.bmp)]*.bmp
Name
opndlgLoad
Options
[ofPathMustExist,ofFileMustExist]
Теперь создадим дочернюю форму.
1. Выберите из меню File/New Form, и появится пустая форма.
2. Установите следующие ее свойства.
Свойство
Значение
FormStyle
fsMDIChild
Name
frmMDIChild
Position
poDefaultPosOnly
3. Поместите компонент TImage во вновь созданную форму и установите его следующие
свойства.
Свойство
Значение
Align
alClient
Name
imgMain
38
Удалите дочернюю форму из списка автоматически создаваемых форм следующим
образом.
1. Выберите команду Project/ Options, и появится диалоговое окно Project Options, показанное
на рис. 1.14.
2. Выберите frmMDIChild в списке Auto-create forms.
3. Щелкните на кнопке. Форма frmMDIChild при этом будет перенесена в список Available
forms.
4. Щелкните на кнопке ОК.
Теперь самое время сохранить проект, выбрав команду File/Save Project As. Сохраните
Unit1 как MDIParent, Unit2 как MDIChild, а проект — как EgMDIApp.
Написание кода
Создав интерфейс, перейдем к написанию исходного текста приложения, который
будет очень похож на код для SDI-приложения.
Сначала загрузим изображение. Введите следующий код в обработчик события
OnClick компонента spbtnLoad.
procedure TfrmMDIParent.spbtnLoadClick(Sender: TObject);
begin
if opndlgLoad.Execute then
with TfrmMDIChild.Create(Application) do
begin
Caption:= opndlgLoad.FileName;
imgMain.Picture.LoadFromFile(opndlgLoad.FileName);
ClientWidth:= imgMain.Picture.Width;
ClientHeight:= imgMain.Picture.Height;
end;
end;
После запуска диалогового окна создается новый экземпляр дочерней формы и
загружается файл изображения. После загрузки размеры дочерней формы изменяются так,
чтобы можно было видеть все изображение.
Еще пара штрихов — и приложение заработает, как и предусматривалось. Поскольку
модуль ссылается на тип TfrmMDIChild, находящийся в модуле MDIChild, после строки
implementation следует добавить еще одну строку:
uses MDIChild;
Теперь можно приступить к компиляции и запуску приложения. Однако заметьте, что,
когда вы щелкаете на кнопке Close, дочерняя форма не закрывается, а сворачивается в
пиктограмму. Чтобы заставить ее закрыться, следует добавить в код обработчика OnClose
класса TfrmMDIChild маленькую деталь— изменить свойство Action:
Action:= caFree;
Компоненты TSpeedButton Stretch и Center выполняют те же функции, что и в SDIприложении, однако их обработчики события OnClick следует изменить следующим образом
if not (ActiveMDIChild = Nil) then
if ActiveMDIChild is TfrmMDIChild then
TfrmMDIChild(ActiveMDIChild).imgMain.Stretch:= spbtnStretch.Down;
и
if not (ActiveMDIChild = Nil) then
if ActiveMDIChild is TfrmMDIChild then
TfrmMDIChild(ActiveMDIChild).imgMain.Center:= spbtnCenter.Down;
Остается последняя проблема — состояния кнопок Stretch и Center одинаковы для
всех дочерних форм. Для решения этой задачи добавьте в обработчик события OnActivate
класса TfrmMDIChild строки.
frmMDIParent.spbtnStretch.Down:= imgMain.Stretch;
frmMDIParent.spbtnCenter.Down:= imgMain.Center;
И, наконец, самый последний из последних штрихов— в модуле MDIChild добавьте
после строки implementation строку.
39
uses MDIParent;
ПРЕДОСТЕРЕЖЕНИЕ: В этом примере присвоение нового значения свойству
Down класса TSpeedButton вызывало событие Оn-click. Будьте осторожны при написании
кода обработчика события, который генерирует новое событие путем присвоения значения
свойству, ведь при этом можно создать бесконечную рекурсию.
40
Скачать