События в Delphi.

Вычислить. событием.

Таблица В9. События

Событие

Происходит

При щелчке кнопкой мыши

При нажатии кнопки мыши

При отпускании кнопки мыши

При перемещении мыши


Вычислить.

Object Inspector Events (События).

Рис. В26. На вкладке Events

В левой колонке вкладки Events

Object Inspector

Рис. В27.

Вычислить.

Листинг В1.

// нажатие кнопки Вычислить

procedure

dist: integer; // дистанция, метров

t: real; // время как дробное число

min: integer; // время, минуты

sek: integer; // время, секунды

v: real; // скорость

begin

//

//

min:= Trunc(t); //

sek:= Trunc(t*100) mod 100;

//

// числа t

// вычисление

// вывод результата

end;

по модулю

В результате нажатия кнопки Завершить Завершить приведена в листинге В2.

Листинг В2.

// нажатие кнопки Завершить

procedure

begin

Form1.Close; //

Событие и процедура обработки события

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

Событие (Event) - это то, что происходит во время работы программы. В Delphi каждому событию присвоено имя. Например, щелчок кнопкой мыши - это событие OnClick, двойной щелчок мышью событие OnDblClick.

В табл. В9 приведены некоторые события Windows.

Таблица В9. События

Событие

Происходит

При щелчке кнопкой мыши

При двойном щелчке кнопкой мыши

При нажатии кнопки мыши

При отпускании кнопки мыши

При перемещении мыши

При нажатии клавиши клавиатуры

При нажатии клавиши клавиатуры. События OnKeyDown и OnKeyPress - это чередующиеся, повторяющиеся события, которые происходят до тех пор, пока не будет отпущена удерживаемая клавиша (в этот момент происходит событие OnKeyUp)

При отпускании нажатой клавиши клавиатуры

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

При появлении окна на экране в начале работы программы, после появления части окна, которая, например, была закрыта другим окном, и в других случаях

При получении элементом управления фокуса

При потере элементом управления фокуса

Реакцией на событие должно быть какое-либо действие. В Delphi реакция на событие реализуется как процедура обработки события. Таким образом, для того чтобы программа выполняла некоторую работу в ответ на действия пользователя, программист должен написать процедуру обработки соответствующего события. Следует обратить внимание на то, что значительную часть обработки событий берет на себя компонент. Поэтому программист должен разрабатывать процедуру обработки события только в том случае, если реакция на событие отличается от стандартной или не определена. Например, если по условию задачи ограничений на символы, вводимые в поле Edit, нет, то процедуру обработки события OnKeyPress писать не надо, т. к. во время работы программы будет использована стандартная (скрытая от программиста) процедура обработки этого события.

Методику создания процедур обработки событий рассмотрим на примере процедуры обработки события OnClick для командной кнопки Вычислить.

Чтобы приступить к созданию процедуры обработки события, надо сначала в окне Object Inspector выбрать компонент, для которого создается процедура обработки события. Затем в этом же окне нужно выбрать вкладку Events (События).

Рис. В26. На вкладке Events перечислены события, которые может воспринимать компонент (в данном случае - командная кнопка)

В левой колонке вкладки Events (рис. В26) перечислены имена событий, которые может воспринимать выбранный компонент (объект). Если для события определена (написана) процедура обработки события, то в правой колонке рядом с именем события выводится имя этой процедуры.

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

Delphi присваивает функции обработки события имя, которое состоит из двух частей. Первая часть имени идентифицирует форму, содержащую объект (компонент), для которого создана процедура обработки события. Вторая часть имени идентифицирует сам объект и событие. В нашем примере имя формы - Form1, имя командной кнопки - Buttoni, а имя события -Click.

Рис. В27. Шаблон процедуры обработки события, сгенерированный Delphi

В окне редактора кода между словами begin и end можно печатать инструкции, реализующие функцию обработки события.

В листинге В1 приведен текст функции обработки события onclick для командной кнопки Вычислить. Обратите внимание на то, как представлена программа. Ее общий вид соответствует тому, как она выглядит в окне редактора кода: ключевые слова выделены полужирным, комментарии - курсивом (выделение выполняет редактор кода). Кроме того, инструкции программы набраны с отступами в соответствии с принятыми в среде программистов правилами хорошего стиля.

Листинг В1. Процедура обработки события OnClick на кнопке Button1 (Вычислить)

// нажатие кнопки Вычислить

procedure TForm1.ButtonlClick(Sender: TObject);

dist: integer; // дистанция, метров

t: real; // время как дробное число

min: integer; // время, минуты

sek: integer; // время, секунды

v: real; // скорость

begin

// получить исходные данные из полей ввода

dist:= StrToint(Edit1.Text); t:= StrToFloat(Edit2.Text);

// предварительные преобразования

min:= Trunc(t); // кол-во минут - это целая часть числа t

sek:= Trunc(t*100) mod 100;

// кол-во секунд - это дробная часть

// числа t

// вычисление

v:= (dist/1000) / ((min*60 + sek)/3600);

// вывод результата

label4.Caption:= "Дистанция: "+ Edit1.Text

+ " м" + #13 + "Время: " + IntToStr(min)

+ " мин " + IntToStr(sek) + " сек " + #13 +

"Скорость: " + FloatToStrF(v,ffFixed,4,2) + " км/час";

end;

Функция Button1click выполняет расчет скорости и выводит результат расчета в поле Label4. Исходные данные вводятся из полей редактирования Editl и Edit2 путем обращения к свойству Text. Свойство Text содержит строку символов, которую во время работы программы введет пользователь. Для правильной работы программы строка должна содержать только цифры. Для преобразования строки в числа в программе используются функции StrToInt и strToFloat. Функция strToInt проверяет символы строки, переданной ей в качестве параметра (Edit1.Text - это содержимое поля Editl), на допустимость и, если все символы верные, возвращает соответствующее число. Это число записывается в переменную dist. Аналогичным образом работает функция strToFioat, которая возвращает дробное число, соответствующее содержимому поля Edit2. Это число записывается в переменную t.

После того как исходные данные будут помещены в переменные dist и t, выполняются подготовительные действия и расчет. Первоначально с использованием функции Trunc, которая "отбрасывает" дробную часть числа, выделяется целая часть переменной t - это количество минут. Значением выражения Trunc(t*100) mod 100 является количество секунд. Вычисляется это выражение так. Сначала число t умножается на 100. Полученное значение передается функции Trunc, которая возвращает целую часть результата умножения t на 100. Полученное таким образом число делится по модулю на 100. Результат деления по модулю - это остаток от деления.

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

Вычисленное значение скорости выводится в поле Label4 путем присваивания значения свойству Caption. Для преобразования чисел в строки используются функции IntToStr И FloatToStr.

В результате нажатия кнопки Завершить программа должна завершить работу. Чтобы это произошло, надо закрыть, убрать с экрана, главное окно программы. Делается это при помощи метода close. Процедура обработки события Onclick для кнопки Завершить приведена в листинге В2.

Листинг В2. Процедура обработки события Onclick на кнопке Button2 (Завершить)

