Глава 3

ОСНОВЫ ВИЗУАЛЬНОГО ПРОГРАММИРОВАНИЯ

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

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

3.1. ПУСТАЯ ФОРМА И ЕЕ МОДИФИКАЦИЯ

Как уже говорилось, окно формы содержит проект Windows-окна программы. Важно помнить, что с самого начала работы над новой программой Delphi создает минимально необходимый код, обеспечивающий ее нормальное функционирование в Windows. Таким образом, простейшая программа готова сразу после выбора опции File | New | Application, и нам остается просто запустить програм-му. Однако до этого советую выполнить две важные вещи: создать собственный рабочий каталог (папку) и нужным образом настроить Delphi.

3.1.1. Настройка Delphi

В процессе работы над проектами программ, описываемых в этой книге, вам понадобится создать множество форм и модулей. Полезно сохранять эти данные в виде дисковых файлов в отдельной папке. Более того, для каждой программы в этой папке имеет смысл создать свою вложенную папку. Тогда, чтобы освободить место на диске для серьезной программы, вам будет достаточно уничтожить основную папку, а чтобы передать ту или иную учебную программу своему коллеге - переписать на дискету содержимое соответствующей вложенной папки. Создайте папку с именем, например, my_delph, а в нем - вложенную папку для вашей первой программы. Чтобы не утруждать себя придумыванием подходящих имен для “безликих” учебных программ, советую использовать для папки имя pgm_1 или что-нибудь подобное.

Второе, что нам предстоит сделать, - это внести изменения в стандартную настройку среды Delphi. Это необходимо для того, чтобы среда автоматически сохраняла на диске последнюю версию создаваемой вами программы. Выберите опцию меню Tools | Environment options и убедитесь, что в появившемся диалоговом окне активна страница preferences. В левом верхнем углу этой страницы в группе Autosave | Options есть переключатели Editor Files и Desktop (в других версиях Delphi эти переключатели располагаются в правом верхнем углу). Активизация переключателей приведет к автоматическому сохранению текста окна кода программы и общего расположения окон Delphi перед началом очередного прогона создаваемой программы, что избавит вас от возможных потерь в случае “зависания” программы. Советую активизировать эти переключатели, щелкнув по каждому мышью. Чтобы следить за ходом компиляции, активизируйте также переключатель Show Compiler progress в группе Compiling and Running. Далее, мне кажется полезным сохранять в коде программы комментарии - текстовые фрагменты, которые не влияют на работу программы, но делают ее текст более понятным. Если вы, как и я, предпочитаете использовать комментарии на русском языке, следует выбрать соответствующий шрифт для отображения кода программы. По умолчанию редактор Delphi использует шрифт Courier New, в котором может не быть символов кириллицы. В этом случае выберите опцию Tools | Editor options и на странице Display в строке Editor Font установите Courier New Cyr (для предыдущих версий страница Display доступна в окне Tools | Environment Options).

Теперь все готово для прогона вашей первой программы. Щелкните мышью по кнопке в главном окне или, что проще, нажмите клавишу F9: именно таким способом подготовленная Delphi-программа последовательно проходит три главных этапа своего жизненного цикла - этапы компиляции, компоновки и исполнения. На этапе компиляции осуществляется преобразование подготовленного в окне кода текста программы на языке Object Pascal в последовательность машинных инструкций, на этапе компоновки к ней подключаются необходимые вспомогательные подпрограммы, а на этапе исполнения готовая программа загружается в оперативную память и ей передается исполнение.

Как только вы нажмете F9, появится диалоговое окно Save Unit1 As, в котором Delphi попросит вас указать имя файла для модуля Unit1. раз и папку его размещения.

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

Лучше не идти на поводу у Delphi и не соглашаться с предложенным именем Unit1.раs, а присвоить модулю какое-нибудь более запоминающееся имя. Например, назовем модуль my_ist_u, что, по мысли автора, должно расшифровываться как “мой_первый_модуль” | разумеется, вам в голову может прийти более подходящее имя). Если в окне Save Uniti As вы укажете такое имя и нажмете Enter, Delphi попросит задать имя еще и для проекта программы в целом. Под этим именем будет создан исполняемый ЕХЕ-файл, и здесь нет предела для вашей изобретательности, например, firstpgm - вполне достойное имя для вашей первой Delphi-программы.

3.1.2. Имена в Delphi

