Прикладное программирование в Lazarus: Учебное пособие [А. Ю. Беляков] (pdf) читать онлайн

Книга в формате pdf! Изображения и текст могут не отображаться!


 [Настройки текста]  [Cбросить фильтры]

Министерство сельского хозяйства Российской Федерации
Федеральное государственное бюджетное
образовательное учреждение
высшего образования
«Пермский государственный аграрно-технологический университет»
имени академика Д.Н. Прянишникова»

А.Ю. БЕЛЯКОВ

ПРИКЛАДНОЕ ПРОГРАММИРОВАНИЕ
В LAZARUS
Учебное пособие

Пермь
ФГБОУ ВО Пермский ГАТУ
2019

УДК 004.43
ББК 32.973-018.1
____
Рецензенты:
Рыбаков А.П. – профессор кафедры общей физики ПНИПУ, доктор физико-математических наук, профессор.
Шабуров А.С. – доцент кафедры автоматики и телемеханики ПНИПУ,
кандидат технических наук, доцент.
_-___

Прикладное программирование в Lazarus [Текст]: Учебное пособие / А.Ю. Беляков; М-во с.-х. РФ; ФГБОУ ВО Пермский ГАТУ. – Пермь: Изд-во ФГБОУ ВПО Пермский ГАТУ,
2019. –114 с.
ISBN _____________

Данное издание является базовым пособием по изучению основ
прикладного программирования в среде визуальной разработки приложений Lazarus. В пособии детально изложены принципы событийного
программирования и на практических примерах проанализированы некоторые приемы работы с визуальными компонентами. Пособие ориентировано на самостоятельное освоение материала с исследованием
программ в среде программирования Lazarus. Рассматриваемый материал требует первичного знания основ структурного и модульного программирования.
Пособие предназначено для студентов, обучающихся по направлению подготовки 09.04.03 Прикладная информатика.
УДК 004.43
ББК 32.973-018.1
Утверждено в качестве учебного пособия на заседании Методического
совета ФГБОУ ВО Пермский ГАТУ (протокол № __ от __.__.2019 г.).

ISBN _____________
© ИПЦ «Прокростъ», 2019
© Беляков А.Ю., 2019

Содержание
Введение...................................................................................

4

Глава 1. Модульное программирование ..........................

6

Глава 2. Событийное программирование ......................

22

2.1. Обработка событий мыши ..................................

22

2.2. Обработка событий клавиатуры ........................

33

2.3. Приоритет обработки нажатия клавиш ..........

42

2.4. Переменная Sender ................................................

49

Глава 3. Обработка файлов .................................................

54

3.1. Текстовые файлы ...................................................

54

3.2. Типизированные файлы ......................................

66

Глава 4. Обработка табличной информации ..................

76

4.1. Табличное представление данных ....................

76

4.2. Построение графиков функций .........................

85

Глава 5. Динамические компоненты ...............................

91

Глава 6. Динамические библиотеки ................................

96

Заключение .............................................................................

112

Библиографический список ...............................................

113

3

Введение
Современное программирование – это работа со множеством различных информационных технологий и технологий
программирования. Для понимания текущей ситуации в сфере
проектирования и реализации прикладных программ следует
иметь представление об истории развития технологий программирования и их предназначении.
В процессе формирования и совершенствования языков
программирования от низкоуровневых, предполагающих узкую специализацию и направленность на определенную архитектуру вычислительной машины, до языков высокого уровня,
близких к естественному языку общения и обладающих значительно большими и универсальными возможностями, появлялись всё новые наработки, упрощающие процесс создания и
последующего сопровождения прикладных программ. К основным технологическим вехам можно отнести: появление
именованных переменных, структурных операторов, подпрограмм, технологию модульного программирования, технологию объектно-ориентированного программирования, динамические библиотеки, событийное программирование, визуальное проектирование приложений, использование фреймворков и платформ исполнения программного кода.
Все перечисленные технологии в настоящее время используются в большинстве самых популярных языков программирования и, в той или иной степени, обеспечивают прикладное программирование (application programming). Определим прикладное программирование как как процесс проектирования, разработки и отладки программных приложений
определённой прикладной направленности, то есть ориентированных на выполнение определённых специфических задач,
4