// нажатие кнопки Завершить

procedure TForm1.Button2Click(Sender: TObject);

begin

Form1.Close; // закрыть главное окно программы

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

Где найти события?

В одном из первых уроков было упомянуто, что каждый объект имеет свойства и события и всё это доступно через Object Inspector . Список всех событий, которые поддерживает объект, находится на вкладке Events Инспектора Объектов. Формат данных аналогичен закладке со свойствами: слева указывается название события, а справа - обработчик, который присвоен событию. Обратите внимание, что всем событиям обычно даются названия, начинающиеся со слова "On " (англ. - "на "). Это хороший тон и довольно устоявшаяся традиция. Такие названия позволяют быстро отличить события от свойств. По аналогии со свойствами, событиям дают вполне логичные имена. Увидев незнакомое событие, в 95% случаев только по названию можно догадаться, когда событие происходит. Если же событие не совсем понятно, либо хочется больше узнать о нём, можно воспользоваться встроенной справочной системой Delphi. Для этого нужно установить курсор на строку с интересующим событием и просто нажать F1 - справочная система откроется на странице с информацией о выбранном событии (если, конечно, оно описано в справке). Для всех стандартных компонент в справочной системе информации предостаточно. Если используется какой-либо сторонний компонент, то описание следует искать в документации, которая идёт вместо с самим компонентом. Некоторые компоненты (в основном - крупные пакеты из большого числа компонент) самостоятельно интегрируют свою документацию в справочную систему Delphi при установке.

Автоматическое создание обработчиков событий

Обработчик события - это набор команд, которые выполняются при вызове события. Создавать обработчики можно двумя способами: прямо в среде Delphi - автоматически, и программным путём, т.е. во время выполнения программы. Создать обработчик очень просто: достаточно дважды щёлкнуть по полю рядом с названием события в Инспекторе Объектов и откроется редактор кода с заготовкой обработчика. Остаётся лишь написать требуемый код между begin и end (курсор уже будет стоять в том месте) и обработчик готов. Как видите, всё довольно просто и быстро. Однако в предыдущих уроках Вы видели, что обработчик создавался и просто при двойном щелчке по объекту на форме... Да, действительно, в этом случае тоже создаётся обработчик. Но этот способ ничем не отличается от только что описанного, просто для каждого объекта задано событие по умолчанию, для которого создаётся обработчик при двойном щелчке. Как правило, это самые используемые события. Например, для кнопки это конечно же будет щелчок по ней. Для нестандартных компонент, если событие по умолчанию не обозначено, берётся первое попавшееся из всех, а если событие всего одно, то выбор тем более очевиден.
После того, как обработчик создан, на вкладке Events рядом с названием события появится название обработчика для него. Это название также можно вписать и вручную или выбрать из списка, в котором содержатся названия всех обработчиков. Имена обработчикам даются также не случайно: берётся имя объекта и к нему дописывается название события. Например, если есть кнопка Button1 и её событие OnClick , то обработчик получит название Button1Click . Опять-таки, по имени обработчика можно догадаться о событии, к которому он относится.

Событие может иметь только один обработчик! Тем не менее, если требуется задать несколько обработчиков, можно сделать следующим образом: единственный указанный обработчик просто программно запускает другие обработчики. Такой приём часто используется.
Однако, обратного запрета не существует: один обработчик может быть привязан к разным событиям объекта и даже к разным объектам . Для этого нужно в строке интересующего события у объекта выбрать имя обработчика из списка.

Обработчик с точки зрения программного кода

Теперь посмотрим, что из себя представляет обработчик в программном коде. А представляет он из себя процедуру, т.е. набор команд и является мини-программой.
Обработчик содержит раздел реализации - он расположен между begin и end (на рисунке выделен рамкой цвета ). В этом блоке, как Вы уже знаете, следует писать код, который и будет выполнен.
Самая верхняя строка обработчика - это его заголовок (выделен цветом ). Элементы заголовка:
- Ключевое слово procedure (процедура);
- Имя объекта, которому принадлежит данная процедура (в данном случае она принадлежит форме - поэтому TForm1 );
- Имя обработчика (цвет );
- Переданные параметры (цвет ).

Между именем объектам (TForm1 ) и именем обработчика (Button1Click ) находится точка - это символ указания на то, что Button1Click принадлежит TForm1 . При работе с любыми структурами точка указывает на принадлежность элемента этой структуре. Сейчас это не играет большой роли - просто небольшое отступление. К примеру, в языке C++ таким разделителем служит комбинация "минус и знак больше": ->

Раздел описаний здесь тоже присутствует, просто он является пустым. Как и положено, расположен он между заголовком обработчика и разделом реализации, т.е. между первой и второй строкой. При необходимости объявления переменных или констант этот раздел описывается обычным образом - добавление ключевого слово var или const и описанием переменных или констант.


Пример обработки событий №1

procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage("Нажата Button1" )
end ;

procedure TForm1.Button2Click(Sender: TObject);
begin
ShowMessage("Нажата Button2" )
end ;

procedure TForm1.Button3Click(Sender: TObject);
begin
ShowMessage("Нажата Button3" )
end ;

Конечно, работать будет... Но настоящие программисты так не делают... Судите сами: а если бы было 100 кнопок - что тогда? 100 обработчиков? Конечно нет!

Можно создать один обработчик сразу для всех кнопок. Выше было сказано, что это можно сделать, если выбрать в Инкспекторе Объектов обработчик события из списка... Но в случае, если 100 кнопок, такой способ тоже непригоден - уйдёт много времени. Есть ещё один: если выбрать на форме сразу несколько объектов, то в Инспекторе Объектов среди свойств и событий останутся только те, которые есть у всех выбранных объектов. Этим и следует воспользоваться.

Итак, выбираем на форме все 3 кнопки (очерчивая область мышью, либо удерживая Shift), далее переходим на вкладку Events в ИО и создаём обработчик события OnClick . Что происходит: открывается редактор кода, но создаётся только один обработчик, хотя он присваивается всем трём кнопкам.

Вывод сообщения также реализуется одной строкой, в которую подставляется имя кнопки, которая была нажата.

procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage("Нажата " +(Sender as TButton).Name)
end ;

Как именно это работает и что делает оператор as сейчас объяснить довольно сложно. Всему своё время. Пример создан с целью показать, что дублирования всегда можно каким-то способом избежать.

Параметры, передаваемые обработчикам

У событий есть параметры. У многих событий параметр один, но у некоторых их бывает и больше - зависит от типа события. Из переданных параметров можно узнать дополнительные данные и условия, при которых произошло событие. Например, если мы знаем, что пользователь передвинул курсор мыши, это ещё ни о чём не говорит и полезной информации практически не несёт. А вот если мы знаем, что курсор был передвинут в точку экрана с некоторыми известными координатами (x;y) - это уже что-то.
Параметр, который встречается практически во всех событиях - Sender . Он указывает на объект, который данное событие инициировал. Использовать его удобно в случае с несколькими объектами, у которых установлен один обработчик одного и того же события (как в нашем примере №1).

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