Поскольку речь зашла об именах, я должен объяснить свою странную приверженность к сокращенным англоязычным именам. Дело в том, что Delphi принципиально не признает ни русских, ни французских, ни китайских, ни вообще каких бы то ни было имен, в которых используются символы, отличные от латинских букв. цифр и знака подчеркивания, причем имя не должно начинаться цифрой, но может начинаться знаком подчеркивания. Так как в этом перечне нет пробела, имена не могут также состоять из нескольких слов. Далее, сокращения до не более чем 8 символов - это дань ограничениям Delphi версии 1. Эта версия рассчитана на работу под управлением Windows З.х, которая не признает длинных имен файлов. Если вы работаете с Delphi 32 (т. е. с любой из версий от 2-й до 6-й), можете не сокращать имена и написать my_first_unit или даже moy_pervij_modul, потому что эти версии рассчитаны на современные 32-разрядные операционные системы, разрешающие использовать длинные имена файлов.

Если вы тем или иным способом решили проблемы с именами модуля и программы, на экране появится окно вашей формы, как и следовало ожидать - пустое, но обладающее всеми атрибутами нормального Windows-окна: оно может изменять свое положение и размеры и, закрываясь, выгружает программу из оперативной памяти ПК.

3.1.3. Изменение свойств формы

Итак, первый и самый простой шаг в Delphi-программировании вами уже сделан: вами создана нормальная Windows-программа. Разумеется, эта программа не реализует придуманного вами алгоритма, она вообще ничего путного не умеет делать, но это не беда! Впереди много времени и эта толстая книга, в которой как раз и рассказывается о том, как заставить вашу программу делать что-нибудь стоящее.

Теперь попробуем разобраться с тем, что такое модуль. В первом приближении мы можем считать модулем самостоятельный раздел программы, в чем-то подобный главе в книге. Модуль создается каждый раз, когда вы создаете новую форму (в программе может быть и, чаще, бывает не одна, а несколько - иногда несколько десятков форм и связанных с ними модулей). При компиляции программы Delphi создает файлы с расширениями pas, dfm и оси для каждого модуля: pas-файл содержит копию текста из окна кода программы, в файле с расширением dfm хранится описание содержимого окна формы, а в оси-файле - результат преобразования в машинные инструкции текста из обоих файлов. Файлы dcu создаются компилятором и дают необходимую базу для работы компоновщика, который преобразует их в единый загружаемый файл с расширением ехе.

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

(Заголовок) окна Инспектора объектов [ Это окно не видно в момент прогона программы. Если после нажатия на клавишу F11 окно Инспектора объектов не появилось на экране, проверьте состояние панели задач Windows - вы наверняка увидите в ней имя вашей программы. Закроите ее.]. Теперь правая колонка этой строки с текстом Form1 выделена цветом и справа от выделенного виден текстовый мигающий курсор. Переключите клавиатуру в режим ввода кириллицы и введите Моя первая программа, после чего еще раз нажмите F9. Новый прогон программы создаст окно с заголовком “Моя первая программа”, что несет в себе гораздо больше информации, чем просто Form1.

Итак, простым изменением содержимого строки в окне Инспектора объектов мы добились важной перемены: изменили одно из свойств окна программы - его заголовок. Таким же образом можно изменять любое другое свойство формы.

3.2. РАЗМЕЩЕНИЕ НОВОГО КОМПОНЕНТА

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

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

Новый компонент имеет стандартное имя Label1, и надпись на нем повторяет это имя. Изменим эту надпись: с помощью строки Caption окна Инспектора объектов введите надпись: я программирую на Delphi. Как только вы начнете вводить новую надпись, вид ком-понента на форме начнет меняться, динамически отражая все изменения, производимые вами в окне Инспектора объектов.

Выделим надпись цветом и сделаем ее шрифт более крупным. Для этого щелкните мышью по свойству Font окна Инспектора объектов и с помощью кнопки в правой части строки раскройте диалоговое окно настройки шрифта. В списке size (Размер) этого окна выберите высоту шрифта 24 пункта [Пункт - 1/72 дюйма, т. е. приблизительно 0,04 мм. Таким образом, 24 пункта означает высоту шрифта чуть более 9 мм.], а с помощью списка Color (Цвет) выберите нужный цвет (например, красный), после чего закройте окно кнопкой ок.

Рис. 3.1. Размещение компонента Label

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

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

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