в том числе, для автоматизации рутинных процессов пользователей в их повседневной работе за персональным компьютером.
Можно выделить, как минимум, две основные особенности приложений подобного рода:
– при разработке программы для непрофессионального
пользователя следует уделять больше внимания проработке
интерфейса пользователя, иногда даже в ущерб производительности и компактности приложения;
– нельзя выделить и ограничить некоторое подмножество необходимых технологий, компонентов для реализации
прикладных программ из-за разной их направленности в зависимости от профессиональной принадлежности заказчика или
возможного потребителя приложения.
Описанные обстоятельства предопределили основную
линию данного учебного пособия, состоящую в большом внимании к элементам взаимодействия пользователя с программой и данными. По ходу изучения материала, вы будете встречать описание новых и разнообразных по функционалу компонентов, обеспечивающих дополнительные возможности интерфейса пользователя. Для развития пользовательских функций мы не будет ограничиваться только визуальными (отображаемыми) компонентами, но также будем пользоваться таймером и его событиями, обработкой событий мыши и клавиатуры, обработкой исключительных ситуаций и специализированными настройками компонентов с помощью инспектора
объектов.

5

Глава 1. Модульное программирование
Приложение на этапе разработки состоит из нескольких
файлов (модулей, ресурсов, описаний визуальных форм, основной программы), которые представляют собой проект. После компиляции проекта будет создана сборка в один файл с
расширением *.exe. Для удобства работы с файлами проекта
для каждого нового приложения следует создавать отдельный
каталог. С помощью указанных на рис. 1 пунктов меню создайте новое приложение в среде Lazarus:

Рис.1. Окно выбора типа приложения.
Перейдите в окно кода программы, нажав клавишу F12
или кликнув по окну кода мышкой. Вы увидите текст модуля:

unit Unit1;

6