OnClick - щелчок мышью по объекту. У кнопки событие также срабатывает, если нажать Enter или Пробел в тот момент, когда фокус ввода находится на кнопке.

OnDblClick - двойной щелчок мышью.

OnContextPopup - при вызове контекстного меню объекта, т.е. при щелчке правой кнопкой мыши. Среди параметров есть MousePos - координаты курсора в момент щелчка. Координата по X доступна как MousePos.X , а по Y - как MousePos.Y .

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

OnExit - момент, когда объект теряет фокус ввода.

OnMouseDown - при нажатии кнопки мыши (не обязательно левой). Параметр Button - нажатая кнопка (mbLeft - левая кнопка, mbRight - правая, mbMiddle - средняя). Shift - множество, указывающее, какие функциональные клавиши были зажаты при щелчке. Таким образом можно отслеживать, например, нажатия при зажатых Ctrl +Alt и т.п. X , Y - координаты курсора во время нажатия (относительно левого верхнего угла самого компонента, а не формы!).

OnMouseUp - событие, аналогичное OnMouseDown . Происходит при отпускании кнопки мыши. Пример комбинации этих двух событий - графический редактор: когда кнопка мыши нажата, происходит рисование, а когда отпущена - не происходит.

OnMouseMove - ещё одно событие мыши, происходящее при перемещении курсора над объектом. X , Y - координаты нового положения, Shift - множество нажатых функциональных клавиш.

OnKeyDown - при нажатии какой-либо клавиши клавиатуры в тот момент, когда фокус ввода находится на объекте. Key - код нажатой клавиши, Shift - всё то же множество функциональных клавиш (этот параметр встречается во многих событиях).

OnKeyUp - при отпускании клавиши (антипод OnKeyDown ).

OnKeyPress - при нажатии клавиши, которая печатает какой-либо символ (буква, цифра, знак). Key - уже не код клавиши, а сам символ (тип данных: Char - один символ).

OnResize - при изменении размеров объекта.

OnPaint - при отрисовке объекта на экране (например, формы).

У самой формы также есть множество событий. Отметим некоторые из них:

OnCreate - при создании формы. Обычно в обработчик этого события помещают действия, которые должны произойти при запуске программы. Но при запуске это выполнится только если форма является главной в приложении и при условии, что форма создаётся автоматически. Если в приложении одна форма - она и является главной.

OnClose - при закрытии формы.

OnCloseQuery - при попытке закрыть форму. Это событие можно использовать, если нужно заблокировать закрытие формы. В обработчике присутствует параметр CanClose (англ. - "можно закрыть "): логическое значение, тип данных - Boolean . Если после выполнения обработчика значение переменной CanClose окажется False , то закрытие формы произведено не будет. Значение этой переменной устанавливается программно. Пример использования этого события - текстовый редактор. Если пользователь ввёл текст, но не сохранил его в файл, при выходе из программы нужно спросить, следует ли сохранить изменения.

Пример обработки событий №2

Цель: запретить "прямое" закрытие формы, а спрашивать, действительно ли пользователь хочет закрыть программу. Используем событие формы OnCloseQuery . В обработчике выведем диалоговое окно и, если пользователь ответит "Нет ", заблокируем закрывание. Для вывода окна диалога воспользуемся функцией MessageDlg . Подробнее о ней и о её параметрах Вы узнаете в одном из следующих уроков. Наш обработчик:

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if MessageDlg("Вы действительно хотите выйти?" ,mtWarning,,0) = mrNo then
CanClose:= False
end ;

Проверяемое условие - нажата ли кнопка "Нет ". Если она нажата, блокирум закрытие присвоением переменной CanClose значения False . В результате при закрытии увидим следующее:


События (продолжение)

OnDestroy - при уничтожении формы (после закрытия форма уничтожается и освобождается занятая ей память).

OnShow - при показе формы на экран.

OnHide - при скрытии формы с экрана.

OnActivate - момент, когда форма становится активной, т.е. когда ей передаётся фокус ввода (например, когда пользователь щёлкнул по форме).

OnDeactivate - соответственно, когда форма теряет фокус.

OnChange - при изменении чего-либо (например, у поля ввода TEdit это событие срабатывает, когда изменяется текст в этом поле).

OnDragDrop , OnDragOver , OnEndDock , OnEndDrag , OnStartDock , OnStartDrag - все эти события связаны с технологией Drag&Drop (т.е. когда объект "захватывается" мышью и переносится в другое место), а также с Dock -технологией. Суть этой (Dock) технологии во встраивании одних объектов в другие. Например, если взять Object Inspector за заголовок и переместить на нижнюю часть Object TreeView , а затем отпустить, то окна объединятся, а если переместить его в центр Object TreeView , то закладок станет 3 (Object TreeView станет третьей закладкой).

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

Заключение

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

Наиболее общее определение события — любое происшествие, вызванное вмешательством пользователя, поведением системы или логикой кода приложения. Событие в программе может быть связано с некоторым кодом, называемым обработчиком события и отвечающим на это происшествие. С точки зрения разработчика, событие — это имя, к которому обработчик события может быть присоединен в программе.

Если разработчик реализовал код обработчика события, то он выполняется, когда это событие происходит. В противном случае обычно ничего не происходит.

Имеется два вида событий: взаимодействие пользователя и изменение состояния. События взаимодействия пользователя почти всегда вызываются в соответствии с сообщениями Windows, указывая, что пользователь делал кое-что, поэтому компонент может ответить. События изменения состояния также могут быть сведены к сообщениям Windows.

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

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

Объявление событий

Синтаксически события объявляются почти полностью аналогично свойствам:

Property :
[Index Read ]
[Write }
[Stored Логическое выражение>} [Default Nil|NoDefault ];

Примечания:
Хотя в командах чтения и записи могут использоваться методы, на практике они не используются. Обычно используется прямой доступ к полю.
Команда Index используется вместе с методами записи или чтения. Поскольку методы практически не используются, то и команда Index также.
Команда Default фактически допускает только одно значение по умолчанию — Nil, которое и так устанавливается компилятором. Поэтому использование команды Default и, соответственно, NoDefault нецелесообразно.
Все события в Delphi принято именовать с «On «: OnCreate, OnClick и т.д.
В данном случае событие и соответствующее поле имеют тип TNotifyEvent.

Таким образом, в общем случае для объявления события необходимо сделать следующее:
определить или выбрать тип данных события (тип указателя на метод)(процедурный тип);
объявить поле соответствующего типа для хранения значения события;
объявить (корреспондирующий — event-dispatching method) метод, который будет вызывать обработчик события, когда оно произойдет. Представить реализацию этого метода и определить механизм его вызова;
объявить собственно событие.

а) Объявление типа события
Событие — это механизм, с помощью которого связывается некоторое происшествие с некоторым кодом. Код оформляется в виде метода, тип которого объявляется до объявления класса, включающего объявление события. Этот метод должен принадлежать не классу, а экземпляру класса, поскольку даже для объектов одного класса исполняемый код обычно бывает различным. Создание кода метода, реагирующего на событие — это привилегия программиста, Delphi же обеспечивает связь этого метода с событием для вызова этого метода.