Замечу, что все видимые компоненты[В Delphi могут использоваться как видимые, так и невидимые компоненты. Невидимые компоненты не имеют визуального отображения на этапе прогона программы.] имеют свойства Left (Слева), тор (Сверху), width (Ширина) и Height (Высота), числовые значения которых определяют положение левого верхнего угла компонента и его размеры в так называемых пикселях, т. е. в минимальных по размеру точках экрана, светимостью которых может управлять программа. При буксировании компонента или изменении его размеров мышью эти значения автоматически меняются и наоборот - изменение этих свойств в окне Инспектора объектов приводит к соответствующему изменению положения и размеров компонента. В Delphi 4, 5 и 6 значения Left и тор автоматически появляются в небольшом окне рядом с указателем мыши при буксировке компонента по форме.

3.3. РЕАКЦИЯ НА СОБЫТИЯ

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

3.3.1. Модификация формы

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

Компонент кнопка изображается пиктограммой на странице standard палитры компонентов. Поместите этот компонент на форму и расположите его ниже метки и посередине формы (рис. 3.2).

3.3.2. Обработчик события OnClick

При щелчке по кнопке мышью в работающей программе возникает событие OnClick. (По щелчку). Пока это событие никак не обрабатывается программой, и поэтому “нажатие” кнопки не приведет ни к каким последствиям. Чтобы заставить программу реагировать на нажатие кнопки, необходимо написать на языке object pascal фрагмент программы, который называется обработчиком события.

Рис. 3.2 Форма со вставленной кнопкой

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

Чтобы заставить Delphi самостоятельно сделать заготовку для процедуры обработчика события OnClick, дважды подряд без заметной паузы щелкните мышью по вновь вставленному компоненту[У начинающего пользователя Windows не всегда получается двойной щелчок. Этот нехитрый прием широко используется и в Windows, и в Delphi, так что вам придется потренироваться в его освоении: без него Delphi не вставит заготовку процедуры, и вам понадобится самостоятельно писать не только этот текст, но и производить дополнительные манипуляции с Инспектором объектов и окном кода.]. В ответ Delphi активизирует окно кода, и вы увидите в нем такой текстовый фрагмент:

procedure TFormI.ButtonlClick(Sender: TObject);

begin

end;

Попробуем разобраться в том, что он содержит. Слово procedure извещает компилятор о начале подпрограммы-процедуры (в Delphi могут использоваться также подпрограммы-функции; в этом случае вместо procedure (процедура) используется слово function (функция); разницу между процедурами и функциями мы обсудим позже). За ним следует имя процедуры TFormi.ButtonlClick. Это имя - составное: оно состоит из имени класса TForm1 и собственно имени процедуры Button1Click.

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

Каждый компонент принадлежит к строго определенному классу, а все конкретные экземпляры компонентов, вставляемые в форму, получают имя класса с добавленным числовым индексом. По используемому в Delphi соглашению все имена классов начинаются с буквы Т. Таким образом, имя TFormi означает имя класса, созданного по образцу стандартного класса TForm. Если вы посмотрите начало текста в окне кода, то увидите следующие строки:

type

TFormi = class(TForm)

Button1: TButton;

Label1: TLabel;

procedure ButtonlClick(Sender: TObject);

private

{ Private declarations }

public

{ Public declarations }

end;

varForm1: TForm1;

Строка

TForm1 = class(TForm)

определяет новый класс Tform1, который порожден от (создан по образцу) стандартного класса TForm. Строка

Form1: Tform1;

создает экземпляр этого класса с именем Formi. Стандартный класс TForm описывает пустое Windows-окно, в то время как класс TFormI описывает окно с уже вставленными в него компонентами метка и кнопка. Описание этих компонентов содержат строки

Button1: TButton;

Label 1: TLabel;

Они указывают, что компонент Buttoni (Кнопка!) представляет собой экземпляр стандартного класса TButton, а компонент Label 1 (Метка 1) - экземпляр класса TLabel.

За именем процедуры TFormi. Buttoniciick в круглых скобках следует описание параметра вызова

Sender: TObject

(параметр с именем Sender принадлежит классу TObject). Как мы увидим дальше, процедуры могут иметь не один, а несколько параметров вызова или не иметь их вовсе. Параметры вызова (если они есть) служат для настройки реализованного в процедуре алгоритма на выполнение конкретной работы. Параметр Sender вставлен Delphi “на всякий случай”: с его помощью подпрограмма Button1Click может при желании определить, какой именно компонент создал событие OnClick. Вся строка в целом