{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs;
type
TForm1 = class(TForm)
private
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
end.

Данное приложение уже работоспособно, его можно запустить на выполнение, нажав F9 или экранную клавишу пуск.
Его (окно приложения) можно подвигать, изменить размеры,
минимизировать, максимизировать, закрыть.
Для того чтобы правильно сохранить разрабатываемое
вами приложение, включая все модули и формы, следует выбрать пункт меню Файл / Сохранить всё (Shift+Ctrl+S) и последовательно сохранить все модули приложения и сам проект
в одну папку.
Обратим внимание на раздел подключения модулей. Ключевое слово Uses определяет начало списка модулей, которые
используются текущим модулем, программой или библиотекой. Следует заметить, что при создании нового приложения
Lazarus самостоятельно размещает несколько модулей в раз-

7

деле подключения модулей uses. Для такого простейшего приложения, которое вы только что запустили это количество избыточно. Попробуйте из раздела подключения модулей uses
удалить все модули за исключением Forms и снова запустите
программу.
Подключаемые модули, разрабатываемые программистом, имеют расширение ppu и представляют собой откомпилированный модуль проекта в промежуточном формате. Когда
компилируется программа, все модули компилируются в
файлы формата ppu, а потом собираются в один исполняемый
exe файл. Если модуль не изменялся с последней компиляции,
то Lazarus пропустит его, а во время сборки будет использовать существующий файл формата ppu, чтобы сократить время
компиляции. Загляните в папку, где вы сохранили свой проект
(в директорию \lib\x86_64-win64), и вы обнаружите файл, совпадающий по имени с модулем вашего проекта unit1, но с расширением ppu. Проведите эксперимент – запустите программу (F9) без внесения изменений в ваш модуль и убедитесь, что время создания файла unit1.ppu не изменилось, затем
закройте запущенную программу и подвиньте немного мышкой форму Form1, после чего вновь запустите программу –
убедитесь, что теперь был создан новый файл unit1.ppu.
При необходимости расширить функциональные возможности приложения, нужно подключать в разделе uses дополнительные модули, однако не обязательно их прописывать
вручную. При добавлении на форму визуального компонента
из библиотеки компонентов редактор Lazarus самостоятельно
добавляет необходимые модули в раздел uses. Например, при
добавлении такого компонента как стандартная экранная клавиша Button, в раздел uses добавляется модуль StdCtrls. Вы можете самостоятельно провести такой эксперимент. Добавить
компонент на форму в среде визуального программирования
8

просто: кликните на соответствующую иконку компонента –
она станет активной, затем кликните в том месте формы, где
хотите компонент разместить, он там и окажется.
Начнем с того, что добавим на форму кнопку Button1,
иконка этого компонента располагается на вкладке Standart
(рис. 2).

Рис.2. Панель стандартных компонентов.
Запустите программу на выполнение – она работает,
кнопка нажимается, но пока не выполняет никаких действий,
так как мы и не задали никаких обработчиков событий. Однако все эти новые возможности стали доступны благодаря
тому, что Lazarus самостоятельно подключил необходимые
модули из списка стандартных – обратите внимание вновь на
раздел uses. Но, не редкость, возникновение таких ситуаций,
когда программисту приходится самостоятельно прописывать
подключаемый модуль, что характерно для модулей, не обслу-

9

живающих работу визуальных компонентов. К таким, например, относятся модули Math (содержит математические функции) или SysUtils (делает доступными множество подпрограмм манипулирования данными, таких как IntToStr).
Убедимся в этом при проведении простого эксперимента.
Остановите работу (закройте) вашей программы, если еще
этого не сделали. Добавьте на форму ещё один компонент –
однострочное редактируемое текстовое поле – Edit1 (рис. 3).

Рис.3. Выбор и настройка компонента.
Обратите внимание, что в среде визуального проектирования приложений сведены к минимуму действия программиста
по ручной настройке приложения – автоматически добавляются не только необходимые для работы модули, но и сама
настройка компонентов может производиться с помощью визуальных средств. Попробуйте поэкспериментировать с
настройкой поля Edit1 через вкладку «Свойства» в окне Инспектора объектов, например, установите размер шрифта,
настройте цвет фона или выравнивание текста. Кроме того,
среда визуально проектирования приложений помогает писать
программный код, автоматически создавая шаблоны процедур
10

или выдавая контекстные подсказки о правильности написания идентификаторов переменных или названий подпрограмм
в зависимости от допустимости их использования в месте расположения курсора.
Кликните два раза на кнопке Button1, на что Lazarus отзовется созданием процедуры обработчика события – «клик по
кнопке», при этом автоматически добавив (вернув на место)
модуль Classes в раздел uses:
procedure TForm1.Button1Click(Sender: TObject);
begin
end;

Начнём набирать программный код:

Рис.4. Контекстная подсказка.
Обратите внимание, что по мере набора кода Редактор
предлагает подходящие в данной ситуации свойства или методы, которые можно не набирать полностью, а ввести нажатием клавиши Enter. Контекстную подсказку можно вывести
на экран также сочетанием клавиш Ctrl+Пробел.
Заполним полностью кодом обработчик Button1Click:

11

procedure TForm1.Button1Click(Sender: TObject);
begin
Edit1.Text:=5;
end;

Предполагая, что по нажатию клавиши Button1 в текстовое поле будет выведена цифра 5. Сделаем попытку запуска
нашей программы на выполнение (F9 – компиляция и запуск
или Ctrl+F9 – только компиляция без запуска программы на
исполнение, что удобно использовать для проверки корректности синтаксиса кода).
Попытка запуска закончится неуспешно – редактор сигнализирует про несовместимые типы строковый и целочисленный, а также про невозможность откомпилировать модуль (вы
сейчас пишете код программы в модуле unit1). Действительно,
текстовое поле оно потому текстовое, что предназначено для
отображения строк. Внесем следующие изменения – сделаем
обрамление из одинарных кавычек ‘5’ (так в языке программирования Pascal обозначают строки):
procedure TForm1.Button1Click(Sender: TObject);
begin
Edit1.Text:=’5’;
end;

и запустим программу. Работает. Однако, если в программе задумана какая-то обработка данных, то хранить их, видимо,
придется все-таки в более подходящем – нетекстовом виде.
Значит, в момент вывода результата вычислений в текстовое
поле, следует полученное значение преобразовать из текстового в числовой формат. Для этих целей подойдут функции
12

модуля SysUtils – IntToStr (для целых чисел) и FloatToStr (для
вещественных чисел).
Как узнать о формате подпрограммы и посмотреть примеры ее использования? Наберите в окне кода модуля Unit1 в
любом месте такой текст: IntToStr, оставьте курсор где-то в
пределах IntToStr и нажмите F1 (таким способом можно
узнать много полезной информации и про другие функции).
Откроется справка:
IntToStr
Convert an integer value to a decimal string.
Declaration
function IntToStr(Value: LongInt):string;
function IntToStr(Value: Int64):string;
function IntToStr(Value: QWord):string;

из которой станет ясно, что аргументом этой функции является переменная целого типа, а результатом строковая переменная. Кроме того, наличие трёх описаний (деклараций)
функции указывает, что эта она относится к перегружаемым
подпрограммам. Наличие механизма перегрузки подпрограмм
позволяет реализовывать подпрограммы с разной сигнатурой,
то есть выполняющие одинаковые действия на основе параметров разных типов или различного их количества. Это упрощает работу программиста, унифицирует программный код,
отменяет необходимость приведения параметров к конкретным типам данных. Для того чтобы компилятор мог выбрать
правильную подпрограмму из нескольких перегруженных,
они должны отличаться хоть чем-то в сигнатуре метода,
например, последовательностью типов данных в списке параметров, их количеством или самим типом данных. В данном
случае, в качестве параметра функции IntToStr может использоваться данное типа Integer, Int64 или QWord (первые два знаковые, последнее целое без знака, то есть только положительное, о числовых типах данных см. Приложение II).
13

Для приведения программы к корректному виду внесем
соответствующие изменения:
procedure TForm1.Button1Click(Sender: TObject);
begin
Edit1.Text:=IntToStr(5);
end;

Запустим программу на выполнение … и опять не получим желаемого результата – оказывается идентификатор
IntToStr не задекларирован. В чем же проблема? Вернемся к
тому с чего начинали – Lazarus не всегда самостоятельно подключает необходимые стандартные модули. В данном случае
не было добавления на форму визуального компонента и связанного с этим автоматического добавления необходимого модуля/модулей в список подключаемых модулей в раздел uses,
поэтому чтобы добиться положительного результата следует
самостоятельно добавить в раздел uses модуль SysUtils. Самостоятельно впишите необходимый модуль в список подключённых и заново проверьте работоспособность программы.
Чтобы в дальнейшем не испытывать затруднений при
усложнении программы давайте вернем все заявленные по
умолчанию модули в разделе uses на место:
uses
Forms, StdCtrls, Classes, SysUtils,
FileUtil, Controls, Graphics, Dialogs;

Если в дальнейшем нам нужно будет создавать многооконное приложение, наподобие самой среды Lazarus, то
нужно уметь передавать значения между формами приложе14

ния. Обратите внимание, что для каждой формы автоматически создаётся свой модуль, совпадающий по идентификатору
с именем формы. Таким образом, для того чтобы пользоваться
возможностями новой/другой формы, необходимо соответствующий ей модуль подключить в разделе uses.
Давайте попробуем создать первое многооконное приложение, для чего через главное меню выберите пункт «Файл» /
«Создать форму». Сохраните её в ту же папку, что и основное
приложение, пока, не меняя имя, данное по умолчанию
(Unit2.pas). На вторую форму поместите компонент Edit1, он
будет иметь такое же имя, как и текстовое поле с первой
формы. Для того чтобы выбрать место куда именно будет записываться результат, достаточно только указать предварительно имя контейнера, содержащего тот или иной компонент,
например, так (Form2.Edit1.Text):
procedure TForm1.Button1Click(Sender: TObject);
begin
Form2.Edit1.Text:=IntToStr(5);
end;

Однако попытка запуска такой программы не закончится
успешно, так как модуль первой формы не знает о существовании второй формы. Чтобы преодолеть данное затруднение
достаточно просто в разделе подключения модулей указать соответствующий идентификатор модуля (Unit2):

uses
Forms, StdCtrls, Classes, SysUtils,
FileUtil, Controls, Graphics, Dialogs, Unit2;

15

После внесения изменений программа должна запуститься, но при нажатии на экранную клавишу Button1 вы не
увидите желаемого результата. Причина этого кроется в том,
что никто не указал, что должна отображаться сама форма
Form2. Окончательно оформленный код выглядит следующим
образом:
procedure TForm1.Button1Click(Sender: TObject);
begin
Form2.Edit1.Text:=IntToStr(5);
Form2.Show;
end;

Следует отметить, что модули могут создаваться не
только совместно с соответствующими экранными формами,
но и отдельно. Как правило, в таких модулях располагают библиотеку подпрограмм, для выполнения часто использующихся задач. К таким задачам можно отнести: конвертацию
данных, математические методы обработки данных, обработку массивов данных, вычислительные задачи и т.п.
Для уточнения порядка разработки модуля и подключения
подпрограмм разработаем небольшой модуль, решающий задачу перевода двоичного числа в десятичное двумя видами
подпрограмм – процедурой и функцией, а также апробируем
технологию создания перегружаемых подпрограмм.
Создайте новое приложение в среде Lazarus и сохраните
его в отдельной папке. Подготовьте интерфейс приложения,
добавив два поля Edit (для ввода/вывода информации) и три
кнопки Button для запуска подпрограмм, отличающихся сигнатурами (рис. 5).

16

Рис.5. Внешний вид программы для перевода чисел.
Наименование у всех подпрограмм будет одинаковое –
binToDec, но количество аргументов, их типы данных и способ возвращения результата в основную программу будет отличаться. Первая подпрограмма – функция, которая принимает строковый аргумент и возвращает ответ в виде строки,
вторая подпрограмма тоже функция, но работающая с целыми
числами и, наконец, третья подпрограмма – процедура, которая работает с целыми числами и возвращает ответ не через
своё имя, а через дополнительный аргумент. Названия кнопок
на форме соответствуют логике работы подпрограмм.
Все подпрограммы разместим в специальном модуле Utils
(название можно дать любое, осмысленное), для чего в главном меню Lazarus выберите пункт «Файл» / «Создать модуль».
Сгенерированный модуль имеет стандартную для модулей
структуру: заголовок (имя даётся автоматически по умолчанию), интерфейсная часть (где декларируются подпрограммы,
видимые вне данного модуля внешней программой), раздел
подключения модулей и часть реализаций (где описывается
содержательная часть подпрограмм):
17

unit Unit2;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
implementation
end.

Прежде всего, сохраните модуль в ту же папку, где хранятся файлы приложения и, при сохранении смените имя на
Utils. В первом модуле Unit1, который работает с формой, подключите модуль Utils в разделе подключения модулей:
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls,
Graphics, Dialogs, StdCtrls, Utils;

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

если есть варианты подпрограмм, соответствующим образом
оформленные:
unit Utils;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
function binToDec(bin: integer): integer; overload;
function binToDec(bin: string): string; overload;
procedure binToDec(bin: integer; var dec: integer);
implementation
procedure binToDec(bin: integer; var dec: integer);
begin
dec:=binToDec(bin);
end;
function binToDec(bin: integer): integer; overload;
var dec, step, tmp, last: integer;
begin
dec:=0; // десятичное число
step:=1; // значение 2 в степени
tmp:=bin; // для хранения убывающего числа
while tmp>0 do
begin
last:=tmp mod 10; // последняя цифра в числе
tmp:=tmp div 10; // число без последней цифры
dec:=dec+last*step; // цифра * на 2 в степени pos
step := step * 2; // значение 2 в степени для следующего
разряда
end;
result:=dec;
end;
function binToDec(bin: string): string; overload;
var i, dec, step: integer;
begin
dec:=0; // десятичное число
step:=1; // значение 2 в степени
for i:=Length(bin) downto 1 do
begin
dec:=dec+StrToInt(bin[i])*step;
step := step shl 1;
end;
result:=IntToStr(dec);
end;
end.

19

Обратите внимание, что модификатор вызова overload не
является обязательным, а оставлен в Lazarus для совместимости с Lazarus.
Итак, у нас есть три подпрограммы, выполняющие одинаковую задачу перевода числа из двоичной системы счисления
в десятичную, но разными способами. Вы, конечно, заметили,
что в коде процедуры
procedure binToDec(bin: integer; var dec: integer);

идёт вызов функции
function binToDec(bin: integer): integer; overload;

из самого же модуля и не содержится самого алгоритма перевода числа. Это самый обычный приём, имеющий логическое
обоснование. И, действительно, зачем писать код решения задачи повторно, когда он уже есть в соседней подпрограмме.
Но внешний пользователь данного модуля этого не знает, однако имеет возможность пользоваться тем видом подпрограммы, которым ему удобнее в его программе. Основываясь
на полученных знаниях, попробуйте самостоятельно сократить текст модуля, упростив функцию:
function binToDec(bin: string): string; overload;

Содержание этой функции нужно вычеркнуть и заменить
ссылкой на функцию, работающую с целыми числами по аналогии с вышеописанным.
Осталось только корректно, с учётом типов данных, подключить подпрограммы модуля к соответствующим экранным
клавишам на форме приложения, заполнив содержимое первого модуля:
procedure TForm1.Button1Click(Sender: TObject);
begin
Edit2.Text:=binToDec(Edit1.Text);
end;
procedure TForm1.Button2Click(Sender: TObject);

20

var bin, dec: integer;
begin
bin:=StrToInt(Edit1.Text);
dec:=binToDec(bin);
Edit2.Text:=IntToStr(dec);
end;
procedure TForm1.Button3Click(Sender: TObject);
var bin, dec: integer;
begin
bin:=StrToInt(Edit1.Text);
binToDec(bin, dec);
Edit2.Text:=IntToStr(dec);
end;

Апробируйте программу, добейтесь её работоспособности и опишите для себя разницу в использовании процедур и
функций.
Сохраните текущие изменения в программе нажатием
клавиш Ctrl+S, в дальнейшем не забывайте периодически производить сохранения во избежание случайных потерь кода.
После первичного ознакомления с технологией визуального
проектирования приложений и модульного программирования в среде Lazarus можно переходить к технологии событийного программирования.

21

Глава 2. Событийное программирование
Ещё одна технология, которая значительно облегчает труд
программиста – событийное программирование. Основной
принцип в событийном программировании заключается в разбиении всей программы на отдельные, имеющие конкретное
предназначение подпрограммы, которые запускаются на исполнение только при наступлении определённого, заранее заданного события. События могут быть как реальными (нажатие сочетания клавиш, двойной клик мышкой), так и виртуальными (изменение размеров экранной формы, запрос на закрытие программы). Не во всех случаях имеет смысл строить программу, основанную на обработке событий. Тем не менее, есть
ряд направлений, где событийное программирование особенно востребовано:
– написание игровых программ со значительным количеством управляемых объектов;
– разработка прикладных программ с пользовательским
интерфейсом;
– создание серверных приложений с ограничением по генерации обслуживающих процессов;
Разберём подробнее наиболее актуальные события, встречающиеся в интерфейсах прикладных программ.
2.1. Обработка событий мыши.
Lazarus позволяет обрабатывать различные события манипулятора «мышь»: одиночный клик левой, средней или правой
клавишей, дополнительные боковые клавиши мыши, двойной
клик левой клавишей мыши; движение указателя мыши, про-

22

крутка колёсика мыши и т.п. Наличие обработчиков и их возможности зависят от компонентов (форма, кнопка, текстовое
поле и др.), к которым привязаны обработчики событий.
Рассмотрим некоторые из событий мыши и попрактикуемся настраивать соответствующие обработчики на разрабатываемом нами приложении.
Создадим обработчик события – движение указателя по
второй форме приложения. Пусть координаты указателя
мыши во время движения отображаются в текстовом поле
Edit1 (принадлежащего Form2).
Чтобы перейти к нужной форме нажмите сочетание клавиш Shift+F12 (к нужному модулю – Ctrl+F12), выберите
Form2, выделите её кликом мыши один раз и в инспекторе
объектов (Object Inspector) станут доступными для редактирования свойства (Properties) и события (Events), доступные для
выделенного объекта (сейчас это Form2). В данный момент
нас интересуют события мыши. Найдите в списке событий в
левом столбце событие OnMouseMove и кликните два раза по
правому (пустому) полю. Ваше действие приведет к декларации процедуры обработчика события движение мыши по
форме (рис.6) и генерации шаблона кода процедуры:
procedure
TForm2.FormMouseMove(Sender:
TShiftState; X, Y: Integer);
begin

TObject;

Shift:

end;

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

procedure
TForm2.FormMouseMove(Sender:
TObject;
TShiftState; X, Y: Integer);
begin
Edit1.Text:=IntToStr(X)+':'+IntToStr(Y);
end;

Shift:

Рис.6. Автоматическая декларация процедуры обработчика события.
Теперь создадим процедуру, которая будет нам сообщать
какой клавишей мыши кликнул пользователь по форме. Разместите на форме компонент Label с вкладки Standard и
настройте его свойства по своему усмотрению. Сгенерируйте
для формы Form2 обработчик события OnMouseDown. Обратите внимание на переменную Button – она содержит наименование нажатой клавиши мыши и имеет тип TMouseButton.
Как же узнать какие именно значения она может приобретать?
Для этого нажмите и удерживайте клавишу Ctrl и наведите
указатель мыши на описание типа в процедуре
(TMouseButton), которое приобретет вид гиперссылки. Клик24

ните на ней и Lazarus откроет вам программный код с описанием модуля Controls, в котором вы и увидите перечисление
значений типа в круглых скобках:
TMouseButton = (mbLeft, mbRight, mbMiddle, mbExtra1,
mbExtra2);

Закройте модуль Controls, кликнув правой клавишей
мыши по его заголовку и выбрав опцию Закрыть вкладку или
просто кликнув средней клавишей мыши.
Заполним процедуру программным кодом, который будет
обеспечивать вывод наименования нажатой клавиши в метку
Label1:
procedure
TForm2.FormMouseDown(Sender:
TObject;
TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
with Label1 do
case Button of
mbLeft:
Caption:='левая';
mbMiddle: Caption:='средняя';
mbRight: Caption:='правая';
mbExtra1: Caption:='дополнительная вперёд';
mbExtra2: Caption:='дополнительная назад';
end;
end;

Button:

Оператор объединения with в процедуре позволяет избежать излишнего дублирования программного кода и не писать
каждый раз Label1.Caption.
Событие OnMouseDown возникает в момент нажатия клавиши мыши, а событие OnMouseUp в момент её отпускания.
Сгенерируйте процедуру FormMouseUp и заполните кодом:
procedure TForm2.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Label1.Caption:=Label1.Caption+' отпущена';
end;

25

Испытайте её следующим образом: кликните мышкой по
форме и удерживайте её нажатой, оцените содержимое поля
Label1, затем отпустите клавишу мыши и посмотрите на изменения. Доработайте код процедуры, используя оператор with.
Теперь поработаем немного с колесиком мыши. Пусть от
вращения колёсика зависит положение метки Label1 по вертикали. Сгенерируйте процедуры FormMouseWheelDown и
FormMouseWheelUp и заполните их кодом:
procedure TForm2.FormMouseWheelDown(Sender: TObject; Shift:
TShiftState; MousePos: TPoint; var Handled: Boolean);
begin
if Label1.Top0 then Label1.Top:=Label1.Top-1;
end;

Shift:

Доработайте процедуры, используя оператор with.
Оцените возможности перемещения метки Label в пределах формы. Вы обнаружите, что при движении вверх метка
упирается в верхнюю границу формы, а при движении вниз –
пересекает её и уходит за пределы формы. Постарайтесь оценить, в чём некорректность написанного ранее кода и самостоятельно исправьте ошибку.
Обратите внимание, что процедуры содержат переменную
Shift. Она содержит комбинацию нажатых управляющих клавиш (Ctrl, Alt, Shift) в момент вращения колёсиком мыши (и
других событий мыши). Посмотрите самостоятельно описание
типа TShiftState и определите, какие значения может принимать переменная такого типа. Использование управляющих
клавиш позволяет разнообразить возможности разрабатывае26

мой процедуры. Пусть вращение колесика мыши будет двигать метку Label1 слева-направо, если при этом удерживается
в нажатом состоянии клавиша Ctrl; сверху-вниз при удержании клавиши Alt; по диагонали – при удержании сразу обеих
клавиш.
procedure TForm2.FormMouseWheelDown(Sender: TObject;
TShiftState; MousePos: TPoint; var Handled: Boolean);
begin
with Label1 do
begin
if Shift = [ssCtrl] then
if Left