Связь события и метода, выполняющего в ответ на это событие, осуществляется в Delphi с помощью указателя на метод. Точнее — это указатель на метод в экземпляре класса. Указатели на метод работают точно также как любой другой процедурный тип, но еще они поддерживают скрытый указатель на объект. Как и всякий указатель, это фактически адрес, в данном случае, адрес метода, и он требует четыре байта для размещения в памяти. Поскольку эти методы предназначены для обработки событий, их называют обработчиками событий (event handler), а управление объектами — управлением по событиям (event driven).

Таким образом, для объявления события необходимо предварительно объявить или выбрать стандартный тип обработчика события. От обычного процедурного типа указатели на метод отличаются тем, что используют специальный синтаксис:

Type =Procedure (Sender : TObject [; }) Of Object ;

Дополнительные ключевые слова Of Object указывают компилятору о том, что это указатель на метод объекта, а не самостоятельная процедура. Таким образом, для обработки событий в Delphi предусмотрено объявление указателей на метод, обеспечивающих неявную передачу указателя на экземпляр (переменная Self), вызвавший то или иное событие.

В большинстве случаев указатели на метод объявляются как процедуры. Хотя компилятор Delphi позволяет объявлять функции-указатели на метод использовать их для обработчиков событий следует осторожно. Программист может не создать код обработчика для события, а поскольку пустая функция возвращает неопределенный результат, то пустой обработчик события недопустим.

Можно использовать Var параметры и для того, чтобы отменять заданную по умолчанию обработку.

Примеры типовых указателей на методы.
Список событий в Delphi:

TNotyfyEvent=Procedure(Sender: TObject) Of Object;
OnClick; OnDblClick; OnCreate; OnDestroy;
TMouseMoveEvent=Procedure(Sender: TObject; Shift: TShiftState; X,Y: Integer) Of Object; =>OnMouseMove

Б) Определение механизма возбуждения события
Этот механизм должен фактически реагировать на какие-то ситуации, происшествия, в ответ на возникновение которых и должно возбуждаться события.

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

в) Объявление и реализация метода, вызывающего обработчик события После определения механизма возбуждения пользовательского события, следует решить, какие реакции (видимые и невидимые) должны быть у объекта, и как будет вызываться обработчик события.

Обычно для реализации кода реакции объекта на событие и вызова обработчика события объявляется и создается реализация соответствующего (корреспондирующего) виртуального защищенного метода.

Так, в задачу динамического метода Click, помимо изменения внешнего представления кнопки (кнопка «утопает»), входит проверка наличия обработчика события, и если он есть, передача управления ему.

Синтаксис объявления такого метода следующий:

Procedure [()]; Dynamic ;

После объявления метода необходимо в разделе Implementation модуля представить его реализацию. Реализация должна позволить компоненту отвечать на действия, активизируемые вашим методом сообщения о событии.

Стандартный синтаксис для реализации метода уведомления о событии имеет следующий вид:

Procedure .[()];
Begin
If Assigned ()
Then (Self [,]);
End ;

Обзор

События в Delphi

Понимание событий

Обработка сообщений Windows в Delphi

  1. Обзор
  2. Одна из ключевых целей среды визуального программирования - скрыть от пользователя сложность программирования в Windows. При этом, однако, хочется, чтобы такая среда не была упрощена слишком, не до такой степени, что программисты потеряют доступ к самой операционной системе.

    Программирование, ориентированное на события - неотъемлемая черта Windows. Некоторые программные среды для быстрой разработки приложений (RAD) пытаются скрыть от пользователя эту черту совсем, как будто она настолько сложна, что большинство не могут ее понять. Истина заключается в том, что событийное программирование само по себе не так уж сложно. Однако, есть некоторые особенности воплощения данной концепции в Windows, которые в некоторых ситуациях могут вызвать затруднения.

    Delphi предоставляет полный доступ к подструктуре событий, предоставляемой Windows. С другой стороны, Delphi упрощает программирование обработчиков таких событий.

    В данном уроке приводится несколько примеров того, как обрабатывать события в Delphi, дается более детальное объяснение работы системы, ориентированной на события.

  3. События в Delphi
  4. Объекты из библиотеки визуальных компонент (VCL) Delphi, равно как и объекты реального мира, имеют свой набор свойств и свое поведение - набор откликов на события, происходящие с ними. Список событий для данного объекта, на которые он реагирует, можно посмотреть, например, в Инспекторе Объектов на странице событий. (На самом деле, на этой странице представлен список свойств, которые имеют тип вроде TMouseMoveEvent и представляют из себя процедуры-обработчики событий. Существует соглашение по названиям данных свойств. Например, OnDblClick соответствует двойному щелчку мыши, а OnKeyUp - событию, когда нажатая клавиша была отпущена.) Среди набора событий для различных объектов из VCL есть как события, портируемые из Windows (MouseMove, KeyDown), так и события, порождаемые непосредственно в программе (DataChange для TDataSource).

    Поведение объекта определяется тем, какие обработчики и для каких событий он имеет. Создание приложения в Delphi состоит из настройки свойств используемых объектов и создания обработчиков событий.

    Простейшие события, на которые иногда нужно реагировать - это, например, события, связанные с мышкой (они есть практически у всех видимых объектов) или событие Click для кнопки TButton. Предположим, что вы хотите перехватить щелчок левой кнопки мыши на форме. Чтобы сделать это - создайте новый проект, в Инспекторе Объектов выберите страницу событий и сделайте двойной щелчок на правой части для свойства OnClick. Вы получите заготовку для обработчика данного события:

    begin

    end;

    Напишите здесь следующее:

    procedure TForm1.FormClick(Sender: TObject);

    begin

    MessageDlg("Hello", mtInformation, , 0);

    end;

    Каждый раз, когда делается щелчок левой кнопки мыши над формой будет появляться окно диалога (см. рис.1).

    procedure TForm1.FormKeyDown(Sender: TObject;

    var Key: Word;

    Shift: TShiftState);

    begin

    MessageDlg(Chr(Key), mtInformation, , 0);

    end;

    Теперь, когда вы имеете начальные знания о программировании событий в Delphi, самое время вернуться назад и посмотреть на теорию, стоящую за тем кодом, что вы написали. После получения представления о том, как работает система, можно вернуться к среде Delphi и посмотреть, как использовать полностью имеющиеся возможности.

  5. Понимание событий

Событийное программирование есть не только в Windows, и данную черту можно реализовать не только в операционной системе. Например, любая DOS программа может быть основана на простом цикле, работающем все время жизни программы в памяти. Ниже вы найдете гипотетический пример, как данный код может выглядеть:

begin

InitializeMemory;

repeat

CheckForMouseEvent(Events);

CheckForKeyPress(Events)

HandleEvents(Events);

until Done:= True;

DisposeMemory;

end.

Это типичный пример программы, ориентированной на события. Она начинается и заканчивается инициализацией и освобождением памяти. В программе присутствует простой цикл repeat..until, который проверяет появление событий от мыши и клавиатуры и затем дает возможность программисту ответить на эти события.