procedure TFormI.Buttoniciick(Sender: TObject);

называется заголовком процедуры. Ее завершает символ “;”. Этот символ играет важную роль в Object Pascal, т. к. показывает компи-- лятору на конец предложения языка. Из отдельных предложений составляется весь текст программы. В конце каждого предложения нужно ставить точку с запятой - это обязательное требование синтаксиса языка.

Три следующие строки определяют тело процедуры:

begin

end;

Слово begin (начало) сигнализирует компилятору о начале последовательности предложений, описывающих алгоритм работы процедуры, а слово end (конец) - о конце этой последовательности. В нашем случае тело процедуры пока еще не содержит описания каких-либо действий, что и неудивительно: Delphi лишь создала заготовку для процедуры, но она ничего “не знает” о том, для чего эта процедура предназначена. Наполнить тело нужными предложениями -задача программиста.

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

Чтобы убедиться в этом, сделаем нашу кнопку “звучащей”: напишите в пустой строке между словами begin...end следующее предложение:

MessageBeep (МВ_ОК);

и сделайте прогон программы[Если вы работаете с версией Delphi 1, используйте строку MessageBeep (0);], предварительно включив звуковую систему компьютера. Теперь в ответ на нажатие кнопки Button1 в динамике компьютера будет раздаваться звуковой сигнал, т. к. вставленная строка реализует обращение к стандартной процедуре, которая умеет извлекать из динамика различные стандартные для Windows звуки.

3.3.3. Динамическое изменение свойств компонента

Поскольку кнопка Buttoni в нашей программе способна “звучать”, полезно изменить ее надпись: вместо умалчиваемой надписи Buttoni, которую автоматически формирует Delphi по имени компонента, назовем кнопку, например, “Звук”. Проще всего это сделать с помощью окна формы и Инспектора объектов, т. е. на этапе конструирования формы (для этого нужно просто изменить свойство caption компонента Button1 в окне Инспектора объектов), но для более полного знакомства с Delphi мы рассмотрим другой способ - динамического[К сожалению, эта процедура работает не всегда: если ваш ПК не оснащен звуковой картой, динамик будет молчать. В этом случае вместо MessageBeep (MB_OK) напишите просто Веер. Изменения на этапе конструирования называются статическими, а в ходе прогона программы - динамическими.] изменения надписи на этапе прогона программы. Для этого создадим обработчик события OnCreate (По созданию) для формы и изменим в нем это свойство.

Событие OnCreate возникает после создания windows-окна, но до появления этого окна на экране. Чтобы создать обработчик этого события, раскройте список компонентов в верхней части окна Инспектора объектов, выберите компонент Formi и дважды щелкните по свойству OnCreate на странице Events этого компонента (щелкать нужно по правой части строки oncreate). В ответ Delphi вновь активизирует окно кода и покажет вам заготовку для процедуры TForm1. FormCreate. Отредактируйте ее следующим образом:

procedure TFormi.FormCreate(Sender: TObject);

begin

Button1.Caption:= 'Звук';

end;

Единственная вставленная нами строка представляет собой так называемый оператор присваивания языка Object Pascal. В левой части оператора указывается свойство Buttoni. caption, а в правой части - значение ' звук ', которое мы хотим придать этому свойству. Связывает обе части комбинация символов “: =”, которая читается как “присвоить значение”. Символы “:=” всегда пишутся слитно, без разделяющих пробелов, хотя перед двоеточием и после знака равенства можно для лучшей читаемости программы вставлять пробелы, что мы и сделали. Как и любое другое предложение языка, оператор присваивания завершается точкой с запятой.

Составное имя Button1.Caption необходимо для точного указания компилятору, о каком свойстве идет речь: в нашей программе используются три компонента (включая саму форму), каждый из которых имеет свойство Caption; уточняющий префикс Button1 заставит изменить это свойство у кнопки, а не у метки или формы. Присваиваемое свойству значение является текстовой строкой. По правилам Object Pascal текстовая строка должна заключаться в обрамляющие апострофы. Внутри апострофов можно написать любое количество произвольных символов - именно они (без обрамляющих апострофов) будут определять новую надпись на кнопке.

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

3.4. НЕКОТОРЫЕ ИТОГИ

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