Переменная Events может быть записью с простой структурой:

TEvent = record

X, Y: Integer;

MouseButton: TButton;

Key: Word;

end;

Тип TButton, указанный выше, можно декларировать так:

TButton = (lButton, rButton);

Эти структуры позволяют вам проследить, где находится мышь, каково состояние ее кнопок, и значение нажатой клавиши на клавиатуре. Конечно, это пример очень простой структуры, но заложенные здесь принципы отражают то, что происходит внутри Windows или внутри других систем, ориентированных на события, вроде Turbo Vision. Если бы программа, приведенная выше, была редактором текста, то обработчик HandleEvent для такой программы мог бы иметь вид:

procedure HandleEvent(Events: TEvent);

begin

case Events.Key of

’A’..’z’: Write(Events.Key);

EnterKey: Write(CarriageReturn);

EscapeKey: Done:= True;

end;

end;

Согласно коду выше, программа будет печатать букву ‘a’ при нажатии этой клавиши и перейдет на новую строку, если нажата клавиша ‘Enter’. Нажатие ‘Esc’ приведет к завершению программы.

Код такого типа может быть очень удобным, в частности, если вы пишете программу, в которой требуется анимация. Например, если нужно перемещать несколько картинок по экрану, то может понадобиться сдвинуть их на несколько точек, затем проверить, нажимал ли пользователь кнопки. Если такое событие было, то его можно обработать, если нет, то двигать дальше.

Надеюсь, что приведенный пример дает некоторое понимание работы ориентированной на события системы. Единственное, что осталось пропущенным - почему система Windows так спроектирована.

Одной из основных причин, почему Microsoft сделал Windows по такой схеме, является тот факт, что множество задач работает в среде одновременно. В многозадачных системах операционная система должна знать, щелкнул ли пользователь мышкой на определенное окно. Если это окно было частично перекрыто другим, то это становится известно операционной системе и она перемещает окно на передний план. Понятно, что неудобно заставлять само окно выполнять эти действия. Операционной системе лучше обрабатывать все нажатия клавиш и кнопок на мыши и затем передавать их в остальные программы в виде событий.

Если кратко, программист в Windows почти никогда не должен напрямую проверять “железо”. Система выполняет эту задачу и передает информацию программе в виде сообщений.

Когда пользователь щелкает мышкой, операционная система обрабатывает это событие и передает его в окно, которое должно обработать данное событие. Созданное сообщение, в этом случае, пересылается в некую процедуру DefWindowProc окна (default window procedure). DefWindowProc - аналог процедуры HandleEvent из примера, приведенного выше.

Каждое окно в Windows имеет свою DefWindowProc. Чтобы полностью понять данное утверждение, представьте, что каждая кнопка, каждый ListBox, каждое поле ввода и т.д. на самом деле являются окнами и имеют свою процедуру DefWindowProc. Это очень гибкая и мощная система, но она может заставить программиста писать очень сложный код. Delphi дает возможность быть защищенным от такой структуры программы.

Почти все, что происходит в Windows принимает форму сообщений и, если вы хотите их использовать в Delphi (в большей мере это необходимо при написании своих собственных компонент), то нужно понять, как эти сообщения работают.

Если посмотреть на DefWindowProc в справочнике по Windows API, то можно увидеть следующее определение:

function DefWindowProc(Wnd: HWnd; Msg, wParam: Word;

lParam: LongInt);

Каждое сообщение, посылаемое в окно, состоит из четырех частей: первая часть - handle окна, получающего сообщение, Msg сообщает, что произошло а третья и четвертая части (wParam и lParam) содержат дополнительную информацию о событии. Вместе эти четыре части являются аналогом показанной выше структуры TEvent.

Вторая часть сообщения имеет длину 16 бит и сообщает, что за событие произошло. Например, если нажата левая кнопка на мыши, то переменная Msg содержит значение WM_LBUTTONDOWN. Существуют десятки различного типа cообщений и они называются вроде WM_GETTEXT, WM_HSCROLL, WM_GETTEXTLENGTH и т.п. Список всех сообщений можно видеть в справочнике по Windows API (on-line help).

Последние две переменные, длиной 16 и 32 бита, называются wParam и lParam. Они сообщают программисту важную дополнительную информацию о каждом событии. Например при нажатии кнопки мыши, lParam содержит координаты указателя мыши.

Одна из хитростей заключается в том, как выделить нужную информацию из этих переменных. В большинстве случаев Delphi освобождает вас от необходимости выполнять данную задачу. Например, в обработчике события OnMouseDown для формы вы просто используете координаты X и Y. Как программисту, вам не нужно прилагать усилия для получения сообщения и связанных с ним параметров. Все, что связано с событиями, представлено в простом и непосредственном виде:

procedure TForm1.FormMouseDown(Sender: TObject;

Button: TMouseButton;

Shift: TShiftState;

X, Y: Integer);

Итак, если подвести итог, то должно стать ясным следующее:

  • Windows является системой ориентированной на события;
  • События в Windows принимают форму сообщений;
  • В недрах VCL Delphi сообщения Windows обрабатываются и преобразуются в более простую для программиста форму;
  • Обработка событий в Delphi сводится к написанию для каждого объекта своих обработчиков;
  • События в программе на Delphi вызываются не только сообщениями Windows, но и внутренними процессами.
      1. Обработка сообщений Windows в Delphi

Конечно, нельзя придумать такую библиотеку объектов, которые бы полностью соответствовали потребностям программистов. Всегда возникнет необходимость дополнения или изменения свойств и поведения объектов. В этом случае, так же, как и при создании своих собственных компонент в Delphi, часто требуется обрабатывать сообщения Windows. Поскольку Object Pascal является развитием и продолжением Borland Pascal 7.0, то это выполняется сходным с BP способом.

Общий синтаксис для декларации обработчика сообщений Windows:

procedure Handler_Name(var Msg: MessageType);

message WM_XXXXX;

Handler_Name обозначает имя метода; Msg - имя передаваемого параметра; MessageType - какой либо тип записи, подходящий для данного сообщения; директива message указывает, что данный метод является обработчиком сообщения; WM_XXXXX - константа или выражение, которое определяет номер обрабатываемого сообщения Windows.

Рассмотрим обработку сообщений на примере. Например, при нажатии правой кнопки мыши на форме в программе появляется всплывающее меню (pop-up menu, если оно было привязано к этой форме). Программист может захотеть привязать к правой кнопке какое-нибудь другое событие. Это можно сделать так:

type

TForm1 = class(TForm)

PopupMenu1: TPopupMenu;

MenuItem1: TMenuItem;

MenuItem2: TMenuItem;

MenuItem3: TMenuItem;

private

{ Private declarations }

procedure WMRButtonDown(var Msg: TWMMouse); message

WM_RBUTTONDOWN;

public

{ Public declarations }

end;

Подчеркнут код, добавленный в декларацию объекта TForm1 вручную. Далее, в секции implementation нужно написать обработчик:

begin

  • , 0);
  • end;

    В данном случае при нажатии правой кнопки мыши будет появляться диалог.

    Вообще-то, у класса TForm уже есть унаследованный от дальнего предка обработчик данного события, который называется точно также и вызывает то самое pop-up меню. Если в новом обработчике сообщения нужно выполнить действия, которые производились в старом, то для этого применяется ключевое слово inherited . Если слегка модифицировать наш обработчик, то после диалога будет появляться pop-up меню:

    procedure TForm1.WMRButtonDown(var Msg: TWMMouse);

    begin

    MessageDlg("Right mouse button click.", mtInformation,

  • , 0);
  • inherited;

    end;

    Однако, есть еще способ обработки всех сообщений, которые получает приложение. Для этого используется свойство OnMessage объекта Application, который автоматически создается при запуске программы. Если определен обработчик события OnMessage, то он получает управление при любом событии, сообщение о котором направлено в программу. Следующий код будет приводить к появлению диалога при двойном щелчке мыши на любом объекте в приложении.

    procedure TForm1.FormCreate(Sender: TObject);

    begin

    Application.OnMessage:=AOM;

    end;

    procedure TForm1.AOM(var Msg: TMsg; var Handled: Boolean);

    begin

    Handled:=False;

    if Msg.Message = WM_LBUTTONDBLCLK then begin

    MessageDlg("Double click.", mtInformation, , 0);

    Handled:=True;

    end;

    end;

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


    Наряду с ними у формы есть и спефические свойства , методы и события , определяемые ее особым значением. Некоторые из них характеризуют форму как главный объект приложения, скажем, свойство , другие присущи форме как контейнеру других компонентов, например, свойства и .

    Система Delphi при добавлении новой формы в проект автоматически создает один экземпляр класса (Form1, Form2 и т. д.), внося соответствующие изменения в файл проекта, например, добавляя строку кода:

    Управлять процессом автоматического создания форм можно, непосредственно редактируя файл проекта (не рекомендуется делать неопытным программистам) или выполняя настройки в окне параметров проекта (список Auto-create forms на странице Form). Если форма переведена из этого списка в список Available forms доступных форм проекта, то инструкция ее создания исключается из файла проекта, и программист в ходе выполнения приложения должен динамически создать экземпляр этой формы.

    На данном скринште мы видим, что Form1 будет создана при запуске программы, а Form2 необходимо будет создать динамически при выполнении программы.

    Метод Сreate

    Для создания экземпляров форм служит метод (конструктор) Сreate . Сам класс формы обычно предварительно описывается при конструировании приложения, и для формы уже существуют файлы формы (dfm) и программного модуля (pas).

    В вышеуказанной процедуре создается форма Form2 , принадлежащая объекту приложения и имеющая заголовок новая форма .

    События формы (Form)

    При создании и использовании формы генерируются следующие события типа TNotifyEvent, указанные в порядке их возникновения:

    1. OnCreate;
    2. OnShow;
    3. OnActivate;
    4. OnPaint.

    Событие OnCreate

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

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

    Приведем в качестве примера процедуру, обрабатывающую событие OnCreate формы Form2:

    При создании форма получает новый заголовок пример формы, в комбинированный список ComboBox2 загружаются данные из файла list.txt , кнопка Button3 блокируется, а фокус ввода устанавливается на редактор Edit1.

    Свойство Visible

    Из всех созданных форм Delphi при выполнении приложения автоматически делает видимой главную форму, для этого свойство Visible этой формы устанавливается в значение True. Для остальных форм значение данного свойства по умолчанию равно False, и после запуска приложения они на экране не отображаются. Если формы создаются вручную, то их отображение и скрытие в процессе работы приложения регулируется программистом через свойство Visible. Даже если форма невидима, ее компонентами можно управлять, например, из других форм.

    Дочерние формы многодокументного приложения становятся видимыми на экране сразу после их создания.

    В вышеуказанных процедурах нажатие кнопок btnShowForm2 и btnHideForm2 , расположенных в форме Form1, приводит, соответственно, к отображению и скрытию формы Form2.

    Методы Show и Hide

    Управлять видимостью форм на экране можно также с помощью методов Show и Hide . Процедура Show отображает форму в немодальном режиме, при этом свойство Visible устанавливается в значение True, а сама форма переводится на передний план. Процедура Hide скрывает форму, устанавливая ее свойство Visible в значение False.

    Если окно видимо, то вызов метода Show переводит форму на передний план и передает ей фокус ввода.

    Пример отображения и скрытия формы:

    Здесь нажатие кнопок btnShowForm3 и btnHideForm3 , расположенных В форме Form1, приводит соответственно к отображению на экране и удалению с экрана формы Form3.

    В момент отображения формы на экране ее свойство visible принимает значение True, и возникает событие OnShow . Соответственно при скрытии формы свойство visible принимает значение False, и возбуждается событие OnHide .

    События OnActivate и OnDeActivate

    При получении формой фокуса ввода, например при нажатии кнопки мыши в области формы, происходит ее активизация и возникает событие OnActivate , а при потере фокуса- событие OnDeActivate .

    Событие OnPaint

    Событие OnPaint генерируется при необходимости перерисовки формы, например, при активизации формы, если до этого часть ее была закрыта другими окнами.

    Метод Сlose — закрывает форму

    Для закрытия формы используется метод close , который, если это возможно, удаляет ее с экрана. В случае закрытия главной формы прекращается работа врего приложения.

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

    Процедура Close не уничтожает созданный экземпляр формы, и форма может быть снова вызвана на экран, в частности, с помощью методов Show или ShowModal .

    Уничтожение формы (Release, Free или Destroy)

    Уничтожение формы происходит с помощью методов Release , Free или Destroy , после чего работа с этой формой становится невозможна, и любая попытка обратиться к ней или ее компонентам вызовет исключение (ошибку). Необходимость уничтожения формы может возникнуть при оформлении заставок или при разработке больших приложений, требующих экономии оперативной памяти. Предпочтительным методом удаления формы считается метод Free, поскольку он предварительно проверяет возможность удаления. Например, в процедуре

    В приведенной процедуре кнопка btnDestroy уничтожает форму Form3 . Для этой кнопки полезно задать соответствующий заголовок, например Удалить .

    События при закрытии и уничтожении формы

    При закрытии и уничтожении формы генерируются следующие события, указанные в порядке их возникновения:

    1. OnDeActivate;
    2. OnHide;

    Событие OnCloseQuery

    Событие типа TcloseQueryEvent возникает в ответ на попытку закрытия формы. Обработчик события получает логическую переменную-признак CanClose, определяющую, может ли быть закрыта данная форма. По умолчанию эта переменная имеет значение True, и форму можно закрыть. Если установить параметр CanClose в значение False, то форма остается открытой. Такую возможность стоит использовать, например, для подтверждения закрытия окна или проверки, сохранена ли редактируемая информация на диске. Событие OnCloseQuery вызывается всегда, независимо от способа закрытия формы.

    Приведем в качестве примера процедуру закрытия формы:

    Здесь при закрытии формы Form2 выдается запрос на подтверждение операции, который представляет собой модальное диалоговое окно с текстом и двумя кнопками - Yes и No . Нажатие кнопки Yes вызывает закрытие формы, при нажатии кнопки No закрытие формы не происходит.

    Событие OnClose

    Событие типа TCioseEvent возникает непосредственно перед закрытием формы. Обычно оно используется для изменения стандартного поведения формы при закрытии. Для этого обработчику события передается переменная Action типа TCloseAction, которая может принимать следующие значения:

    • caNone (форму закрыть нельзя);
    • caHide (форма делается невидимой);
    • caFree (форма уничтожается, а связанная с ней память освобождается);
    • caMinimize (окно формы сворачивается) - значение по умолчанию для MDI-форм.

    При закрытии окна методом Close переменная Action по умолчанию получает значение caHide, и форма делается невидимой. При уничтожении формы, например, методом Destroy, переменная Action по умолчанию получает значение caFree, и форма уничтожается.

    Событие возникает при закрытии формы щелчком мыши на кнопке закрытия системного меню или при вызове метода Close. Когда закрывается главная форма приложения, все остальные окна закрываются без вызова события OnClose.

    В выше указанной процедуре при закрытии формы Form2 проверяется признак модификации содержимого редактора Memo1. Если информация в Memo1 была изменена, то форма не закрывается.

    Событие onDestroy

    Событие типа TNotifyEvent возникает непосредственно перед уничтожением формы и обычно используется для освобождения ресурсов.

    Событие onResize

    При каждом изменении размеров формы в процессе выполнения приложения возникает событие типа TNotifyEvent. В обработчике этого события может размещаться код, например, выполняющий изменение положения и размеров элементов управления окна, не имеющих свойства Align.

      procedure TForml. FormResize (Sender: TObject ) ; begin

      // Установка размеров и положения сетки строк

      StringGrid1. Left : = 10 ;

      StringGrid1. Top : = 5 ;

      StringGrid1. Width : = Form1. ClientWidth �— 20 ;

      StringGrid1. Height : = Form1. ClientHeight �— 15 ;

      Button1. Height ;

      // Установка положения кнопки

      Button1. Left : = Form1. ClientWidth �— 10�— Button1. Width ;

      Button1. Top : = Form1. ClientHeight - 5 - Button1. Height ;

      end ;

    В форме Form1 находятся два компонента: сетка строк StringGrid1 и кнопка Button1. Эти компоненты расположены в форме следующим образом:

    • сетка StringGrid1 занимает всю ширину клиентской области формы Form3, отступы слева и справа составляют 10 пикселов;
    • кнопка Button1 (Закрыть) выровнена по правому краю сетки StringGrid1;
    • расстояния между сеткой, кнопкой, верхним и нижним краями формы составляют 5 пикселов.

    При изменении размеров формы Form1 выполняется пересчет параметров, задающих размеры и положение сетки строк, а также положение кнопки.

    Cвойство FormStyle — стиль формы

    Стиль формы определяется свойством типа TFormstyle, принимающим следующие значения:

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

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

    Пример динамического изменения стиля формы:

    При выборе пункта меню mnuTop форма переключает свой стиль между значениями fsNormal и fsStayOnTop . Смена стиля отображается графически галочкой в заголовке этого пункта меню.

    Cвойство BorderStyle — свойства рамки формы

    Каждая форма имеет ограничивающую рамку. Вид и поведение рамки определяет свойство типа TFormBorderstyle. Оно может принимать следующие значения:

    • bsDialog (диалоговая форма);
    • bsSingle (форма с неизменяемыми размерами);
    • bsNone (форма не имеет видимой рамки и заголовка и не может изменять свои размеры) - часто используется для заставок;
    • bsSizeable (обычная форма с изменяемыми размерами) - по умолчанию, имеет строку заголовка и может содержать любой набор кнопок;
    • bsToolwindow (форма панели инструментов);
    • bsSizeToolwin (форма панели инструментов с изменяемыми размерами).

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

    Невозможность изменения размеров форм некоторых стилей относится только к пользователю - нельзя с помощью мыши передвинуть границу формы в ту или иную сторону. Программно при выполнении приложения для формы любого стиля можно устанавливать любые допустимые размеры окна, а также изменять их.

    Пример программного изменения размеров формы:

    При нажатии кнопки btnResizeForm ширина формы Form2 увеличивается на 100 пикселов, даже если ее свойство BorderStyle имеет значение, равное bsDialog, bsSingle или bsNone.

    Метод ShowModal

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

    Cвойство BorderIcons

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

    • blSystemMenu (окно имеет системное меню и может содержать кнопки системного меню);
    • blMinimize (окно содержит кнопку свертывания);
    • blMaximize (окно содержит кнопку развертывания/восстановления);
    • blHelp (окно содержит кнопку справки, которая отображает вопросительный знак и вызывает контекстно-зависимую справку).

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

    Различные значения свойства не являются независимыми друг от друга. Так, если отсутствует системное меню, то ни одна кнопка не отображается. Если имеются кнопки развертывания и свертывания, то не отображается кнопка справки. Возможность появления кнопок также зависит от стиля формы. Например, отображение кнопок развертывания и свертывания возможно только для обычной формы и формы панели инструментов с изменяемыми размерами.

    Обычно стиль формы и набор кнопок заголовка задаются на этапе разработки приложения в окне Инспектора объектов. При этом в проектируемой форме всегда видны обычная рамка и три кнопки (развертывания, свертывания и закрытия формы), независимо от значения свойств и . Заданные стиль формы и набор кнопок становятся видимыми при выполнении программы.

    Форма включает в себя клиентскую и неклиентскую области. Неклиентская область занята рамкой, заголовком и строкой главного меню. Обычно эта область прорисовывается Windows и программистом не затрагивается. При необходимости изменить отображение в неклиентской области программист может перехватить и обработать сообщение WM_NCPaint .

    Cвойства ClientWidth и ClientHeight

    В клиентской области обычно размещаются различные элементы управления, выводится текст или отображается графика. Аналогично тому как свойства Width и Height определяют размеры всей формы, свойства ClientWidth и ClientHeight типа Integer задают ширину и высоту (в пикселах) клиентской части формы.

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

    Обычно форму перетаскивают мышью, указатель которой устанавливается в любом месте области заголовка. При необходимости можно переместить форму и при помещении указателя на ее клиентскую область, для чего требуется описать соответствующие операции программно. Одним из способов является перехват системного сообщения WM_NCHitTest . Для этого создается процедура FormMove , которая анализирует, в каком месте формы находится указатель мыши при нажатии кнопки. Код местоположения указателя мыши содержится в поле Result системного сообщения типа TMessage. Если значение Result равно 1, что соответствует нажатию кнопки мыши в клиентской области, то полю Result присваивается новое значение, равное 2, имитирующее нахождение указателя мыши в области заголовка. В процедуре FormMove первая инструкция inherited осуществляет вызов предопределенного обработчика перехватываемого события.

    Чтобы указать среде Delphi, что процедура FormMove является обработчиком события WM_NCHitTest, при ее описании в классе формы TForm1 используется специальный синтаксис, включающий ключевое слово message . Как обработчик системного сообщения, процедура содержит один параметр типа TMessage.

    Имена MoveForm и Msg процедуры и ее параметра могут быть изменены.

    Свойство Menu

    Отображаемое формой меню задается свойством Menu типа TMainMenu. При разработке приложения размещение компонента MainMenu главного меню в форме вызывает автоматическое присвоение значения MainMenu1 свойству Menu. Это самый простой способ ссылки на главное меню. Если в ходе выполнения приложения какая-либо форма должна отображать различные меню, то через свойство Menu можно указать другое главное меню, например, следующим образом: Form1.Menu:= MainMenu2;

    Свойство Icon



    Каждая форма отображает в левой стороне области заголовка свой значок, определяемый свойством Icon типа Ticon. Если форма не является главной в приложении, то этот значок отображается при свертывании формы. Для любой формы свойство Icon можно задать с помощью Инспектора объектов или динамически (при выполнении приложения). Если значок не задан, то форма использует значок, указанный в свойстве Icon объекта Application. Последний выводится также при свертывании и отображении в панели задач Windows значка главной формы приложения.

    В вышеуказанной процедуре значок динамически загружается из файла Picture1.ico при создании формы Form1 .

    Свойство Position

    Размещение и размер формы при отображении определяет свойство типа TPosition. Оно может принимать значения, перечисленные далее:

    • poDesigned (форма отображается в той позиции и с теми размерами, которые были установлены при ее конструировании) - значение по умолчанию. Положение и размеры формы определяются свойствами Left, Tор, Width и Height . Если приложение запускается на мониторе с более низким разрешением, чем у того, на котором оно разрабатывалось, часть формы может выйти за пределы экрана;
    • poScreenCenter (форма выводится в центре экрана, ее высота и ширина- свойства Height и width- не изменяются);
    • poDefault (Windows автоматически определяет начальную позицию и размеры формы) - при этом значении программист не имеет возможности управлять этими параметрами, поэтому оно не допускается для форм многодокументных приложений;
    • poDefaultPosOnly (Windows определяет начальную позицию формы, ее размеры не изменяются);
    • poDefaultSizeOnly (Windows определяет начальные ширину и высоту формы и помещает форму в позицию, определенную при разработке);
    • PoDesktopCenter (форма выводится в центре экрана, ее высота и ширина не изменяются);
    • PoMainFormCenter (форма выводится в центре главной формы приложения, ее высота и ширина не изменяются) - это значение используется для вторичных форм, при применении его для главной формы оно действует как значение poScreenCenter;
    • PoOwnerFormCenter (форма выводится в центре формы, которая является ее владельцем, высота и ширина формы не изменяются) - если для формы не указан владелец (свойство Owner), то данное значение аналогично значению poMainFormCenter.

    Приложение может запоминать расположение и размеры форм и при последующем выполнении правильно отображать формы на экране. Для этого программист должен записать соответствующие данные в инициализационный файл приложения или в системный реестр Windows, а при последующем выполнении приложения считать эти данные и установить их для форм.

    Свойство Active

    Свойство Active типа Boolean позволяет определить активность формы. В любой момент времени активной может быть только одна форма, при этом ее заголовок выделяется особым цветом (обычно синим). Если свойство Active имеет значение True, то форма активна (находится в фокусе ввода), если False - то неактивна. Это свойство доступно для чтения во время выполнения программы. Если требуется активизировать форму программно, следует использовать свойство или метод Show (showModal).

    Cвойство ChildActiveForm

    В многодокументном приложении родительское окно не может быть активным независимо от цвета заголовка. Для определения активного дочернего окна многодокументного приложения служит свойство ChildActiveForm типа TForm родительской формы.

      procedure TForm1CheckFormActive модуля главной формы выполняет проверку активности для двух форм приложения и отображает соответствующую информацию в заголовках форм.

      Свойство WindowState

      Свойство типа TWindowstate определяет состояние отображения формы и может принимать одно из трех значений:

      • wsNormal (обычное состояние) - по умолчанию;
      • wsMinimized (свернута);
      • wsMaximized (развернута).

      Кнопки btnMiniForm и btnNormalForm в форме Form1 сворачивают и восстанавливают обычное состояние формы Form2 соответственно.

      Форма, для которой изменяется состояние отображения на экране, предварительно должна быть создана методами CreateForm или Create . Если форма не создана, то при обращении к ней будет сгенерировано исключение, несмотря на то, что переменная формы объявлена в модуле. Если форма создана, но не отображается на экране, то изменения ее состояния (свойства windowstate) происходят, однако пользователь не видит этого до тех пор, пока форма не будет отображена на экране.

      Свойство ActiveControl

      Будучи контейнером, форма содержит другие элементы управления. Оконные элементы управления (потомки класса TWinControl) могут получать фокус ввода. Свойство типа TWinControl определяет, какой элемент формы находится в фокусе. Для выбора элемента, находящегося в фокусе ввода (активного элемента), можно устанавливать это свойство в нужное значение при выполнении программы:

      Эту же операцию выполняет метод SetFocus , который устанавливает фокус ввода для оконного элемента управления:

      Свойство AutoScroll

      В случае, когда размеры окна недостаточны для отображения всех содержащихся в форме интерфейсных компонентов, у формы могут появляться полосы прокрутки. Свойство AutoScroll типа Boolean определяет, появляются ли они автоматически, Если свойство AutoScroll имеет значение True (по умолчанию), то полосы прокрутки появляются и исчезают автоматически, без каких-либо действий программиста. Необходимость в полосах прокрутки может возникнуть, например, в случае, если пользователь уменьшит размеры формы так, что не все элементы управления будут полностью видны. Если же свойство AutoScroll установлено в значение False, то программист реализует управление просмотром информации вручную через свойства HorzScrollBar (горизонтальная прокрутка) и VertScrollBar (вертикальная прокрутка) типа TControlScrollBar формы.

      Метод ScrollInView

      Для программного управления полосами прокрутки можно использовать метод ScrollInView . Процедура ScrollInView (AControl: TControl) автоматически изменяет позиции полос прокрутки так, чтобы заданный параметром AControl элемент управления стал виден в отображаемой области.

      Свойство KeyPreview

      Свойство типа Boolean определяет, будет ли форма обрабатывать события клавиатуры, прежде чем их обработают элементы управления формы. Если свойство имеет значение False (по умолчанию), то клавиатурные события поступают к активному элементу управления (имеющему фокус ввода). При установке свойства KeyPreview в значение True форма первой получает сообщения о нажатии клавиш и может на них реагировать, что обычно используется для обработки комбинаций клавиш, независимо от активности элементов управления формы.

      В вышеуказанной процедуре форма Form1 обрабатывает нажатие алфавитно-цифровых клавиш, отображая введенный символ в диалоговом окне Information .

      Форма не может обрабатывать нажатие клавиши <ТаЬ> в связи с ее особым назначением.

      Cвойство MDichildCount и метод Cascade

      У формы имеется ряд свойств и методов , например свойство MDichildCount и метод Cascade , предназначенных для организации многодокументных приложений.