Федоров А. Г. / книги / Delphi 3.0 для всех



  

Текст получен из библиотеки 2Lib.ru

 
Код произведения: 11494 
Автор: Федоров А. Г. 
Наименование: Delphi 3.0 для всех 





А.Г. Фёдоров

                           Delphi 3.0 для всех.



  ПРЕДИСЛОВИЕ


  В настоящее время в мире компьютеров существует множество языков
программирования. Одну и ту же программу можно "написать" на Basic,
Pascal, С. Какой из этих языков лучше? Ответ на данный вопрос не такой
простой. Однако можно с уверенностью сказать, что Pascal лучше других
языков подходит для обучения программированию. И не удивительно, ведь этот
язык был разработан швейцарским ученым Н. Виртом, в том числе и для
обучения программированию.
  Язык программирования Pascal оказался настолько удачным, что с момента его
появления за короткое время различными фирмами было создано достаточно
большое количество компиляторов (компилятор - программа, переводящая
инструкции языка программирования высокого уровня на язык инструкций
процессора вычислительной машины, язык низкого уровня). Одной из наиболее
удачных стала разработка американской фирмы Borland, в которой в единое
целое были объединены редактор текста и высокоэффективный компилятор.
Созданная система получила название Turbo Pascal, а язык программирования,
используемый в ней, стал называться Turbo Pascal.
  Совершенствуя Turbo Pascal, фирма Borland разрабатывала новые версии
пакета. Так в систему были внесены дополнения, позволяющие создавать
большие программные проекты, что сделало ее привлекательной для
профессиональных программистов. Со временем в Turbo Pascal появились
средства, обеспечивающие поддержку концепции объектно-ориентированного
программирования.
  Развитие вычислительной техники и технологии программирования привело к
тому, что фирма Borland разработала принципиально новый программный
продукт, который получил название Delphi.
  Delphi - это среда разработки программ, ориентированных на работу в
Windows. В основе идеологии Delphi лежит технология визуального
проектирования и методология объектно-ориентированного программирования.
  Первая версия, Delphi 1, работала в среде Windows 3.1 (Windows 3.11).
После появления Windows 95, Borland выпустила сначала 16-разрядную версию,
Delphi 2, затем, значительно более совершенную, 32-разрядную - Delphi 3.
  Для представления программ в Delphi используется разработанный Borland
язык Object Pascal, в основе которого лежит ставший классическим Turbo
Pascal. Слово "Object" особо подчеркивает, что язык поддерживает концепцию
объектно-ориентированного программирования.

  4________________________Delphi 3. Программирование на Object Pascal

  Книга представляет собой руководство, пособие по разработке программ в
среде Delphi 3 с использованием языка Object Pascal. Ее основная цель
может быть сформулирована так: научить создавать законченные программы,
работающие в Windows 95.
  Научиться программировать можно только постоянно программируя, решая
конкретные задачи. При этом достигнутые в программировании успехи в
значительной степени зависят от опыта. Поэтому, чтобы получить
максимальную пользу от книги, необходимо активно работать с ней. Не
занимайтесь просто чтением примеров, реализуйте их с помощью компьютера.
Не бойтесь экспериментировать - вносите изменения в программы. Чем больше
вы сделаете самостоятельно, тем большему вы научитесь.
  Соглашение об обозначениях
Для облегчения восприятия материала в книге используются различные способы
оформления текста.
  Шрифт Courier применяется для представления текстов программ, обозначения
имен переменных, функций и процедур.
  Шрифт courier italic используется для записи имен параметров процедур и
функций, которые в инструкциях программы должны быть заменены фактическими
параметрами - именами конкретных переменных программы или константами.
Например, в описании
ShowMessage(Сообщение)
showMessage - это имя процедуры, которая выводит на экран диалоговое окно
с сообщением. Сообщение - это имя параметра функции. При использовании
процедуры параметр Сообщение должен быть заменен фактическим параметром -
выражением символьного типа, например, строковой константой.
  Полужирным шрифтом выделены названия меню, команд, кнопок и имена
диалоговых окон среды программирования и их элементов, пользовательских
программ. Например, Options, кнопка Пересчет, программа Вычисление ПИ.


  ВВЕДЕНИЕ

  Программирование, как область деятельности, бурно развивается. Если
несколько лет назад о создании своих собственных программ под Windows
рядовому программисту оставалось только мечтать, так как практически
единственным инструментом разработки программ, ориентированных на работу в
Windows, был Borland C++ for Windows, явно предназначенный для
профессионалов, то сейчас, благодаря появлению Delphi, возможность
создания программ под Windows стала реальностью.
  (Замечание)

  Справедливости ради следует упомянуть о Microsoft Visual Basic, как об
удобном и достаточно мощном средстве разработки программ под Windows.
Однако для большинства программистов Basic остается языком для начинающих
и поэтому, как они считают, не заслуживающим внимания. Хотя с последним
можно поспорить и не согласиться. Кроме того, последние версии Visual
Basic, ориентированные исключительно на объектно-ориентированное
программирование, вследствие своей сложности стали практически недоступны
для начинающих программистов.
  Borland Delphi 3 - это среда разработки программ, ориентированных на
работу в 32-разрядной операционной системе Windows 95. В качестве языка
программирования в Delphi 3 используется объектно-ориентированный язык
Object Pascal.
  В основе идеологии Delphi лежат технологии визуального проектирования и
программирование процедур обработки событий, применение которых позволяет
существенно сократить время разработки и облегчить процесс создания
приложений (программ, работающих в Windows).


  Основы ПРОГРАММИРОВАНИЯ

  В этом разделе рассматриваются базовые понятия программирования,
необходимые для начала практической работы в Delphi.
  Программа, работающая в компьютере, нередко отождествляется с самим
компьютером, так как человек, использующий программу, "вводит в компьютер"
исходные данные, например, с клавиатуры, и "компьютер выдает результат" на
экран. На самом деле ввод исходных данных, их преобразование в результат и
его вывод выполняет процессор компьютера в соответствии с
последовательностью команд, программой, составленной программистом. Таким
образом, можно дать следующее определение программы. Программа - это
последовательность команд, которая выполняется процессором компьютера.
Следовательно, чтобы компьютер (процессор) выполнил некоторую работу,
необходимо разработать последовательность команд, или, как говорят,
"написать программу", в результате выполнения которой эта работа будет
выполнена.
  Этапы разработки программы
Выражение "написать программу" отражает только один из этапов создания
компьютерной программы, когда разработчик действительно пишет команды
(инструкции) на бумаге или при помощи редактора текста.
  Программирование - это процесс создания (разработки) программы, который
может быть представлен как последовательность следующих шагов:
  О Определение требований к программе
О Разработка или выбор алгоритма решения поставленной задачи
О Написание команд
О Отладка
О Тестирование
Определение требований к программе - один из важнейших этапов. На этом
этапе подробно описывается исходная информация и формулируются требования
к результату. Кроме того, описывается поведение программы в особых случаях.
  Например, требования к программе решения квадратного уравнения, которое в
общем виде записывается ax^bx+c^, могут быть такими:


  8________________________Delphi 3. Программирование на Object Pascal

  О Исходными данными для программы являются коэффициенты (а, Ь, с) при
степенях неизвестного, значения которых должны вводиться в режиме диалога
во время работы программы
П Выходные данные- значения корней уравнения
П Если уравнение не имеет корней, то должно печататься соответствующее
сообщение
При разработке программы, предназначенной для работы в Windows, требования
к ней могут включать пункты о желаемом виде диалоговых окон программы.
  На этапе разработки алгоритма необходимо определить последовательность
действий, которые надо выполнить для достижения поставленной цели,
получения результата. Если задача может быть решена различными способами,
и, следовательно, возможны различные варианты алгоритма решения, то
программист, используя некоторый критерий, выбирает наиболее подходящее
решение. Затем составляется подробное описание алгоритма.
  После того как определены требования к программе и составлен алгоритм
решения, он записывается на выбранном языке программирования.
  Под отладкой понимается процесс поиска ошибок в программе; которые бывают
синтаксические (ошибки в тексте) и алгоритмические. Ошибки в тексте - это
наиболее легко устраняемые ошибки. Алгоритмические ошибки обнаружить
труднее. Этап отладки можно считать законченным, если программа правильно
работает на одном-двух наборах входных данных.
  Этап тестирования особенно важен, если вы предполагаете, что вашей
программой будут пользоваться другие. На этом этапе следует проверить
работу программы на как можно большем количестве наборов входных данных,
причем, возможно, и на заведомо неверных. Например, следует проверить, как
ведет себя программа вычисления корней квадратного уравнения, если задать
равным нулю коэффициент при второй степени неизвестного или задать равными
нулю все коэффициенты уравнения.
  Алгоритм и программа
На первом этапе создания программы программист должен определить
последовательность действий, которые необходимо выполнить, чтобы решить
поставленную задачу. Пусть, например, необходимо разработать программу
вычисления корней квадратного уравнения. Исходными данными для решения
уравнения являются значения коэффициентов уравнения. Результат - значения
корней уравнения или вывод, сообщение о том, что уравнение не имеет
корней. Метод решения квадратного уравнения известен, т. е. существуют
формулы, используя которые можно вычислить значения корней "вручную".
Последовательность шагов решения поставленной задачи очевидна. Сначала
надо по формуле найти значение дискриминанта. Затем,


  Основы программирования__________________________________9

  если полученное значение больше нуля, вычислить по формулам значения
корней.
  Алгоритм - это точное предписание, определяющее процесс перехода от
исходных данных к результату.
  Следует уточнить, что предписание считается алгоритмом, если оно обладает
тремя следующими свойствами:
  О Однозначностью
О Массовостью
П Результативностью
Под однозначностью алгоритма понимается единственность толкования правил
выполнения действий и порядка их выполнения. Таким образом, алгоритм не
должен оставлять место произволу при его выполнении.
  Массовость алгоритма означает возможность его применения для решения
класса задач, предполагает его правильную работу при меняющихся, в
заданных пределах, значениях исходных данных.
  Результативность алгоритма предполагает, что выполнение алгоритма должно
приводить к получению определенного результата.
  Ниже приведен пример алгоритма математического характера - алгоритм
вычисления корней квадратного уравнения.
  Исходные данные - это коэффициенты уравнения: а - при второй степени
неизвестного; b - при первой степени неизвестного; с - при нулевой степени
неизвестного.
  Искомый результат - значения корней уравнения, которые можно обозначить Xl
И Х2.
  Предписание:
  1. Вычислить значение дискриминанта (d) уравнения по формуле:
  с1=Ь-'-4ас.
  2. Если значение дискриминанта больше или равно нулю, то вычислить
значения корней уравнения по формулам:
  - Ь-д/d -b+^/d x^=-2a-'' Х2= 2а 
3. Если значение дискриминанта меньше нуля, то это значит уравнение не
имеет действительных корней.
  Приведенное предписание обладает всеми свойствами алгоритма:
  O Однозначностью (в предписании указано, как обозначаются все коэффициенты
уравнения, и приведены формулы для вычисления значения дискриминанта и
корней уравнения)


  10 Delphi 3. Программирование на Object Pascal




  О Массовостью (в предписании указаны не конкретные значения коэффициентов,
а приведены формулы, в которых использованы обозначения коэффициентов)
О Результативностью (при выполнении предписания получается результат -
значения корней уравнения или сообщение о том, что уравнение не имеет
решения)
При описании алгоритма используются обобщенные понятия, например
"коэффициент" и "корень уравнения". При решении задачи эти понятия
конкретизируются. Нельзя найти корни квадратного уравнения, можно решить
только конкретное уравнение, т. е. необходимо задать коэффициенты
уравнения.
  Алгоритм решения задачи может быть представлен в виде словесного описания
или графически в виде блок-схемы. В блок-схемах для обозначения логически
различных фрагментов программы используются определенные стандартные
символы. Основные элементы блок-схемы: Начало/Конец, Ввод/Вывод, Обработка
и Выбор, - изображены на рис. 1.
  Например, алгоритм вычисления корней квадратного уравнения может быть
представлен в виде блок схемы, изображенной на рис. 2.
  Изображение алгоритма в виде блок-схемы позволяет наглядно представить
последовательность действий, необходимых для решения поставленной задачи,
убедиться самому программисту в правильности понимания поставленной задачи.

  Рис. 2. Блок-схема алгоритма вычисления корней квадратного уравнения


  Основы программирования________________________________11

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

  procedure SqRoot(Editi,Edit2,Edit3:tEdit;Label2:tLabel) ;
var
a,b,c:real; ( Коэффициенты уравнения }
d:real; ( Дискриминант }
xl,x2:real; ( Корни уравнения }
begin
{ Ввод исходных данных ) a:=StrToFloat(Editl.text) ;
b:=StrToFloat(Edit2.text) ;
с :=StrToFloat (Edj.t3.text) ;
{ Вычисление дискриминанта ) d:=Sqr(b)-4*a*c;
if d"0 then begin
Label2.color:=clRed;
Label2.font.color:=clRed;
Label2.caption:=
"Дискриминант меньше нуля.'+#13+
'Уравнение не имеет корней.' end else
begin
( Вычисление корней }
xl:=(b+Sqrt(d))/(2*a);
x2:=(-b+Sqrt(d))/(2*а) ;
{ Вывод результата - значений корней) Label2.font.color:=clBlack;
Label 2.caption:"'Корни уравнения:' +#13+'xl=1+FloatToStr(xl)
+#13+'x2='+FloatToStr(x2) ;
end;
end;


  Компиляция

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


  12 Delphi 3. Программирование на Object Pascal

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

  Рис. 3. Схема работы компилятора

  Компилятор генерирует, создает исполняемую программу только в том случае,
если в тексте исходной программы нет синтаксических ошибок. Однако
генерация исполняемой программы машинного кода свидетельствует только об
отсутствии в тексте программы синтаксических ошибок. Убедиться в
правильности работы программы можно только во время ее тестирования -
пробных запусках программы и при анализе полученных результатов. Например,
если в программе нахождения корней квадратного уравнения допущена ошибка в
записи выражения вычисления дискриминанта, то даже если это выражение
будет синтаксически верно, программа выдаст неверные значения корней.
  Язык программирования Object Pascal Типы данных
Программа на Object Pascal может оперировать различными типами данных:
  целыми и дробными числами, отдельными символами и строками символов,
логическими величинами.
  Целый тип
Язык программирования Object Pascal поддерживает семь целых типов данных:
shortint, smailint,longint,byte, word, integer И cardinal.


  Основы программирования ____ ____ _____ __ __ 13

  Типы данных shortint, smallint, longint, byte И word ОТНОСЯТСЯ К ОСНОВНОЙ
(fundamental) категории. Формат и диапазон значений типов основной
категории не зависит от разрядности процессора и используемой
операционной'системы.
  Ниже, в таблице, перечислены целые типы, относящиеся к основной категории.
  Тип
Диапазон
Формат
shortint
- 128..127
Знаковый, 8 бит
smallint
- 32768..32767
Знаковый,16 бит
longint
- 2147483648..2147483647
Знаковый, 32 бита
byte
0..255
Беззнаковый,8 бит
word
0..65535
Беззнаковый,16 бит

  Типы данных integer и cardinal относятся к общей (generic) категории.
Формат и диапазон значений типов этой категории зависит от разрядности
процессора и используемой операционной системы.
  Ниже, в таблице, перечислены целые типы, относящиеся к общей категории.
  Тип
Диапазон
Формат
integer
- 32768..32767
Знаковый, 16 бит
cardinal
0..65535
Беззнаковый,16 бит
integer
- 2147483648..2147483647
Знаковый, 32 бита
cardinal
0.. 2147483647
Беззнаковый, 32 бита


  Вещественный тип

  Язык программирования Object Pascal поддерживает четыре типа данных,
позволяющих работать с дробными, вещественными числами: real, single,
double, extended. Эти типы различаются между собой диапазоном допустимых
значений и возможным количеством цифр, т. е. точностью. Ниже, в таблице,
перечислены вещественные типы.

  Тип
real
Диапазон
2.9 х Ю-39. 1.7 х Ю-"8
Кол-во цифр
11-12
Кол-во байт

                                6

  single
1.5 х Ю-45. 3.4 х КГ38

                                7-8

  4
double
5.0 х Ю-324.. 1.7Х10"308
15-16

                                8

  extended
3.4х10-4932..1.1 хЮ"4932
19-20

                                10




  14 _____________________Delphi 3. Программирование на Object Pascal

  Символьный тип

  Язык программирования Object Pascal поддерживает три символьных типа
данных: ansichar, widechar и char, которые, как и целые типы,
подразделяются на основную и общую категории. Основная категория включает
в себя ТИПЫ ansichar И widechar.
  Тип ansichar представляет собой Ansi-символы, т. е. печатаемые
(отображаемые) и служебные символы, которые кодируются числами от 0 до 255
(см. приложение).
  Тип widechar представляет собой Unicode-символы, которые кодируются
числами от 0 до 65 535. Первые 256 символов Unicode совпадают с символами
Ansi.
  Тип char относится к общей категории и представляет собой печатаемые и
служебные Ansi-символы.
  Строковый тип
Язык программирования Object Pascal поддерживает три строковых типа:
  shortstring, longstring И widestring.
  Тип shortstring представляет собой статически размещаемые в памяти
компьютера строки длиной от 0 до 255 символов.
  Тип longstring представляет собой динамически размещаемые в памяти
компьютера строки, длина которых ограничена только объемом свободной
памяти компьютера.
  Тип widestring представляет собой динамически размещаемые в памяти
компьютера строки, длина которых ограничена только объемом свободной
памяти компьютера, однако, в отличие от строки типа longstring, каждый
символ является Unicode-символом, т. е. кодируется 16 битами.

  (Замечание)

  В Object Pascal для обозначения строкового типа допускается использовать
идентификатор string, который применяется для обозначения строкового типа
в Turbo Pascal. Тип String эквивалентен типу shortstring.
  Логический тип
В Object Pascal логический тип, Boolean, представлен двумя логическими
величинами: true (истина) и false (ложь).


  Переменные

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


  Основы программирования 15

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

  Рис. 4. Переменная - ячейка памяти компьютера


  Переменная - это область, ячейка памяти компьютера (рис. 4). Каждая
переменная, используемая в программе, должна иметь имя. В качестве имени
переменной можно использовать последовательность букв латинского алфавита,
цифр и некоторых специальных символов, причем первым символом должна быть
буква. Пробел в имени переменной использовать нельзя.
  Компилятор Object Pascal не различает прописные и строчные буквы в именах
переменных, поэтому имена SUMMA, Summa и summa обозначают одну и ту же
переменную.
  Желательно, чтобы имя переменной было логически связано с назначением
переменной. Например, если переменные предназначены для хранения
коэффициентов квадратного уравнения, записываемого в виде АХ''+ВХ+С=О, то
вполне логично присвоить этим переменным имена А, в и с. Переменным,
предназначенным для хранения значений корней квадратного уравнения, -
имена XI и Х2. Другой пример. Если в программе есть переменные,
предназначенные, например, для хранения суммы покупки и величины скидки,
то этим переменным можно присвоить имена TotalSurom и Discount или ObSumma
И Skidka.
  В Object Pascal каждая переменная перед использованием должна быть
объявлена. С помощью объявления устанавливается не только факт
существования переменной, но и задается ее тип, тем самым указывается
диапазон допустимых значений.


  16 __ ___ Delphi 3. Программирование на Object Pascal В
общем виде инструкция объявления переменной выглядит так:

  имя:тип;

  где имя - имя объявляемой переменной; тип - один из допустимых типов языка
программирования Object Pascal.
  Ниже приведены примеры объявления переменных.
  а:real ;
b:real;
i:integer;
В приведенном примере объявлены две переменные типа real и одна переменная
типа integer.
  В тексте программы объявление каждой переменной, как правило, помещают на
отдельной строке.
  Если в программе несколько переменных одного типа, то можно через запятую
перечислить имена переменных, относящихся к одному типу и после имени
последней переменной, через двоеточие, указать их тип.
  Пример:
  а,Ь,с:геа1;
х1,х2:геа1;
Константы
В языке программирования Object Pascal существует два вида констант:
  обычные и именованные.
  Обычная константа - это целое или дробное число, строка символов или
отдельный символ, логическое значение.
  В тексте программы числовые константы записываются обычным образом, точно
так же, как числа, например, при решении математических задач. При записи
дробных чисел для разделения целой и дробных частей используется точка.
Если константа отрицательная, то непосредственно перед первой цифрой
ставится знак "минус".
  Ниже приведены примеры числовых констант.
  123 0.0 -524.03
О

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

  Основы программирования__________________________________17

  числа меньшего 10, которое называется мантиссой, и степени десяти,
называемой порядком. Ниже, в таблице, приведены примеры чисел, записанных
в обычной, алгебраической, и в форме с плавающей точкой.
  Число
Алгебраическая форма
Плавающая точка
1000000
1х106
1.0000000000Е+06
- 123.452
- 1.23452х102
- 1.2345200000Е+02
0.0056712
5.6712х10-3
5.6712000000Е-03

  Строковые и символьные константы заключаются в кавычки. Ниже приведены
примеры символьных констант.
  'Язык программирования Object Pascal'
'Delphi 3'
'2.4'
'Д'
Здесь следует обратить внимание на константу '2.4'. Это именно символьная
константа, строка символов, которая изображает число "две целые четыре
десятых", а не число 2.4.
  Именованные константы, как и переменные, перед использованием должны быть
объявлены. В общем виде инструкция объявления именованной константы
выглядит так:
  константа=значение;
где константа - имя константы; значение - значение именованной константы.
Ниже приведены примеры объявления именованных констант.
  Hbound=10;
Captions'Решение квадратного уравнения';
pi=3.1415926;
После объявления именованной константы в инструкциях программы, вместо
значения константы, можно использовать ее имя.
  Тип константы определяется ее видом. Так, например, константа 125 - это
константа целого типа, константа о. о - дробного, 'выполнить' - строковая
константа, а V - символьная.
  Инструкция присваивания
В результате выполнения инструкции присваивания переменная получает
значение. В общем виде инструкция присваивания выглядит так:
  Имя:= Выражение;


  18_______________________Delphi 3. Программирование на Object Pascal

  где имя - имя переменной, значение которой изменяется в результате
выполнения инструкции присваивания; двоеточие и следующий за ним знак
"равно" - это символ инструкции присваивания.
  Выражение
Выражение состоит из операндов и операторов. Операторы находятся между
операндами. Операндами выражений могут быть константы и/или переменные.
Операторы обозначают действия, выполняемые над операндами. Ниже, в
таблице, перечислены операторы языка Object Pascal и действия ими
обозначаемые.
  Оператор
+
Действие
сложение
-
вычитание

                                *

  умножение
/ DIV
деление деление нацело
MOD
вычисление остатка от деления

  При записи выражений между операндом и оператором, за исключением
операторов DIV и MOD, пробел можно не ставить.
  В простейшем случае выражение может представлять собой константу или
переменную.
  Примеры выражений:
  123
0.001 i
А+В/С Summa*0.75 (В1+ВЗ+ВЗ)/100 Cena MOD 1000
Операторы имеют разный приоритет. Так у операторов *, /, DIV, MOD более
высокий приоритет, чем у операторов + и -. При вычислении выражений
сначала выполняются операторы с более высоким приоритетом. Если приоритет
операторов в выражении одинаковый, то сначала выполняется оператор,
стоящий левее от конца выражения.
  Для задания нужного порядка выполнения операций в выражении можно
использовать скобки. Например:
  (rl+r2+r3)/(rl*r2*r3)


  Основы программирования__________________________________19

  Выражение, заключенное в скобки, трактуется как один операнд. Это значит,
что операции над операндами в скобках будут выполняться в обычном порядке,
но раньше чем операции над операндами, находящимися за скобками. 'При
записи выражений, содержащих скобки, должна соблюдаться парность скобок,
т. е. число открывающих скобок должно быть равно числу закрывающих скобок.
Нарушение парности скобок наиболее распространенная ошибка при записи
выражений.
  Тип выражения
Тип выражения определяется типом операндов, входящих в выражение, и
зависит от операций, выполняемых над ними.
  При определении типа выражения следует иметь в виду, что тип константы
определяется ее видом, а тип переменной задается в инструкции объявления.
Например, константы о, l и -512 целого типа, а константы l.o, о. о, з.
2Е-05 - вещественного типа.
  Операции, выполняемые над операндами, задаются операторами. Ниже приведены
правила, при помощи которых можно определить тип выражения, в зависимости
от вида оператора и типа операндов.
  О Операторы *, +, -. Если хотя бы один операнд имеет вещественный тип, то
результат тоже будет вещественного типа; если все операнды целого типа, то
результат тоже будет целым
П Оператор I. Результатом всегда является значение вещественного типа
О Операторы DIV и MOD. Результатом всегда является значение целого типа.
Операнды этих операторов всегда должны быть целого типа
Выполнение инструкции присваивания
Выполнение инструкции присваивания заключается в следующем: сначала
вычисляется результат выражения, находящегося справа от символа
присваивания, затем вычисленное значение записывается в переменную, имя
которой стоит слева от символа инструкции присваивания.
  Например, в результате выполнения инструкций:
  О i:=o; - значение переменной i становится равным нулю
П а:=ь+с; - значением переменной а будет число, равное сумме значений
переменных ь и с
О j :=j+l; - значение переменной j увеличивается на единицу
Инструкция присваивания считается верной, если тип выражения
соответствует, или может быть приведен, к типу переменной, получающей
значение. Например, переменной типа real можно присвоить значение
выражения типа real или integer, а переменной типа integer можно присвоить


  20________________________Delphi 3. Программирование на Object Pascal

  значение выражения только типа integer. Так, например, если переменные i и
п типа integer, а переменная d типа real, то инструкции
i:=n/10;
i:=1.0;
неправильные, а инструкция
d:=i+l;
правильная.
  Во время перевода исходной программы в исполняемую компилятор проверяет
соответствие типов выражений и переменных. Если тип выражения не
соответствует типу переменной, то компилятор выдает сообщение об ошибке.
  Стандартные функции
Для выполнения часто встречающихся вычислений и преобразований данных в
Object Pascal существуют стандартные функции.
  Арифметические функции
Арифметические функции позволяют выполнять различные вычисления. Например,
функция sqrt вычисляет значение квадратного корня.
  Ниже приведены некоторые стандартные арифметические функции.
  Функция
Значение
Abs(n)
Абсолютное значение п
Sqrt(n)
Квадратный корень п
Sqr(n)
Квадрат n
Sin(n)
Синус n
Cos(n)
Косинус n
Arctan(n)
Арктангенс n
Exp(n)
Экспонента n
Ln(n)
Натуральный логарифм n

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


  Основы программирования__________________________________21

  типа real, надо сначала получить изображение числа, являющегося значением
данной переменной. Это можно сделать при помощи функции FloatToStr,
которая возвращает строковое представление выражения действительного типа,
указанного при вызове функции.
  Ниже перечислены наиболее часто используемые функции преобразования.
  Функция
Значение
Спг(л)
Символ ANSI с номером n
IntToStr(n)
Строка, являющаяся изображением значения целого n
FloatToStr(л)
Строка, являющаяся изображением значения веществен


  ного n
FloatToStrF(n,f,.Z,Jn)
Строка, являющаяся изображением значения вещественного п. При вызове
функции указываются:


  f - формат (способ изображения);


  1 -точность (нужное общее количество цифр);


  m - количество цифр после десятичной точки
StrToInt(s)
Целое, изображением которого является строка s
StrToFloat(s)
Вещественное, изображением которого является строка s
Round(n)
Ближайшее к n целое
Trunc(n)
Целая часть от n
Frac(n)
Дробная часть вещественного n
Int(n)
Целая часть вещественного n

  Использование функций
Функции обычно используются в качестве операндов выражений. При этом
параметром функции может быть переменная, константа или выражение.
Например, ниже приведены выражения для вычисления дискриминанта (d) и
корней (х1,х2) квадратного уравнения.
  d:=Sqrt(b)-4*a*c;
xl:=(-b+Sqrt(b*b-4*a*c))/2;
x2:=(-b-Sqrt(Sqrt(b)-4*a*c))/2;
В первом выражении аргументом функции sqrt является переменная, во втором
выражении в качестве аргумента функции sqrt используется выражение.
  При использовании функций важно, чтобы тип выражения, используемого в
качестве параметра функции, соответствовал или мог быть преобразован к
нужному типу, указанному в описании функции типу.

  22

  Delphi 3. Программирование на Object Pascal



  Ввод данных

  Программа может получить исходные данные из окна ввода, поля ввода
диалогового окна или файла.
  Ввод из окна ввода
Ввод данных из окна ввода осуществляется вызовом функции inputBox,
возвращаемым значением которой является строка, введенная пользователем. В
общем виде инструкция для ввода данных с использованием функции inputBox
выглядит так:
  Переменная:=InputBox(Заголовок,Подсказка,Значение);
где
переменная - имя переменной строкового типа, значение которой должно быть
получено из окна ввода;
Заголовок - текст заголовка окна ввода;
подсказка - текст поясняющего сообщения;
Значение - текст, находящийся в поле ввода в момент появления окна ввода
на экране.
  Например, в программе пересчета веса из фунтов в килограммы инструкция
ввода количества фунтов может выглядеть так:
  s:=InputBox('Фунты-килограммы','Введите вес в фунтах','');
Выполняется эта инструкция следующим образом. На экран выводится окно
ввода (рис. 5).
  Рис. 5. Пример окна ввода
После того как в поле ввода будет введено (набрано на клавиатуре) число и
выполнен щелчок на одной из командных кнопок окна ввода, QK или Cancel,
переменная s получит значение: введенную строку, если щелчок был на кнопке
ОК, или, если щелчок был на кнопке Cancel, предопределенное значение,
указанное при вызове функции inputBox в качестве ее аргумента.
  Следует еще раз обратить внимание, что значение функции inputBox
строкового (string) типа. Поэтому, если программе надо получить значение
числового типа, то введенная строка (изображение числа) должна быть
преобразована в число при помощи соответствующей функции преобразования.


  Основы программирования__________________________________23

  Например, если в программе переменная funt вещественного (real) типа, то
инструкции, обеспечивающие ввод ее значения, могут выглядеть так:
  s:=Inp^itBox('Фунты-килограммы','Введите вес в фунтах','');
funt:=StrToFloat(s) ;
Ввод из поля диалогового окна
Ввод данных из поля ввода диалогового окна осуществляется обращением к
свойству Text этого поля.
  На рис. 6 приведен вид диалогового окна программы решения квадратного
уравнения.
  Рис. 6. Пример диалогового окна
Если Editi - это имя поля, предназначенного для ввода коэффициента при
второй степени неизвестного, то инструкция ввода значения коэффициента,
для представления которого в программе используется переменная а типа
real, может быть такой:
  a:=StrToFloat(Editl.Text) ;
В приведенной инструкции параметр Text - это имя внутренней переменной,
свойства, поля ввода, которая содержит текст, находящийся в поле.
  Вывод данных
Вывести результат программа может в окно сообщения, в поле вывода
диалогового окна, файл или на принтер.
  Вывод в окно сообщения
Вывод в окно сообщения может быть выполнен вызовом процедуры ShowMessage
ИЛИ функции MessageDlg.


  24 _____________________Delphi 3. Программирование на Object Pascal

  Процедура showMessage позволяет вывести на экран простое диалоговое окно с
текстом и одной командной кнопкой.
  В общем виде инструкция вызова процедуры showMessage выглядит так:
  ShowMessage(Сообщение);
где сообщение - выражение строкового типа.
  Например, на рис. 7 приведен вид окна сообщения, полученного в результате
выполнения инструкции
ShowMessage('Уравнение не имеет действительных корней.');
Рис. 7. Пример окна сообщения
Следует обратить внимание на то, что заголовок окна сообщения, выводимого
процедурой ShowMessage, совпадает с именем исполняемого файла приложения.
  Функция MessageDig более гибкая. Она позволяет снабдить сообщение одним из
стандартных значков Windows, например значком "Внимание", задать
количество и тип командных кнопок. На рис. 8 приведен пример окна
сообщения, полученного в результате выполнения инструкции
г:=MessageDlg('Дискриминант равен нулю'+#13
+'Уравнение не имеет действительных корней.', mtlnfonnation,Рис. 8. Пример
окна сообщения
Функция MessageDig возвращает результат - число, проверив значение
которого можно определить, выбором какой командной кнопки был завершен
диалог.
  В общем виде обращение к функции MessageDig выглядит так:
  Выбор:" MessageDig{Сообщение,Тип,Кнопки,КонтекстСправки)
Сообщение - это текст выводимого сообщения.
  Тип - это тип, вид сообщения. Сообщение может быть информационным,
предупреждающим или сообщением об ошибке. Тип сообщения задается


  Основы программирования__________________________________25

  именованной константой. Ниже, в таблице, приведены именованные константы,
определяющие тип сообщения, выводимого функцией MessageDlg.
  Константа
Тип сообщения и значок
mtWarning
Внимание, черный восклицательный знак в желтом треугольнике
MtError
Ошибка, белый крест в красном круге
MtInformation
Информация, синяя латинская i на фоне белого облачка
MtConfinnation
Запрос подтверждения, знак вопроса на фоне белого облачка
MtCustom
Пользовательское, обычное, сообщение без значка

  Число и вид кнопок задается списком кнопки, который может состоять из
нескольких разделенных запятыми именованных констант, записанных в
квадратных скобках. Константы и соответствующие тексты на кнопке приведены
ниже в таблице. Например, чтобы в окне сообщения были кнопки ОК и Cancel
список кнопки должен быть таким: Константа
Текст на кнопке
mbYes
Yes
mbNo
No
mbOK
OK
mbCancel
Cancel
mbHelp
Help
mbAbort
Abort
mbRetry
Retry
mbignore
Ignore
mbAll
All

  Кроме списка из констант, приведенных выше, можно использовать константы:
mbOkCancel, mbYesNoCancel И mbAbortRetryIgnore. Эти константы определяют
наиболее часто используемые в диалоговых окнах комбинации командных кнопок.
  Параметр КонтекстСправки определяет номер экрана справочной системы,
который появится при нажатии на клавишу "F1" в тот момент, когда окно
сообщения находится на экране. Если использование справочной системы не
предусмотрено, то при вызове функции MessageDlg в качестве параметра
КонтекстСправки должен быть указан ноль.


  26_______________________Delphi 3. Программирование на Object Pascal

  Значение, возвращаемое функцией MessageDig после щелчка на одной из
командных, позволяет определить, на какой из кнопок был выполнен щелчок.
Ниже приведен список констант, идентифицирующих нажатую кнопку.
  Константа
Диалог завершен щелчком на кнопке
mrAbort
Abort
mrYes
Yes
mrOk
Ok
mrRetry
Retry
mrNo
No
mrCancel
Cancel
mr Ignore
Ignore
mrAll
All


  Вывод в поле диалогового окна

  Часть диалогового окна, предназначенная для вывода информации, называется
полем вывода или полем метки. У каждого поля вывода есть имя. Чтобы в поле
вывода появился текст, достаточно присвоить значение свойству Caption
этого поля. Например, если Labeil - это имя поля вывода диалогового окна
программы решения квадратного уравнения, то для того, чтобы в этом поле
появился текст "Уравнение не имеет действительных корней", достаточно
записать:
  Labeil.Caption:" 'Уравнение не имеет действительных корней';
В первом приближении свойство caption поля метки можно рассматривать как
переменную символьного типа. Поэтому, для того чтобы можно было в это поле
вывести значения числового типа, исходное значение предварительно должно
быть преобразовано в строку символов, например, при помощи функции
FloatToStr или intToStr. Ниже, в качестве примера, приведена инструкция из
программы решения квадратного уравнения, которая используется для вывода
значений вычисленных корней.
  Labeil.Caption:=" 'Корни уравнения:'+Chr(13)+
'xl='+FloatToStr(xl)+Chr(13)+ 'х2='+FloatToStr(х2) ;
В приведенном примере для вывода текста в три строки используется функция
chr, которая возвращает символ "Новая строка", код которого равен
тринадцати.


  Основы программирования__________________________________27

  Программирование в Delphi

  При программировании в Delphi основная работа программиста заключается в
разработке подпрограмм. Задачу организации взаимодействия разработанных
подпрограмм берет на себя Delphi.
  В языке Object Pascal основной программной единицей является подпрограмма.
Различают два вида подпрограмм: процедуры и функции. Процедуры и функции
выполняют некоторую часть общей, решаемой всей программой задачи. Отличие
функции от процедуры заключается в том, что с именем функции связано
значение, поэтому имя функции можно использовать в выражениях.
  Структура процедуры
Процедура начинается заголовком, за которым следуют разделы: описания
констант, описания типов, описания переменных и раздел инструкций.
  Описание процедуры в общем виде выглядит так:
  Procedure Имя const
{ описание констант} type
( описание типов } var
( описание переменных ) begin
{ исполняемые инструкции } end;
Заголовок процедуры состоит из слова procedure, за которым следует имя
процедуры. Если у процедуры есть параметры, то они указываются после имени
процедуры в скобках. Завершается заголовок процедуры символом "точка с
запятой".
  Если в процедуре используются именованные константы, то они объявляются в
разделе объявления констант, который начинается словом const.
  За разделом констант следует раздел описания типов, начинающийся словом
type. После раздела описания типов следует раздел описания переменных, в
котором объявляются все переменные, используемые в программе. Раздел
описания переменных начинается словом var. За разделом описания переменных
следует раздел инструкций. Раздел инструкций начинается словом begin и
заканчивается словом end, за которым следует символ "точка с

  30_______________________Delphi 3. Программирование на Object Pascal
st:= 'Корни уравнения'+Chr(13)
+'xl=',FloatToStr(xl)+Chr(13) +'x2=',FloatToStr(x2) ) ;
Для облегчения понимания логики работы программы в текст программы можно
включать комментарии. Комментарий - это текст, заключенный в фигурные
скобки или следующий за двумя подряд наклонными черточками до конца
строки. Комментарий обычно располагают на отдельной строке, в этом случае
он заключается в фигурные скобки, или после инструкции, в этом случае
перед комментарием ставятся две наклонные черты. Ниже приведен пример
раздела описания переменных, в котором использованы оба способа оформления
комментария.
  var
(коэффициенты уравнения) a:real; // при второй степени неизвестного
b:real; // при первой степени неизвестного с:real; // при нулевой степени
неизвестного
{корни уравнения } х1,х2:геа1;


  DELPHI - СРЕДА ВИЗУАЛЬНОГО ПРОГРАММИРОВАНИЯ

  Установка Delphi
Установка пакета Delphi производится с CD-ROM, на котором находятся все
необходимые файлы и программа установки. Программа установки запускается
автоматически, сразу после того, как установочный диск будет помещен в
CD-дисковод.
  Замечание
Перед началом установки Delphi необходимо завершить работу всех активных
приложений.
  В результате запуска программы установки на экране появляется окно Setup
(рис. 9), в котором выводится информационное сообщение и процент
выполненной программой работы по подготовке к установке Delphi.
  Рис. 9. Начало установки Delphi
После завершения подготовки к установке Delphi на экране появляется
диалоговое окно Welcome (рис. 10), в котором для продолжения установки
следует выбрать кнопку Next (следующий шаг).
  После щелчка на кнопке Next появляется диалоговое окно Software License
Agreement (рис. 11). Прочитав текст лицензионного соглашения, надо
щелкнуть на кнопке Yes.
  Следующее диалоговое окно, которое появляется в процессе установки Delphi,
- это окно Setup Type (тип, вариант установки) (рис. 12). В этом окне
можно выбрать один из предлагаемых программой вариантов установки Delphi:
Full (полная), Compact (компактная) или Custom (частичная).
  Полный вариант установки предполагает, что с установочного CD-ROM на
жесткий диск компьютера будут скопированы все компоненты Delphi 3.


  32 Delphi 3. Программирование на Object Pascal

  Рис. 10. Диалоговое окно Welcome программы установки Delphi
Рис. 11. Диалоговое окно Software License Agreement
При компактной установке на жесткий диск компьютера копируются только
самые необходимые компоненты Delphi. По сравнению с остальными вариантами
установки, компактный вариант требует наименьшее количесто свободного
дискового пространства. Вместе с тем, некоторые возможности Delphi в этом
варианте установки не будут доступны.
  Выборочный вариант установки позволяет программисту самому выбрать
необходимые для работы компоненты Delphi. Этот вариант установки обычно
используют опытные программисты.


  Delphi - среда визуального программирования 33

  Рис. 12. Диалоговое окно Setup Type
Замечание
Полный вариант установки требует порядка 100 Мб дисковой памяти, однако
если на жестком диске компьютера достаточно свободного места, то лучше
выбрать этот вариант установки.
  После выбора варианта установки надо щелкнуть на кнопке Next. В результате
этого появляется следующее диалоговое окно программы установки - окно
Select Directories (рис. 13).
  Рис. 13. Диалоговое окно Select Directories


  34 Delphi 3. Программирование на Object Pascal

  В диалоговом окне Select Directories (выбор каталога) помимо информации о
требуемом (Space Required) для установки Delphi и свободном (Space
Available) дисковом пространстве, указаны каталоги, куда программа
установки будет копировать файлы Delphi. Если данных каталогов на диске
нет, то программа установки создаст их.
  ( Замечание j
При первой установке Delphi лучше согласиться с предлагаемыми программой
установки именами каталогов.
  После щелчка на кнопке Next появляется диалоговое окно Select Program
Folder (рис. 14).
  Рис. 14. Диалоговое окно Select Program Folder
В диалоговом окне Select Program Folder (выбор программной папки) в списке
Existing Folders (существующие папки) указаны существующие в компьютере
программные папки, а в поле Program Folder (программная папка) находится
имя папки, куда программа установки предлагает поместить значки
компонентов Delphi. Если папки Borland Delphi на рабочем' столе компьютера
нет, то программа установки создаст ее.
  На этом заканчивается подготовительный этап установки. После щелчка на
кнопке Next, появляется диалоговое окно Start Copying Files (рис. 15), в
котором указана информация о выбранном варианте установки: тип установки,
имена каталогов, куда будут копироваться файлы Delphi, имя программной
папки.


  Delphi - среда визуального программирования_____________________35

  Рис. 15. Диалоговое окно Start Copying Files
Прокручивая список Current Settings (текущие установки), следует проверить
значения, которые будут использоваться во время непосредственной установки
Delphi. Чтобы изменить какой-либо параметр установки, следует щелчком на
кнопке "Back вернуться к тому диалоговому окну программы установки, в
котором этот параметр устанавливался и задать требуемое значение.
  Если все параметры установки заданы правильно, то следует щелкнуть на
кнопке Install. После этого начинается процесс копирования файлов Delphi с
CD-ROM на жесткий диск компьютера. Во время копирования на экран выводится
информация о Delphi, на фоне которой в диалоговом окне Setup (рис. 16)
отображается имя копируемого в данный момент файла и процентное количество
уже скопированных файлов.
  Рис. 16. Диалоговое окно Setup
После копирования всех необходимых файлов появляется диалоговое окно
Readme Information (рис. 17).
  После щелчка на кнопке Next появляется последнее, выводимое программой
установки, диалоговое окно Setup Complete (установка завершена) (рис. 18).

  36 Delphi 3. Программирование на Object Pascal
Рис. 17. Диалоговое окно Readme Information
Рис. 18. Диалоговое окно Setup Complete

В этом окне можно выбрать один из двух вариантов завершения работы
программы установки Delphi: перезапустить компьютер, для того чтобы внести
произведенные программой установки изменения в файлы настроек системы;
отложить перезапуск компьютера. Предопределенным и рекомендуемым вариантом
завершения программы установки является перезапуск компьютера, именно
поэтому в диалоговом окне Setup Complete выбран переключатель Yes, I want
to restart my computer now (Да, перезапустить компьютер сейчас). После
щелчка на кнопке Finish выполняется перезагрузка

  Delphi - среда визуального программирования 37
Windows (если выбран вариант перезапуска компьютера). На этом установка
Delphi завершается. Теперь можно приступать к работе.
  Запуск Delphi
Delphi, как и любая программа Windows, может быть запущена выбором команды
из главного меню Windows или щелчком на ярлычке, идентифицирующем Delphi и
расположенным, например, на рабочем столе.
  Для запуска Delphi выбором команды надо из главного меню выбрать строку
Программы, затем, в появившемся списке, строку Borland Delphi 3, в
следующем списке, - строку Delphi 3 (рис. 19) и выполнить на ней двойной
щелчок.
  Рис. 19. Запуск Delphi выбором команды из меню Windows
Чтобы запустить Delphi щелчком на ярлычке, идентифицирующем Delphi, надо
сначала создать этот ярлычок, который наиболее удобно расположить на
рабочем столе.
  Создается ярлычок следующим образом. Сначала надо щелкнуть правой кнопкой
мыши в поле рабочего стола, и в появившемся списке выбрать Создать, затем
Ярлык (рис. 20).
  Рис. 20. Выбор команды Создать/Ярлык


  38_______________________Delphi 3. Программирование на Object Pascal

  В результате этого появляется диалоговое окно Создание ярлыка (рис. 21).
  Рис. 21. Диалоговое окно Создание ярлыка
В поле Командная строка следует ввести командную строку, обеспечивающую
запуск Delphi. Если установка Delphi выполнена в каталог Program
Files\Borland\Delphi 3, например, на диск С:, то командная строка должна
быть такой:
  "C:\Program Files\Borland\Delphi 3\BIN\Delphi32.exe"
Если установка Delphi выполнена в другой каталог, то, для того чтобы найти
на диске файл delphi32.exe, лучше воспользоваться кнопкой Обзор....
  После ввода командной строки и щелчка на кнопке Далее" появляется
диалоговое окно Выбор названия программы (рис. 22). В поле Укажите название
ярлыка надо ввести текст - подпись, которая будет выводиться под ярлычком,
например, текст "Delphi 3". После щелчка на кнопке Готово, на рабочем
столе появляется ярлычок, идентифицирующий Delphi (рис. 23).
  Рис. 22. Диалоговое окно Выбор названия программы


  Delphi - среда визуального программирования 39

  Рис. 23. Ярлычок Delphi
Рис. 24. Выбор из меню команды Свойства
Рис. 25. Вкладка Ярлык диалогового окна Свойства: Delphi 3
Последнее, что надо сделать после создания ярлыка для Delphi, - задать
рабочий каталог Delphi. Для этого надо щелкнуть правой кнопкой мыши на
изображении ярлычка Delphi и из появившегося списка выбрать команду
Свойства (рис. 24).
  Затем в появившемся окне Свойства: Delphi 3, на вкладке Ярлык, в поле
Рабочий каталог ввести имя рабочего каталога (рис. 25) и щелкнуть на
кнопке ОК.
  Начало работы в Delphi
Вид экрана после запуска Delphi несколько необычен (рис. 26), вместо
одного окна на экране появляются четыре: главное, формы, инспектора
объектов и редактора кода, которое почти полностью закрыто окном формы.
  В главном окне (рис. 27) находится меню команд Delphi, панель инструментов
и палитра компонентов.
  Окно формы, его заголовок Fonnl представляет собой заготовку, макет одного
из окон разрабатываемого приложения.
  Окно инспектора объектов, его заголовок Object Inspector позволяет видеть
и менять свойства объектов проекта. После запуска Delphi в этом окне
находятся свойства формы Fonnl.


  40 Delphi 3. Программирование на Object Pascal

  Рис. 26. Вид экрана после запуска Delphi
/ Меню команд



  Палитра компонентов
Панель инструментов Рис. 27. Главное окно Delphi

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


  Delphi - среда визуального программирования 41

  Работа над новым проектом, так в Delphi называется разрабатываемое
приложение, начинается с создания стартовой формы - окна, которое
появляется при запуске приложения.
  
Форма приложения
Стартовая форма создается путем изменения свойств (свойств) формы Forml.
Свойства формы определяют ее внешний вид: размер, положение на экране,
текст заголовка, вид рамки. Свойства перечислены на вкладке Properties
(свойства) окна Object Inspector. В левой колонке находятся имена свойств,
в правой - их значения.
  Сначала надо изменить значение свойства caption (заголовок) - заменить
Forml на Фунты-килограммы. Для этого щелкнуть мышью в поле Caption. В
результате этого в правой колонке, где находится текущее значение свойства
- текст Forml, появляется курсор (рис. 28).
  Используя клавишу "Backspase", надо удалить
Forml И ввести Фунты-килограммы.
  Рис. 28. Установка значения свойства Caption посредством ввода
Аналогичным образом можно установить значения свойств Height и width,
которые определяют высоту и ширину формы. Этим свойствам надо присвоить
значения 185 и 290.
  Замечание
Размер формы и элементов управления, а также положение формы на экране и
элементов управления на поверхности формы задаются в пикселях, точках
экрана.
  При выборе некоторых свойств, например color (цвет), которая определяет
цвет фона формы, после значения свойств выводится значок выпадающего
списка. В результате щелчка на нем появляется список допустимых значений
свойства, из которого можно выбрать нужное значение (рис. 29).
  Помимо обычных свойств у объектов, в том числе и у формы, могут быть
вложенные свойства. Перед именем вложенного свойства стоит значок "плюс".
При двойном щелчке на имени вложенного свойства раскрывается список
уточняющих свойств (рис. 30), а значок "плюс" меняется на "минус".


  42 Delphi 3. Программирование на Object Pascal



  Рис. 29. Установка значения свойства выбором из списка

  Рис. 30. Пример раскрытого списка уточняющих свойств свойства Font

  В поле значения свойства Font расположена командная кнопка с тремя
точками, при нажатии на которую появляется стандартное диалоговое окно
Windows выбора шрифта и его свойств.
  Большинство свойств определяют внешний вид формы. Свойство Name определяет
имя формы, оно используется в программе для управления формой.
  Ниже, в таблице, приведены измененные свойства формы разрабатываемого
приложения. Остальные свойства формы оставлены без изменения и в таблице
не приведены.
  Свойство
Обозначение
Значение
Имя формы
Name
Form"!
  Заголовок
Caption
Фунты-килограммы
Высота
Height

                                185

  Ширина
Width

                                290

  Шрифт
Font. Name
Arial
Размер шрифта
Font. Size

                                10


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


  Delphi - среда визуального программирования_____________________45

  Рис. 31. Вид формы приложения после установки значений свойств
Компоненты формы
Программа пересчета веса из фунтов в килограммы должна получить от
пользователя исходные данные - значение веса в фунтах. В Windows данные с
клавиатуры вводятся в поля редактирования. Поэтому в данную форму надо
добавить компонент - поле редактирования.
  ( Замечание ^
В Delphi поля редактирования, командные кнопки, поля статического текста и
прочие элементы управления, находящиеся в форме, называются компонентами
(компоненты формы). В программе форма и компоненты рассматриваются как
объекты. Этим можно объяснить то, что окно, в котором находятся свойства
компонентов, называется Object Inspector.
  Чтобы добавить к форме компонент, надо в палитре компонентов (рис. 32)
щелкнуть.на пиктограмме нужного компонента, и затем щелкнуть кнопкой мыши
в той точке формы, где должен находиться правый верхний угол компонента. В
результате в форме появляется компонент стандартного размера.
  Метка Поле редак- Командная тирования кнопка
Рис. 32. Пиктограммы стандартной палитры компонентов
Добавить к форме компонент нужного размера можно следующим образом. После
щелчка на палитре компонентов нужно поместить курсор мыши в ту точку
формы, где должен находиться левый верхний угол компонента, нажать кнопку
мыши и, удерживая ее нажатой, переместить курсор в точку, где должен быть
правый нижний угол компонента, затем отпустить кнопку мыши. В форме
появится компонент нужного размера.
  На рис. 33 представлен вид формы после добавления к ней поля
редактирования.


  44 Delphi 3. Программирование на Object Pascal

  Рис. 33. Форма с одним компонентом - полем редактирования
Компонент формы, окруженный восемью маленькими квадратиками, называется
выделенным (маркированным). Свойства маркированного компонента
отображаются в окне Inspector Object. Ниже, в таблице, перечислены
основные свойства компонента, называемого полем редактирования.
  Свойство
Обозначение
Имя поля. Используется в программе для доступа к содержимому (тексту) поля
Name
Текст, находящийся в поле ввода-редактирования
Text
Расстояние от левой границы поля до левой границы формы
Left
Расстояние от верхней границы поля до верхней границы формы
Top
Высота поля
Height
Ширина поля
Width
Шрифт, используемый для отображения вводимого текста
Font
Признак наследования свойств шрифта родительской формы
ParentFont

  Delphi позволяет легко изменить положение и размер компонента. Чтобы
изменить положение компонента, надо установить курсор мыши на изображение
компонента, нажать левую кнопку мыши и, удерживая ее нажатой, переместить
изображение границы компонента в нужную точку формы. Затем отпустить
кнопку мыши.
  Чтобы изменить размер компонента, надо его маркировать (щелкнуть на
изображении компонента), установить указатель мыши на один из квадратиков,
помечающих границу компонента, нажать левую кнопку мыши и, удерживая ее
нажатой, изменить положение границы компонента. Затем отпустить кнопку
мыши.
  Так же, как свойства формы, свойства компонента можно изменить в окне
Object Inspector. Чтобы свойства требуемого компонента появились в данном
окне, надо маркировать нужный компонент, или выбрать его имя из
раскрывающегося списка объектов, кнопка раскрытия которого находится в
верхней части окна Object Inspector (рис. 34).

  Delphi - среда визуального программирования 45

  Ниже приведены свойства поля редактирования. предназначенного для ввода
веса в фунтах.
  Name
Edit-1
Text


  Top

                                48

  Left

                                24

  Height

                                24

  Width

                                121


  Рис. 34. Развернутый список объектов диалогового окна Object Inspector
Помимо полей редактирования окно формы должно содержать поясняющий текст:
краткое информационное сообщение.
  Текст, находящийся в форме, называется меткой. Добавляется метка к форме
точно так же, как и поле редактирования. Пиктограмма метки (большая буква
А) находится в палитре компонентов перед пиктограммой поля редактирования.
После того как метка добавлена, можно, используя окно Object Inspector,
изменить ее свойства.
  К форме разрабатываемого приложения надо добавить две метки. Первая метка
будет представлять собой информационное сообщение. Вторая метка
предназначена для вывода результата пересчета веса из фунтов в килограммы.
  После добавления меток и установки значений их свойств, форма
разрабатываемого приложения приобретает вид, представленный на рис. 35.
  Рис. 35. Вид формы после добавления меток
Ниже, в таблице, приведены свойства меток Label l и Label2.
  Name
Label!
  Label2
Caption
Введите вес в фунтах и щелкните на Пересчет


  AutoSize
false
false



  46_______________________Delphi 3. Программирование на Object Pascal

  (окончание)
Name
LabeH
LabelZ
Top

                                8

  96
Left

                                24

  24
Height

                                33

  49
Width

                                209

  121
Wordwrap
true
true
ParentFont
true
false

  Свойство ParentFont метки Label 2 имеет значение false, поэтому свойство
Font этой метки не наследует значения свойства Font "родителя", в данном
случае основной формы. Это дает возможность установить свойства шрифта
метки иные, чем у формы. У метки Labell значение свойства ParentFont
оставлено без изменения.
  Если свойство Autosize (автоматический подгон размера) имеет значение
true, то Delphi автоматически устанавливает размеры метки в зависимости от
количества символов текста метки, используемого шрифта и его размера. Если
надо, чтобы метка представляла собой текст из нескольких строк, то
свойству Autosize надо присвоить значение false и вручную установить
значения свойств, определяющих ее размер.
  В завершение к форме надо добавить командную кнопку, при щелчке на которой
будет выполняться пересчет введенного в поле ввода веса в фунтах в вес в
килограммах. Кнопка добавляется в форму точно так же, как и другие
компоненты. Пиктограмма командной кнопки, в виде кнопки ОК, находится на
палитре стандартных компонентов. После добавления кнопки с помощью
диалогового окна Object Inspector надо установить требуемые значения ее
свойств, которые представлены ниже в таблице.
  Name
Buttoni
Caption
Пересчет
Top

                                56

  Left

                                184

  Height

                                25

  Width

                                75


  Окончательный вид формы приложения пересчета веса из фунтов в килограммы
представлен на рис. 36.


  Delphi - среда визуального программирования 47

  Рис. 36. Форма приложения решения квадратного уравнения
Событие и процедура обработки события
Вид созданной формы подсказывает, как работает приложение. Очевидно, что
пользователь должен ввести значение веса в фунтах в поле редактирования,
затем щелкнуть на кнопке Пересчет. Щелчок на изображении командной кнопки
- это пример того, что в Windows называется событием. Событие - это то,
что происходит во время работы приложения. В Delphi у каждого события есть
имя, например, щелчок кнопкой мыши это событие ondick, двойной щелчок -
событие OnDblciick.
  Ниже, в таблице, приведены некоторые события Windows.
  Событие
OnClick
Происходит при щелчке кнопкой мыши
OnDblClick
Происходит при двойном щелчке кнопкой мыши
OnEnter
Происходит перед тем, как элемент управления действительно получает фокус
OnError
Происходит, когда элемент контроля обнаруживает ошибку и не может вернуть
информацию об ошибке вызывающей программе
OnExit
Происходит непосредственно перед тем, как элемент управления теряет фокус
OnKeyDown
Происходит при нажатии на клавишу. События OnKeyDown и OnKeyPress - это
чередующиеся, повторяющиеся события, которые происходят до тех пор, пока
не будет отпущена удерживаемая клавиша (в этот момент происходит событие
OnKeyUp)
OnKeyPress
Происходит, когда пользователь нажимает клавишу, которая генерирует
печатаемый символ. Может происходить также при нажатии клавиши печатаемого
символа с "Ctrl". He происходит при нажатии клавиш "Tab", "Enter", клавиш
перемещения курсора
OnKeyUp
Происходит при отпускании нажатой клавиши
OnMouseDown
Происходит при нажатии кнопки мыши
OnMouseMove
Происходит при перемещении мыши
OnMouseUp
Происходит при отпускании кнопки мыши


  48 Delphi 3. Программирование на Object Pascal

  Реакцией на событие должно быть какое-либо действие. Например, реакцией на
событие Ondick, произошедшее на кнопке Пересчет, должен быть пересчет веса
из фунтов в килограммы. В Delphi реакция на событие реализуется как
процедура обработки события. Таким образом, задача программиста состоит в
написании необходимых процедур обработки событий.
  Методику создания подобных процедур рассмотрим на примере процедуры
обработки события для кнопки.
  Сначала следует маркировать (выделить) объект, для которого создается
процедура обработки события, в нашем случае это командная кнопка Пересчет.
Затем выбрать вкладку Events (события) окна Object Inspector. В результате
этих действий в окне Object Inspector появится вкладка со списком событий,
которые способен воспринимать маркированный компонент, в данном случае -
командная кнопка (рис. 37).



  Рис. 37. Вкладка Events командной кнопки Пересчет
Рис. 38. Окно редактора кода с макетом процедуры обработки события


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


  Delphi - среда визуального программирования_____________________49

  цедура обработки события. Вторая часть имени идентифицирует сам объект и
событие. В нашем случае имя формы - Fonnl, Bottoni - имя командной кнопки
Вычислить, а имя события - click.
  
В окне редактора кода, между begin и end, можно печатать инструкции Object
Pascal, реализующие процедуру обработки события.
  Ниже приведен текст процедуры для события Ondick на кнопке Пересчет.
  procedure TForml.ButtonlClick(Sender: TObject);
var
f:real; { вес в фунтах }
k:real; ( вес в килограммах } begin
f:= StrToFloat(Editi.Text) ;
k:= f*0.4059;
label2.caption:=Editl.text+' фунт(а/ов) это '+
FloatToStrF(k,ffGeneral,4,2)+ ' килограмм(а/ов)';
end;
Исходные данные программа получает из поля редактирования Editi,
обращением к свойству Text. Свойство Text содержит строку символов, текст,
поэтому, для преобразования изображения числа в число, в программе
используется ФУНКЦИЯ StrToFloatF.
  Вывод вычисленного значения программа осуществляет в поле метки Label2,
присвоением ее свойству Caption метки значения - текста сообщения.
  Редактор кода Delphi
Редактор кода Delphi автоматически выделяет ключевые слова языка
программирования Object Pascal (begin, end, procedure, const, var И Другие)
полужирным, что делает текст программы более выразительным, облегчает
восприятие структуры программы.
  Кроме ключевых слов, редактор выделяет комментарии. Как только программист
напечатает символ начала комментария, открывающую фигурную скобку, текст,
стоящий после этой скобки, меняет свой вид. После того как программист
поставит закрывающую скобку комментария, текст, находящийся после этой
скобки, приобретает обычный вид.
  Контекстно-зависимая справочная система
Редактор кода снабжен контекстно-зависимой справочной системой, которая
автоматически, во время набора текста программы, выводит справочную
информацию о процедурах и функциях языка программирования.


  50 Delphi 3. Программирование на Object Pascal

  Например, если во время набора текста программы напечатать слово
"StrToFloat", которое является именем функции преобразования строки
символов в действительное число, и после него поставить открывающую
скобку, то на экране появится маленькое окно, в котором будет указан тип
параметра функции (рис. 39).
  Рис. 39. Пример подсказки справочной системы Delphi
Справочная система
При наборе текста программы можно получить справку о конструкции языка
программирования, процедуре или функции. Для этого надо в окне редактора
кода напечатать слово, о котором надо получить справку, установить курсор
на любую его букву и нажать функциональную клавишу "F1". Например, если
курсор поместить на слово real и нажать "П", то на экране появится окно,
изображенное на рис. 40.
  Рис.40.Пример диалогового окна справочной системы Delphi


  Delphi - среда визуального программирования 51

  Как правило, с одним словом в справочной системе связано несколько
разделов, поэтому, для получения справки по конкретному разделу надо в
списке выбрать его название и щелкнуть на кнопке Вывести.
  " Другой способ получить справку - это из меню Help выбрать команду
Keyword Search и в открывшемся окне справочной системы, в поле Введите
первые буквы нужного слова, ввести слово, по которому нужно получить
справку.
  Сохранение проекта
В терминологии Delphi проект - это набор файлов, используя которые
компилятор создает файл исполняемой программы. Один из файлов проекта,
который называется файлом проекта и имеет расширение dpr, содержит общее
описание проекта. Помимо файла проекта, проект включает в себя один или
более модулей (Unit - модуль). Файлы модулей проекта имеют расширение pas,
и содержат тексты процедур, функций, описания типов и прочую информацию,
необходимую компилятору для создания исполняемой программы.
  Чтобы сохранить проект, надо из меню File выбрать команду Save Project As.
Если проект еще ни разу не был сохранен, то в ответ на команду сохранения
проекта Save Project As Delphi сначала выводит диалоговое окно Save Uniti
As (рис. 41).
  Рис. 41. Диалоговое окно Save Unit1 As
В этом окне следует выбрать папку, предназначенную для хранения всех
проектов Delphi.
  Замечание
Если при настройке ярлычка для запуска Delphi в качестве рабочего каталога
была задана папка проектов Delphi, то в результате выбора команды Save
Project As в диалоговом окне сразу выводится содержимое этой папки.


  52 Delphi 3. Программирование на Object Pascal

  В папке проектов Delphi следует создать новую, отдельную папку для файлов
сохраняемого проекта. Для этого надо щелкнуть на кнопке Создание новой
папки (рис. 42).
  Рис. 42. Кнопка Создание новой папки
Рядом с появившимся значком новой папки, в рамке, следует напечатать имя
папки проекта, например, Фунты-килограммы, и нажать "Enter", после чего
двойным щелчком на значке созданной папки раскрыть ее. Затем в поле Имя
файла надо ввести имя программного модуля, например FuntToKg, и щелкнуть
на кнопке Сохранить (рис. 43).

  Рис. 43. Сохранение модуля проекта


  После щелчка на кнопке Сохранить в диалоговом окне Save Uniti As
появляется следующее диалоговое окно - Save Projecti As (рис. 44).

  Рис. 44. Диалоговое окно Save Projecti As


  Delphi - среда визуального программирования______________________53

  В поле Имя файла следует ввести имя файла проекта.
  С Замечание ^)
Хотя файлы, имеющие одинаковые имена, но разные расширения операционной
системой рассматриваются как разные файлы, однако при попытке присвоить
файлу проекта такое же имя, которое было уже присвоено модулю проекта,
Delphi выводит диалоговое окно с сообщением об ошибке: The project already
contains a form or module named... (Проект уже содержит форму или модуль,
который называется...). Это следует учитывать при определении имени файла
проекта и имен файлов модулей. Следует обратить внимание, что имя
исполняемого файла программы, создаваемого компилятором, совпадает с
именем файла проекта. Поэтому файлу проекта следует присвоить такое имя,
которое, по вашему мнению, должен иметь файл исполняемой программы, а
файлу модуля - какое-либо другое, например, полученное из имени файла
проекта путем добавления в конец имени, например цифры - порядкового
номера формы проекта, или другого символа.
  Компиляция
После ввода текста процедуры обработки события и сохранения проекта можно,
выбрав команду Compile из меню Project, откомпилировать приложение. Если в
программе нет синтаксических ошибок, то на экране появляется окно
Compiling, информирующее о результатах компиляции (рис. 45).




  Рис. 45. Сообщение о результате компиляции
В этом окне выводится количество обнаруженных компилятором ошибок
(Errors), количество предупреждения (Warnings) и количество подсказок
(Hints).
  Следует обратить внимание, что после установки Delphi среда
программирования автоматически настраивается таким образом, что окно с
сообщением о результатах компиляции на экране не появляется. Чтобы после
завершения компиляции окно Compiling появлялось на экране, надо из меню
Tools выбрать команду Environment Options, в открывшемся диалоговом окне
(рис. 46) выбрать вкладку Preferences и установить флажок Show compiler
progress, находящийся в группе Compiling and Running, затем щелкнуть на
кнопке ОК.


  54 Delphi 3. Программирование на Object Pascal

  Рис. 46. Диалоговое окно Environment Options
Ошибки времени компиляции
Во время компиляции текст программы проверяется на отсутствие
синтаксических ошибок. Компилятор просматривает программу от начала и если
обнаруживает ошибку, то процесс компиляции приостанавливается и в
появившемся окне Compiling, в поле Errors, указывается количество ошибок,
которое, как правило, равно двум. Первая ошибка - это первая от начала
текста синтаксическая ошибка, обнаруженная компилятором. Наличие в тексте
даже одной синтаксической ошибки приводит к возникновению второй,
фатальной, - невозможности генерации исполняемой программы.
  После щелчка на ОК окно Compiling исчезает, и в окне редактора кода
выделяется строка, которая, по мнению компилятора, содержит ошибочную
конструкцию (рис. 47).
  В нижнюю часть окна редактора кода компилятор выводит сообщения об
ошибках. Если размер окна редактора кода недостаточен, чтобы сообщение об
ошибке полностью было отображено, то в конце сообщения указываются три
точки. В этом случае можно развернуть окно редактора кода на весь экран
или поместить курсор мыши на слово Error, в результате чего появится
всплывающее окно, содержащее весь текст сообщения об ошибке.
  Здесь следует обратить внимание на то, что строка, выделенная
компилятором, не всегда содержит ошибку. Довольно часто ошибочной является
инструкция, находящаяся в предыдущей строке. Так, в приведенном примере
(рис.47) инструкция k:=f*o.4059; верная, хотя и помечена компилятором как
ошибочная. Ошибку содержит предыдущая строка программы, в ко-


  Delphi - среда визуального программирования 55

  торой после инструкции f:=StrToFloat (Editl.Text) не поставлен символ
"точка с запятой".
  Рис. 47. Пример выделения компилятором ошибочной строки программы
Ниже, в таблице, приведены сообщения о наиболее типичных ошибках.
  Сообщение компилятора
Вероятная причина
Undeclared identifier (Необъявленный идентификатор)
- используется переменная, не объявленная в разделе var программы;
- ошибка при написании имени объявленной переменной, например, объявлена
переменная Summa, а в тексте программы написано Suma: = ....;
- ошибка при написании имени инструкции, например, вместо const написано
conts
Unterminated string (Незавершенная строка)
- при записи строковой константы не поставлена завершающая кавычка
Incompatible types ...and ... (Несовместимые типы)
- в инструкции присваивания тип выражения не соответствует или не может
быть приведен к типу переменной, получающей значение выражения
Missing operator or semicolon (Отсутствует оператор или точка с запятой)
- не поставлена точка с запятой после инструкции программы

  Если синтаксических ошибок в программе нет, компилятор создает исполняемый
файл программы, который позже можно будет запустить из Windows. Имя
исполняемого файла такое же, как и у файла проекта, расширение - exe.
Delphi помещает исполняемый файл в тот каталог, где находится файл проекта.

  56 Delphi 3. Программирование на Object Pascal



  Предупреждения и подсказки компилятора
При обнаружении в программе неточностей, которые не являются ошибками,
компилятор выводит подсказки (Hints) и предупреждения (Warnings).
  Например, наиболее часто выводимой подсказкой является сообщение об
объявленной, но не используемой в программе переменной (Variable ... is
declarated but never used ...). Действительно, зачем объявлять переменную
и не использовать ее?
  Типичным предупреждением (Warnings) является: Variable ... might not have
been initialized. (Переменной, вероятно, не присвоено начальное значение.)
Запуск приложения из среды программирования
Пробный запуск приложения можно выполнить непосредственно из среды
программирования, не заверщая работу с Delphi. Для этого надо выбрать
команду Run из меню Run.
  На рис. 48 приведен вид одноименного окна работающего приложения
Фунты-килограммы после ввода веса в фунтах и щелчка на командной кнопке
Пересчет.
  Рис. 48. Пример работы приложения фунты-килограммы
Окно приложения - это обычное окно Windows. Его можно перемещать по
экрану, можно развернуть на весь экран, можно свернуть и представить в
виде пиктограммы.
  Ошибки времени выполнения приложения
Во время работы приложения могут возникать ошибки, которые называют
ошибками времени выполнения или исключениями (exceptions). В большинстве
случаев причинами исключений являются неверные исходные данные. Например,
если в программе пересчета веса из фунтов в килограммы число фунтов ввести
не цифрами, а, например, словом "полтора", то после щелчка на кнопке
Пересчет произойдет ошибка и на экран будет выведено окно с сообщением об
ошибке (рис. 49).


  Delphi - среда визуального программирования 57

  Рис. 49. Пример окна с сообщением об ошибке времени выполнения
Замечание
В тексте программы дробная часть числовой константы от целой части
отделяется точкой. Во время работы программы, при вводе исходных данных,
пользователь может отделить дробную часть числа от целой точкой или
запятой. Какой из этих двух символов является допустимым, зависит от
настройки Windows (рис. 50).
  Так, например, если в настройке Windows указано, что разделитель целой и
дробной частей числа - запятая (для России это стандартная настройка), и
если во время работы приложения пользователь введет в поле редактирования,
например, строку 12.34, то при выполнении инструкции
p:=StrToFloat(Editl.Text)
возникает исключение, так как при указанной выше настройке Windows
содержимое поля ввода и, следовательно, аргумент функции strToFloat, не
является изображением дробного числа. (Предполагается, р - это переменная
типа real, a Editi - имя одного из полей ввода приложения).
  Рис. 50. Диалоговое окно Windows Свойства: Язык и стандарты


  58 Delphi 3. Программирование на Object Pascal

  Если программа запускается из Delphi, то при возникновении исключения
появляется окно с сообщением об ошибке и выполнение программы
приостанавливается. При этом в окне редактора кода Delphi выделит
инструкцию, при выполнении которой возникло исключение (рис. 51).
  Рис. 51. Пример возникновения исключения при запуске программы из Delphi
После щелчка на кнопке ОК можно продолжить выполнение программы, для этого
надо из меню Run выбрать Step Over. Для завершения работы приложения надо
из меню Run выбрать Program Reset.
  Разрабатывая проект программист должен предусмотреть все возможные
варианты некорректных действий пользователя, которые могут привести к
возникновению ошибок времени выполнения, и обеспечить способы защиты от
них.
  В Delphi существуют специальные способы защиты от возможных ошибок времени
выполнения, которые будут рассмотрены позже, в соответствующем разделе
книги.
  Окончательная настройка приложения
После того как программа отлажена, необходимо выполнить ее окончательную
настройку: назначить приложению значок, который будет изображать
исполняемый файл приложения в папке или на рабочем столе. Этот же значок
будет изображать системное меню в главном окне приложения во время его
работы и работающее приложение на панели задач Windows.
  Чтобы назначить приложению значок, надо из меню Project выбрать команду
Options, затем, в открывшемся диалоговом окне Project Options вкладку
Application (рис. 52).
  В поле Title (заголовок) следует ввести название приложения. Название
приложения, во время его работы, выводится на панели задач Windows рядом
со значком, изображающим это приложение.


  Delphi - среда визуального программирования 59

  Рис. 52. Вкладка Application диалогового окна Project Options
Чтобы назначить приложению значок, надо щелкнуть на командной кнопке Load
Icon (загрузить значок). В открывшемся окне Application Icon (рис. 53),
просматривая каталоги компьютера, следует найти файл подходящего значка
(значки хранятся в файлах с расширением ico), и щелкнуть на кнопке Открыть.
  Рис. 53. Диалоговое окно выбора файла значка для приложения
В результате диалоговое окно Application Icon закрывается, и вновь
появляется диалоговое окно Project Options, в котором изображается
выбранный значок. После этого следует щелкнуть на кнопке ОК.


  60 Delphi 3. Программирование на Object Pascal

  Создание уникального значка для приложения

  В состав Delphi входит программа Image Editor (редактор изображений), при
помощи которой программист может создать для своего приложения уникальный
значок.
  Чтобы начать работу по созданию нового значка, надо из меню Tools главного
окна Delphi выбрать команду Image Editor, затем, в появившемся окне
редактора изображений, из меню File, выбрать команду New и в появившемся
уточняющем списке команду Icon File.
  В результате этих действий появляется диалоговое окно Icon Properties
(свойства значка) (рис. 54), в котором выбраны стандартные для значков
Windows свойства: размер 32 на 32 пикселя, 16 цветов.
  Рис. 54. Диалоговое окно Icon Properties
После щелчка на кнопке ОК появляется новое окно (рис. 55), в котором
профаммист может, используя инструменты и палитру Image Editor, нарисовать
нужный значок.
  Рис. 55. Диалоговое окно Image Editor
Процесс создания изображения в Image Editor практически ничем не
отличается от процесса создания картинок при помощи Microsoft Paint. Однако


  Delphi - среда визуального программирования______________________61_

  есть одна тонкость. Первоначально поле картинки закрашено "прозрачным"
(transparent) цветом. Если картинку нарисовать на этом фоне, то при
использовании значка, части поля изображения, закрашенные "прозрачным"
цветом, будут закрашены тем цветом, на фоне которого будет находиться
значок.
  Во время создания картинки можно удалить, стереть, ошибочно нарисованные
элементы, закрасив их прозрачным цветом, которому на палитре соответствует
левый квадрат в нижнем ряду (рис. 56).
  "Инверсный"
"Прозрачный" Основные цвета Image Editor
цвет Рис. 56. Палитра Image Editor
Кроме прозрачного цвета, палитра Image Editor предоставляет программисту
инверсный цвет. Нарисованные этим цветом части рисунка при выводе значка
на экран окрашиваются инверсным, по отношению к цвету фона, на котором
значок изображается, цветом.
  После того как значок нарисован, его следует сохранить в файле. Для этого
надо из меню File выбрать команду Save, в открывшемся окне выбрать папку с
файлами проекта, для которого предназначен значок, задать имя файла и
щелкнуть на кнопке Сохранить.
  Созданный значок можно связать с приложением так, как было описано выше.
  Установка приложения
Значок приложения можно поместить на рабочий стол или в одну из
подструктур пункта Программы главного меню Windows. Также можно для
приложения создать новый подпункт в меню Программы.
  С Замечание ^
Подпункты меню Программы также называют группами программ.
  Чтобы установить приложение, надо из главного меню Windows выбрать команду
Настройка, затем - команду Панель задач. В появившемся диалоговом окне на
вкладке Настройка меню щелкнуть на командной кнопке Добавить... (рис. 57).
  В результате этих действий появляется диалоговое окно Создание ярлыка
(рис. 58).


  62 Delphi 3. Программирование на Object Pascal

  Рис. 57. Вкладка Настройка меню
Рис. 58. Диалоговое окно Создание ярлыка
В этом диалоговом окне в поле Командная строка надо ввести имя файла
исполняемого приложения с указанием пути к нему.
  Для ввода имени файла приложения можно воспользоваться командной кнопкой
Обзор..., после щелчка на которой появляется диалоговое окно для поиска
нужного файла.
  Замечание
При "ручном" вводе командную строку следует заключить в двойные кавычки.

  63 Delphi-среда визуального программирования



  После ввода командной строки надо щелкнуть на командной кнопке Далее" и в
появившемся диалоговом окне Выбор папки (рис. 59) выбрать одну из
существующих групп программ меню Программы.
  KH^cZZI^3^ в новую группу' над0 ^^ на --^ной ^o^aSe^""(tm) имя новой
профаммной 1РУППЫ- -Р-
Рис. 59. Создание новой программной группы
^="^г ^ == s^r^60^
^фГ0^" рядом с0 3"aчкш" "эшбPaжa""" п^фаммувТГк:
  Рис. 60. Диалоговое окно Выбор названия программы


  64_______________________Delphi 3. Программирование на Object Pascal

  После щелчка на командной кнопке Готово в указанной командной группе
появляется строка, позволяющая запустить созданное приложение выбором
команды из главного меню Windows.
  Структура простого проекта Delphi
Проект Delphi представляет собой набор программных единиц - модулей. Один
из модулей, главный, содержит инструкции, с которых начинается выполнение
программы. Главный модуль приложения формирует Delphi.
  Ниже приведен текст главного модуля программы пересчета веса из фунтов в
килограммы.
  С Замечание ^
Главный модуль хранится в файле с расширением dpr. Чтобы увидеть текст
главного модуля приложения, надо из меню View выбрать команду Project
Source.
  program FuntToKg;
uses Forms, FuntToKgl in 'FuntToKgl.pas' (Fonnl);
($R *.RES)
begin
Application.Initialize;
Application. Title := 'Фунты-Жилограммы';
Application.CreateForm(TForml, Formi) ;
Application.Run;
end.
  Начинается главный модуль словом program, за которым следует имя
программы, совпадающее с именем проекта. Имя программы задается
программистом в момент сохранения файла проекта и оно определяет имя
создаваемого компилятором исполняемого файла программы. Далее, за словом
uses, следуют имена используемых модулей: библиотечного модуля Forms и
МОДУЛЯ формы FuntToKgl.
  Похожая на комментарий директива ( $R* . RES " указывает компилятору, что
нужно использовать файл ресурсов, который содержит описания ресурсов
приложения, например, пиктограммы. Звездочка показывает, что имя файла
ресурсов такое же, как и у файла проекта, но с расширением res.
  ( Замечание ^
Файл ресурсов не является текстовым файлом и просмотреть его с помощью
редактора текста нельзя. Для работы с файлами ресурсов используют специ-


  Delphi - среда визуального программирования_____________________65_

  апьные программы, например, Resource Workshop. Можно использовать также
входящую в состав Delphi утилиту Image Editor, доступ к которой можно
получить выбрав команду Image Editor из меню Tools.
  Выполняемая часть главного модуля находится между инструкциями begin и
end. Инструкции исполняемой части обеспечивают инициализацию приложения и
вывод на экран стартового окна.
  Помимо главного модуля каждая программа включает в себя как минимум один
модуль формы, который содержит описание стартовой формы приложения и
поддерживающих ее работу процедур. В Delphi каждой форме соответствует
свой модуль.
  Ниже приведен текст модуля формы программы пересчета веса из фунтов в
килограммы.
  unit FuntToKgl;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TFonnl = class (TFonn)
Label 1: TLabel;
Editi: TEdit;
Buttoni: TButton;
Label2: TLabel;
procedure ButtonlClick(Sender: TObject);
private
( Private declarations } public
( Public declarations ) end;
var
Fonnl: TFonnl;
implementation ($R *.DFM)
procedure TFonnl.ButtonlClick(Sender: TObject);
var
f:real; { вес в фунтах }
d,k:real; ( вес в килограммах }
begin
( ввод исходных данных} f:=StrToFloat(Editi.Text);


  66_______________________Delphi 3. Программирование на Object Pascal

  { вычисление) k:=f*0.4095;
{ вывод результата )
label2.caption:=Editl.text+' фунт(а/ов) это' +
FloatToStrF(k,ffGeneral,4,2)+ ' килограмм(а/ов)';
end;
end.

  Начинается модуль словом unit, за которым следует имя модуля. Именно это
имя упоминается в списке используемых модулей в инструкции uses главного
модуля приложения, текст которого был приведен выше.
  Состоит модуль из трех разделов: интерфейса, реализации и инициализации.
  Раздел интерфейса (начинается словом interface) сообщает компилятору,
какая часть модуля является доступной для других модулей программы. Здесь
перечислены используемые модулем другие библиотечные модули, находится
сформированное Delphi описание формы (типа), которое следует за словом
Type.
  Раздел реализации (начинается словом implementation) содержит объявления
локальных переменных, процедур и функций, поддерживающих работу формы.
  Начинается раздел реализации директивой ($R *.DFM}, указывающей
компилятору, что в раздел реализации надо вставить инструкции установки
значений свойств формы, которые находятся в файле с расширением dfm, имя
которого совпадает с именем модуля. Файл в формате DFM генерируется Delphi
на основе внешнего вида формы.
  За директивой ($R *.DFM) следует описание процедур обработки событий
формы. Сюда же программист может поместить описание своих процедур и
функций, которые могут вызываться из процедур обработки событий.
  Раздел инициализации позволяет выполнить инициализацию переменных модуля.
Инструкции раздела инициализации располагаются после раздела реализации
между begin и end. Если раздел инициализации не содержит инструкций (как в
приведенном примере), то слово begin не указывается.
  Следует отметить, что значительное количество инструкций модуля
записываются Delphi. Например, Delphi, анализируя действия программиста по
созданию формы, формирует описание класса формы. В приведенном примере
инструкции, набранные программистом, выделены цветом. Очевидно, что Delphi
выполнил значительную часть работы по составлению текста программы.


  УПРАВЛЯЮЩИЕ СТРУКТУРЫ

  OBJECT PASCAL


  Алгоритмы решения большинства задач не являются последовательными.
Действия (вычисления), которые необходимо выполнить, могут зависеть от
определенного условия, например, входных данных, или результатов,
полученных во время выполнения программы. Например, в программе проверки
знаний оценка за выбранный из нескольких вариантов ответ, добавляемая к
общей сумме баллов, зависит от того, является ли ответ правильным.
Фрагмент алгоритма решения этой задачи представлен на рис. 61.
  Рис. 61. Пример фрагмента разветляющегося алгоритма
Условие
Условие - это выражение логического типа (Boolean), которое может
принимать одно из двух значений: "истина" (true) или "ложь" (false).
  Простое условие состоит из двух операндов и оператора сравнения. В общем
виде условие записывается следующим образом:
  Оп1 Оператор Оп2
где: оп1 и Оп2 - операнды условия, в качестве которых может выступать
переменная, константа, функция или выражение; Оператор - оператор
сравнения.
  Имеется шесть операторов сравнения, которые приведены ниже. Оператор
Пояснение. Значение выражения
" Больше, true, если первый операнд больше второго, иначе false "
Меньше, true, если первый операнд меньше второго, иначе false


  68^_______________________Delphi 3. Программирование на Object Pascal

  (окончание)
Оператор
Пояснение. Значение выражения
=
Равно, true, если первый операнд равен второму, иначе false
о
Не равно, true, если первый операнд не равен второму, иначе false
"=
Больше или равно, true, если первый операнд больше или равен второму,
иначе false
"=
Меньше или равно, true, если первый операнд меньше или равен второму,
иначе false

  Ниже приведены примеры условий.
  Зшттоа " 1000 Score "= HBound
Sim = Chr(13)
В первом примере операндами условия является переменная и константа.
Значение этого условия зависит от значения переменной summa. Условие будет
верным и, следовательно, иметь значение true, если значение переменной
Summa меньше, чем юоо. Если значение переменной Summa больше или равно
юоо, то значение этого условия будет false.
  Во втором примере в качестве операндов используются переменные. Значение
этого условия будет true, если значение переменной score больше или равно
значению переменной HBound.
  В третьем примере в качестве второго операнда используется функция.
Значение этого условия будет true, если в переменной Sim находится
символьный код клавиши "Enter", равный 13.
  При записи условий следует обратить особое внимание на то, что операнды
условия должны быть одного типа или, если тип операндов разный, то тип
одного из них может быть приведен к типу другого операнда. Например, если
в программе переменная Key объявлена как integer, то условие
Key = Chr(13)
неверное, так как возвращаемое функцией chr значение имеет тип char
(символьный).
  Во время трансляции программы, при обнаружении в программе неверного
условия компилятор выводит сообщение: Incompatible types (несовместимые
типы).
  Из простых условий, которые являются выражениями логического типа, можно
строить сложные условия с применением к ним, как к операндам,


  Управляющие структуры Object Pascal___________________________69

  логических операторов: NOT - отрицание; AND - логическое И; OR -
логическое ИЛИ.
  Результат применения логических операторов к операндам логического типа
представлен в таблице.
  Op1
Op2
Op1 AND Op2
Op1 OR Op2
NOT Op1
false
false
false
false
true
false
true
false
true
true
true
false
false
true
false
true
true
true
true
false

  При записи сложных условий важно учитывать то, что логические операторы
имеют более высокий приоритет, чем операторы сравнения, а поэтому простые
условия следует брать в скобки.
  Например, пусть условие предоставления скидки сформулировано следующим
образом: "Скидка предоставляется, если сумма покупки превышает 100 руб. и
день покупки - воскресенье". Если день недели обозначен как переменная Day
целого типа, и равенство ее значения семи соответствует воскресенью, то
условие предоставления скидки можно записать:
  (Sumrna " 100)AND(Day = 7)
Если условие предоставления скидки дополнить тем, что скидка
предоставляется в любой день, если сумма покупки превышает 500 руб., то
условие можно записать:
  ( (Surnma " 100)AND(Day = 7) ) OR (Suinma " 500)

  Выбор

  Выбор действия в зависимости от выполнения условия может быть реализован
при помощи инструкций if и case.
  Инструкция IF
Выбор действия в зависимости от выполнения условия может быть реализован
при помощи инструкции if. Записывается инструкция так:
  if условие then
begin


  Управляющие структуры Object Pascal 71

  else
z:=(rl+r2)/(rl*r2);
вычисляет суммарное сопротивление цепи в зависимости от типа соединения
сопротивлений.
  Если необходимо произвести какое-либо действие только при выполнении
некоторого условия и пропустить это действие в случае невыполнения
условия, тогда инструкция выбора может быть записана так:
  if условие then begin
( инструкции, которые надо выполнить,
если условие выполняется, истинно } end
На рис. 63 представлена алгоритмическая конструкция, соответствующая
ИНСТРУКЦИИ if-then.


  Рис. 63. Алгоритмическая конструкция, соответствующая инструкции if-then

  Например, инструкция

  if n=m
then с:=с+1 ;
увеличивает значение переменной с только в том случае, если значения
переменных п и m равны.
  В качестве примера использования инструкции if рассмотрим программу
вычисления стоимости телефонного разговора. Как известно, стоимость
разговора по телефону в воскресные дни ниже, чем в обычные дни. Следующая
программа запрашивает длительность разговора и день недели, затем
вычисляет стоимость разговора. Если день недели суббота или воскресенье,
то стоимость уменьшается на величину скидки. Цена минуты разговора и
величина скидки задаются в тексте программы как константы.
  На рис. 64 приведен вид диалогового окна программы.


  70 Delphi 3. Программирование на Object Pascal

  { инструкции, которые надо выполнить,
если условие выполняется, истинно. } end else
begin
{ инструкции, которые надо выполнить, если условие не выполняется, ложно.
} end
Инструкция if выполняется следующим образом:
  1. Вычисляется значение условия (условие - выражение, значение которого
может быть равно true или false).
  2. Если условие выполняется (значение выражения условие равно true), то
выполняются инструкции следующие за словом then, находящиеся между begin и
end. Если условие не выполняется (значение выражения условие равно false),
то выполняются инструкции следующие за словом else (находящиеся между
begin И end) .
  Замечание
Если при выполнении (невыполнении) условия надо выполнить только одну
инструкцию, то слова begin и end после then (else) могут быть опущены.
  На рис. 62 представлена алгоритмическая конструкция, соответствующая
ИНСТРУКЦИИ if-then-else.

  Рис. 62. Алгоритмическая конструкция, соответствующая инструкции
if-then-else


  Пример
Если переменная t содержит обозначение типа соединения сопротивлений
электрической цепи (t=l соответствует последовательному соединению, t=2 -
параллельному), а переменные rl и г2 содержат величины сопротивлений, то
инструкция
if t=l then
z:=rl+r2


  Управляющие структуры Object Pascal 71

  else
z:=(rl+r2)/(rl*r2);
вычисляет суммарное сопротивление цепи в зависимости от типа соединения
сопротивлений.
  Если необходимо произвести какое-либо действие только при выполнении
некоторого условия и пропустить это действие в случае невыполнения
условия, тогда инструкция выбора может быть записана так:
  if условие then begin
{ инструкции, которые надо выполнить,
если условие выполняется, истинно } end
На рис. 63 представлена алгоритмическая конструкция, соответствующая
инструкции if-then.


  Рис. 63. Алгоритмическая конструкция, соответствующая инструкции if-then
Например, инструкция
if n=m
then c:=c+l;
увеличивает значение переменной с только в том случае, если значения
переменных п и m равны.
  В качестве примера использования инструкции if рассмотрим программу
вычисления стоимости телефонного разговора. Как известно, стоимость
разговора по телефону в воскресные дни ниже, чем в обычные дни. Следующая
программа запрашивает длительность разговора и день недели, затем
вычисляет стоимость разговора. Если день недели суббота или воскресенье,
то стоимость уменьшается на величину скидки. Цена минуты разговора и
величина скидки задаются в тексте программы как константы.
  На рис. 64 приведен вид диалогового окна программы.


  72 Delphi 3. Программирование на Object Pascal

  Рис. 64. Диалоговое окно программы вычисления стоимости телефонного
разговора
Для ввода исходных значений (длительность разговора, номер дня недели)
используются поля редактирования, для вывода результата и пояснительного
текста - поля меток. Ниже перечислены компоненты и приведены значения их
свойств.
  Компонент (имя, свойство Name)
Предназначен для
Edit-1
ввода длительности разговора в минутах
Edit2
ввода номера дня недели
Label-1, Label2
вывода пояснительного текста о назначении полей ввода
Label3
вывода результата вычисления - стоимости разговора
Button"!
  Активизации процедуры вычисления стоимости разговора

  Свойство
Значение
Form"!. Caption
Стоимость разговора
Editl.Text


  Edit2.Text


  Labell.Caption
Длительность (мин.)
Label2.Caption
Номер дня недели
Label3. Caption


  Buttoni .Caption
Вычислить

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


  Управляющие структуры Object Pascal__________________________7.

  В таблицах, содержащих описание значений свойств компонентов формы, ука
зывается имя компонента и через точку имя свойства. Например, строка
таблицы
Form"!. Caption Стоимость разговора
обозначает, что во время создания формы приложения, свойству caption формы
приложения надо присвоить указанное значение - текст "Стоимость разговора".

  Программа производит вычисления при щелчке на командной кнопке Вычислить.
В этом случае возникает событие ondick, процедура обработки которого
приведена ниже.
  procedure TFoml.ButtonlClick (Sender: TObject);
const
PAY=0.15; (цена одной минуты разговора 0.15 рубля! DISCOUNT=20; {скидка
20 процентов) var
Time:real; { длительность разговора )
Day:integer; ( день недели }
SuiTOia: real; { стоимость разговора } begin
(получить исходные данные)
Time:=StrToFloat(Editi.Text) ;
Day:=StrToInt(Edit2.Text) ;
( Вычислить стоимость разговора } Summa:= PAY*Time;
{ Если день суббота или воскресенье, то уменьшить
стоимость на величину скидки } if (Day = 6) OR (Day = 7)
then Sunima:=Surnma* (100-DISCOUNT) /100;
{ вывод результата вычисления ) label3.caption:='К оплате '
+FloatToStr(Summa)+'py6.';
end;
Часто в программе необходимо реализовать выбор более чем из двух
вариантов. Например, известно, что для каждого человека существует
оптимальное значение веса, которое может быть вычислено по формуле: рост
(см)-юо. Очевидно, что реальный вес может отличаться от оптимального: вес
может быть меньше оптимального, равняться ему или превышать оптимальное
значение.
  Следующая программа (ее алгоритм приведен ниже на рис. 65) запрашивает вес
и рост, вычисляет оптимальное значение, сравнивает его с реальным и
выводит соответствующее сообщение.


  74 Delphi 3. Программирование на Object Pascal




  Рис. 65. Алгоритм программы контроля веса
Диалоговое окно программы Контроль веса изображено на рис. 66, в таблицах
приведены значения свойств компонентов диалогового окна.
  Рис. 66. Диалоговое окно программы Контроль веса
Как и в предыдущей программе, вычисления выполняются при щелчке на кнопке
Вычислить (ее имя Buttoni). Ниже приведена процедура обработки события
ondick для этой командной кнопки.
  procedure TFormI.ButtonlClick(Sender: TObject) ;
var
w:real; ( вес }
h:real; { рост }
opt:real; { оптимальный вес }
d:real; ( отклонение от оптимального веса }


  Управляющие структуры Object Pascal 75


  begin
w:=StrToFloat(Editl.text) ;
h:=StrToInt(Edit2.Text) ;
opt:=h-100;
if i?=opt then
Label3.caption:='Ваш вес оптимален !' else
if w"opt then begin
d:=opt-w;
Label3.caption:"'Вам надо поправиться, на ' + FloatTostr(d)+ 'кг.';
end else begin
d:=w-opt;
Labe13.capt i on:='Надо немного похудеть, на + FloatTostr(d)+ ' кг.';
end;
end;
В приведенном примере множественный выбор реализован при помощи двух
инструкций if, одна из которых "вложена" в другую. Обратите внимание, что
после инструкций, расположенных перед else, символ "точка с запятой" не
поставлены.
  Инструкция CASE
Инструкция case позволяет реализовать множественный выбор и общем виде
записывается так:
  case выражение of список! констант: begin
( последовательность 1
инструкций ) end;
Список'2 констант: begin
(последовательность2
инструкций ) end;
списокЫ констант: begin
( последовательностьЫ
инструкций } end;


  76 Delphi 3. Программирование на Object Pascal


  else
begin
end;
end;
где
СЧ Выражение - выражение, от значения которого зависит дальнейший ход
программы (последовательность инструкций, которая должна быть выполнена);
П Список констант - константы, разделенные запятыми. Если константы
представляют диапазон чисел, то вместо списка можно указать первую и
последнюю константу диапазона, разделив их двумя точками. Например, список
1,2,3,4,5,6 может быть заменен диапазоном l.. б
Примеры.
  case n day of
1,2,3,4,5: day:"'Рабочий день.';
6: day:='Суббота!';
7: day:='Воскресенье!' ;
end;
case n day of
1..5: day:='Рабочий день.' ;
6: day:='Суббота!' ;
7: day:='Воскресенье!';
end;
case n day of
6: day:='Суббота!';
7: day:='Воскресенье!';
else day:='Рабочий день.';
end;
Выполняется инструкция case следующим образом. Сначала вычисляется
значение выражения после case, затем полученное значение последовательно
сравнивается с константами из списков констант перед двоеточием. Если
значение выражения совпадает с константой из списка, то выполняется
соответствующая последовательность инструкций и на этом выполнение
инструкции case завершается. Если значение выражения не совпадает ни с
одной из констант всех списков, то выполняется последовательность
инструкций после else. Синтаксис инструкции case позволяет не писать else
и соответствующую последовательность инструкций. В этом случае, если
значение выражение не совпадает ни с одной из констант всех списков, то
выполняется следующая за case инструкция программы.

  77 Управляющие структуры Object Pascal



  На рис. 67 приведена блок-схема алгоритма, соответствующего инструкции
case.

  Рис. 67. Блок-схема алгоритма, соответствующего инструкции case


  В качестве примера использования инструкции case рассмотрим программу,
которая пересчитывает вес из фунтов в килограммы, но в отличие от ранее
рассмотренной подобной программы, она учитывает, что в разных странах фунт
"весит" по-разному. Например, в России фунт равен 405,9 грамма, в Англии
453,592 грамма, а в Германии, Дании и Исландии фунт весит 500 грамм.
  В диалоговом окне программы, изображенном на рис. 68, для выбора страны
используется список.
  Рис. 68. Диалоговое окно программы Фунты-килограммы
Список (ListBox) добавляется к форме приложения точно так же, как и другие
компоненты, например, командная кнопка или поле редактирования. Ниже, в
таблице, приведены свойства компонента ListBox.


  78 Delphi 3. Программирование на Object Pascal


  Свойство Обозначение
Имя компонента. В программе используется для доступа свойствам компонента
Name
Элементы списка
Items
Номер выбранного элемента списка. Номер первого элемента списка равен нулю
Item Index
Расстояние от левой границы списка до левой границы формы
Left
Расстояние от верхней границы списка до верхней границы формы
Top
Высота поля списка
Height
Ширина поля списка
Width
Шрифт, используемый для отображения элементов списка
Font
Признак наследования свойств шрифта родительской формы
ParentFont

  Для разрабатываемой программы наибольший интерес представляют два
свойства: Items И Itemlndex.
  Свойство items содержит элементы списка. Список, выводимый в поле списка,
может быть сформирован во время создания формы приложения или динамически,
во время работы программы. Для формирования списка во время создания формы
приложения надо в форме выделить поле списка, затем в окне Object
Inspector выбрать свойство items и щелкнуть на кнопке редактора списка
строк, на которой изображены три точки (рис. 69).
  Рис. 69. Формирование списка с помощью Object Inspector
В появившемся диалоговом окне String list editor (редактор списка строк)
следует набрать список, поместив каждый элемент списка на отдельной строке
(рис.70).
  Ввод очередного элемента списка должен заканчиваться нажатием клавиши
"Enter". После ввода всех элементов списка нужно щелкнуть на кнопке ОК.
  Свойство Itemlndex во время работы программы содержит номер выбранного
элемента списка. Если ни один из элементов списка не выбран, то его
значение равно минус единице.


  Управляющие структуры Object Pascal 79

  Рис. 70. Диалоговое окно String list editor

  Ниже перечислены компоненты формы приложения и приведены значения их
свойств.
  Компонент (имя, свойство Name)
Предназначен для
ListBoxl
выбора страны, для которой надо выполнить пересчет
Edit1
ввода веса в фунтах
Label1,Label2, Labels
вывода пояснительного текста о назначении полей ввода
Label4
вывода результата пересчета
Button 1
активизации процедуры пересчета веса из фунтов в килограммы

  Свойство
Значение
Form1. Caption
Пример использования Case
Edit1 .Text


  Label 1. Caption
Выберите страну, введите количество фунтов и щелкните на Вычислить
Label2.Caption
Страна
Labels. Caption
Фунтов
Buttoni .Caption
Вычислить

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


  80_______________________Delphi 3. Программирование на Object Pascal

  килограммах одного фунта. Значение коэффициента зависит от номера
выбранного элемента списка.
  Ниже приведен текст процедуры обработки события ondick на командной кнопке
Вычислить.
  procedure TFormI.ButtonlClick(Sender: TObject);
var
funt:real; ( вес в фунтах ) kg:real; ( вес в килограммах } k:real; (
коэффициент пересчета } begin case ListBoxl. Itemindex of
0: k:=0.4059; ( Россия } 1: k:=0.453592;( Англия } 2:
k:=0.56001; ( Австрия } 3..5,7: k:=0.5; {
Германия,Дания,Исландия,Нидерланды ) 6: k:=0.31762; ( Италия ) end;
funt:=St rToFloat(Edit 1.Text) ;
kg:=k*funt;
label4.caption:=Editl.Text
+ ' фунт(а/ов) - это '
+ FloatToStrFtkg,ffFixed,6,3)
+ ' кг. ' ;
end;
Вот другой пример использования инструкции case. При выводе числовой
информации с поясняющим текстом возникает проблема согласования выводимого
значения и окончания поясняющего текста. Например, в зависимости от
числового значения поясняющий текст к денежной величине может быть
"рубль", "рублей" или "рубля" (123 рубля, 120 рублей, 121 рубль).
Очевидно, что окончание поясняющего слова определяется двумя последними
цифрами числа, что отражено в приведенной ниже таблице.
  Две последние цифры числа
Поясняющий текст
*0,*5,*6,*7,*8,*9

рублей

                                *1

  рубль
*2,*3,*4,
рубля

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


  Управляющие структуры Object Pascal___________________________81

  Ниже приведен фрагмент программы, которая формирует в переменной Tail
поясняющий текст с правильным окончанием. Предполагается, что переменные п
и г целого типа, а переменная Tail - строкового.
  i п - число }
( г - остаток от деления п на 10 )
{ tail - формируемый поясняющий текст }
( формирование поясняющего текста } if n " 100
then п:=п mod 100;
if ( п "= 11) and ( п "= 14) then
tail:=' рублей' else begin
r:= n mod 10;
case r of
0, 5 .. 9: tail:=' рублей';
1: tail:=' рубль';
2 .. 4: tail:=' рубля' ;
end;
end;
Еще один пример. Приведенный ниже фрагмент программы, используя дату
сегодняшнего дня (представленную тремя переменными day (день), month
(месяц) и year (год)), вычисляет дату следующего, завтрашнего, дня.
  Сначала с помощью инструкции case проверяется, является ли текущий день
последним днем месяца. Если текущий месяц - февраль и если текущее число
28, дополнительно выполняется проверка: является ли год високосным.
Делается это анализом остатка от деления года на четыре (для високосного
года остаток равен нулю). Если год високосный, то число 28 не является
последним днем месяца. Если выясняется, что текущий день - последний день
месяца, то следующее число - первое. Затем проверяется, не является ли
текущий месяц январем, если нет, то увеличивается номер месяца, а если да,
то увеличивается номер года.
  { вычисление даты следующего дня }
var
day:integer;
month:integer-year:integer-last:boolean;(true если последний день месяца }
г:integer; (если год високосный, то остаток от деления year на 4 равен
нулю }


  82 __________________Delphi 3. Программирование на Object Pascal

  begin
( переменные day, month и year содержат сегодняшнюю дату }
last:"false;
case month of
1,3,5,7,8,10,12:if day=31
then last:= true;
4,6,9,11: if day = 30 then last:" true;
2: if ( day " 28) then begin
r:= year mod 4;
if r "" 0 then last:= true;
end;
end;
if last then
begin ( последний день месяца } day:= 1;
if month = 12 then
begin { последний месяц } month:" 1;
year:" year + 1;
end else month:" month + 1;
end else day:" day + 1;
( переменные day, month и year содержат завтрашнюю дату ) end;
Циклы
Алгоритмы решения многих задач являются циклическими, то есть для
достижения результата определенная последовательность действий должна быть
выполнена несколько раз. Например, программа контроля знаний выводит
вопрос, принимает ответ, добавляет оценку за ответ к сумме баллов, затем
повторяет это действие еще и еще раз, и так до тех пор, пока испытуемый не
ответит на все вопросы. Другой пример. Чтобы найти фамилию человека в
списке, надо проверить первую фамилию списка, затем вторую, третью и т. д.
до тех пор, пока не будет найдена нужная фамилия, или не будет дос-


  Управляющие структуры Object Pascal___________________________83

  тигнут конец списка. Такие повторяющиеся действия называются циклами и
реализуются в программе с использованием инструкций циклов.
  Циклические действия (вычисления) могут быть реализованы при помощи
инструкций for, while И repeat.
  Инструкция FOR
Инструкция for используется, если некоторую последовательность действий,
операторов, надо выполнить несколько раз, причем, число повторений заранее
известно. Например, если надо вычислить значения некоторой функции в
нескольких различных, отстоящих на равном расстоянии друг от друга точках
(построить таблицу значений функции).
  В общем виде инструкция for записывается следующим образом:
  for счетчик:=нач знач to кон знач счетчика do begin
( последовательность инструкций, которая называется телом цикла } end
где счетчик - имя переменной-счетчика числа повторений инструкций цикла;
нач_энач - выражение, определяющее начальное значение переменной-счетчика;
кон_знач - выражение, определяющее конечное значение переменной-счетчика.
  Примеры:
  for i:=l to 10 do begin
write('-');
end;
for j:=i+l to n do begin
y:=2*x*x-10;
x:=x+0.5;
end;
С Замечание ^
Если между инструкциями begin и end находится только одна инструкция, то
их можно не писать.


  84 Delphi 3. Программирование на Object Pascal


  Обычно в качестве выражений, определяющих значения начального и конечного
состояния счетчика циклов, используют переменные или константы. В этом
случае последовательность операторов, находящаяся между begin и end, будет
выполнена (кон_знач - нач_знач +1) раз.
  Алгоритм, соответствующий инструкции for представлен на рис. 71. Обратите
внимание, что в случае, если начальное значение счетчика превышает
конечное значение счетчика, то последовательность операторов между begin и
end ни разу не будет выполнена.
  Рис. 71. Алгоритм, соответствующий инструкции for

  Значение переменной счетчика можно использовать в последовательности
инструкции между begin и end. Например, в результате выполнения следующих
инструкций:
  tabl:='';
for i:=l to 5 do
begin
tabl:=tabl+IntToStr(i)+' '+IntToStr(i*i)+chr(13) ;
end;
переменная tabi будет содержать изображения таблицы квадратов чисел.
  Следующая программа вычисляет сумму первых 10 элементов ряда:
  1+1/2+1/3+... (значение i-ro элемента ряда связано с его номером формулой
1/i). После вычисления очередного элемента ряда в поле метки формы,
предназначенное для вывода результата, выводится номер элемента ряда и его
значение.
  Диалоговое окно программы содержит два компонента: поле метки (Labeii) и
командную кнопку (Buttoni). Вычисление суммы ряда и вывод результата
выполняет процедура обработки события ondick, текст которой приведен ниже.
  procedure TFoml.ButtonlClickt Sender: TObject);
var
i:integer; ( номер элемента ряда }


  Управляющие структуры Object Pascal 85

  elenureal; { значение элемента ряда } з1дпт:геа1; ( сумма элементов
ряда ) begin
sunra:=0;
labell.caption:='';
for i:=l to 10 do begin
elem:=l/i;
labell.caption:=labell.caption+
IntToStr(i)+' '+FloatToStr(elem)+#13;
surnm: "surnm+elem;
end;
labell.caption:=labell,caption+
'Сумма ряда:'+FloatToStr(suiroi) ;
end;
Если в инструкции for вместо слова to записать downto, то после очередного
выполнения инструкций цикла, значение счетчика будет не увеличиваться, а
уменьшаться.
  Инструкция WHILE
Инструкция while используется в том случае, если некоторую
последовательность действий /{инструкций программы) надо выполнить
несколько раз, причем, необходимое число повторений во время разработки
программы неизвестно и может быть определено только во время ее работы, т.
е. в процессе вычисления.
  Типичными примерами использования цикла while являются вычисления с
заданной точностью, поиск в массиве или в файле.
  В общем виде инструкция while записывается следующим образом:
  while условие do begin
{ последовательность инструкций } end
где О условие - выражение логического типа.
  Инструкции, находящиеся между begin и end, выполняются до тех пор, пока
условие истинно (значение выражения условие равно true)
Алгоритм, соответствующий инструкции while, представлен на рис. 72.
Обратите внимание:
  О Для того чтобы инструкции цикла, находящиеся между begin и end, были
выполнены хотя бы один раз, необходимо, чтобы перед выполне-

  86 Delphi 3. Программирование на Object Pascal


  нием инструкции while выражение условие было истинно
О Для того чтобы цикл завершился, необходимо, чтобы последовательность
инструкций между begin и end изменяла значения переменных, входящих в
выражение условие
Рис. 72. Алгоритм, соответствующий инструкции while

  Следующая программа вычисляет значение числа п с задаваемой пользователем
точностью. В основе алгоритма вычисления лежит тот факт, что сумма ряда
1-1/3+1/5-1/7+1/9+, если взять достаточно много его членов, приближается к
значению л/4.
  В программе очередной член ряда, с номером п, вычисляется по формуле:
  1/(2*п-1) и умножается на минус один, если его номер четный (определить,
является ли п четным можно, например, проверкой остатка от деления п на
2). Вычисление заканчивается тогда, когда значение очередного члена ряда
становится меньше, чем заданная точность вычисления.
  Рис. 73. Диалоговое окно программы Вычисление ПИ
Вид диалогового окна программы приведен на рис. 73. Пользователь вводит
точность вычисления в поле ввода (Editi). После щелчка на командной кнопке
Вычислить (Buttoni) программа вычисляет значение числа л и выводит
результат в поле метки (Labeii).
  Как и в предыдущих примерах, основную работу выполняет процедура обработки
события ondick, текст которой приведен ниже.
  ( Вычисление числа я с заданной точностью ) procedure
TFonnl.ButtonlClick(Sender: TObject);
var
pi: real; { вычисляемое значение тс" t:real; { точность вычисления}


  Управляющие структуры Object Pascal 87


  n:integer; { номер члена ряда} elem:real; ( значение члена ряда} begin
pi:=J3;
n:=l';
t:=StrToFloat(editl.text) ;
elem:=t+l; { чтобы начать цикл } while elem "= t do begin
elem:=l/(2*n-l) ;
if (n MOD 2) = 0 then pi:=pi-elem else pi:=pi+elem;
n:=n+l;
end;
pi:=pi*4;
labell.caption:= 'ПИ равно '+ FloatToStr(pi) + #13
+ 'Просуммировано '+IntTostr(n)+' членов ряда.';
end;
Инструкция REPEAT...UNTIL
Инструкция repeat.. .until, как и инструкция while, используется в
программе, если надо провести некоторые повторные вычисления
(организовать цикл), причем, необходимое число повторений во время
разработки программы неизвестно и может быть определено только во время
работы программы, т. е. определяется ходом вычисления.
  В общем виде инструкция repeat. . .until записывается следующим образом:
  repeat
{ инструкции } until условие
где условие - выражение логического типа, определяющее условие завершения
цикла.
  Примеры:
  repeat
writeln(i) ;
i:=i+l;
until i=10;
repeat
read (n) ;
if n "" 0 then surnm:=sumn+n;
until n=0;


  88 Delphi 3. Программирование на Object Pascal


  Инструкция выполняется следующим образом:
  1. Выполняются инструкции, находящиеся между словами repeat и until,
инструкции цикла.
  2.
  Вычисляется значение выражения условие. Если условие ложно (значение
выражения условие равно false), то повторно выполняются инструкции цикла.
Если условие истинно (значение выражения условие равно true), то
выполнение цикла прекращается.
  Таким образом, инструкции, находящиеся между repeat и until выполняются до
тех пор, пока условие ложно (значение выражения условие равно false).
  Алгоритм, соответствующий инструкции repeat, .until, представлен на рис.

                                74.


  Обратите внимание:
  D Инструкции цикла, находящиеся между repeat и until, выполняются, как
минимум, один раз;
О Для того чтобы цикл завершился, необходимо, чтобы инструкции цикла,
находящиеся между repeat и until, изменяли значения переменных, входящих в
выражение условие
Рис. 74. Алгоритм, соответствующий инструкции repeat..until
Ниже в качестве примера использования инструкции repeat.. .until приведена
программа, которая проверяет: является ли число, введенное пользователем,
простым. Как известно, число является простым, если оно делится только на
единицу и само на себя. Проверить, является ли число п простым, можно
делением числа на два, на три и т. д. до п и проверкой после каждого
деления остатка. Если после очередного деления остаток равен нулю, то это
значит, что найдено число, на которое п делится без остатка. Сравнив п и
число, на которое п разделилось без остатка, можно определить, является ли
п простым числом.
  Форма приложения Простое число изображена на рис. 75.
  Рис. 75. Форма приложения Простое число


  Управляющие структуры Object Pascal___________________________89


  Ниже перечислены компоненты формы и приведены значения их свойств.
  Компонент (имя, свойство Name)
Предназначен для
Edit-1
ввода числа
Label-l
вывода пояснительного текста о назначении поля ввода
Label2
вывода результата проверки
Button 1
активизации процедуры проверки числа

  Свойство
Значение
Form 1.Caption
Простое число
Edit-l.Text


  Labeh. Caption
Введите целое число
Label2.Caption


  Buttonl.Caption
Проверить

  Процедура проверки, текст которой приведен ниже, выполняется в результате
щелчка на командной кнопке Проверить.
  procedure TForml.ButtonlClick(Sender: TObject) ;
var
n: integer; ( проверяемое число } d: integer; ( делитель ) r: integer; {
остаток от деления п на d) begin
n:=StrTo!nt(Editl.text) ;
d:= 2; { сначала будем делить на два ) repeat
r:= n mod d;
if г о 0 { n не разделилось нацело на d } then d:= d + 1;
until r = 0;
1аЬе12.caption:=Editl.text ;
if d = n
then iabel2. caption: =label2. caption
+ ' - простое число.' else Iabel2. caption: =label2. caption
+ ' - обычное число.' ;



  90 ____________Delphi 3. Программирование на Object Pascal


  Инструкция GOTO

  Инструкции if и case используются для выбора последовательности инструкций
программы в зависимости от некоторого условия, поэтому их иногда называют
инструкциями условного перехода. Помимо этих инструкций управления ходом
выполнения программы существует еще одна - инструкция безусловного
перехода goto.
  В общем виде инструкция goto записывается следующим образом:
  goto Метка
метка - это идентификатор, находящийся перед инструкцией, которая должна
быть выполнена после инструкции goto.
  Метка, используемая в инструкции goto, должна быть описана в разделе меток
программы, который начинается словом label и располагается перед разделом
описания переменных.
  В тексте программы метка ставится перед инструкцией, которая должна быть
выполнена после инструкции goto. Сразу после метки ставится двоеточие.
  Ниже приведена измененная процедура проверки простого числа, в которой для
перехода к последней инструкции процедуры, в случае если пользователь
введет неверные данные, используется инструкция goto.
  procedure TForml.ButtonlClick(Sender: TObject);
label ( раздел объявления меток ) bye;
var
n: integer; ( проверяемое число )
d: integer; ( делитель }
r: integer; { остаток от деления n на d}
begin
n:=StrToInt(Editl.text) ;
if n "= 0 then begin
MessageDlgt"Число должно быть больше нуля.', mtError,Editl.text:= ";
goto bye;
end;
( введено положительное число } d:= 2; { сначала будем делить на два }



  Управляющие структуры Object Pascal__________________________91


  repeat
r:= n mod d;
if r "" 0 ( n не разделилось нацело на d } then d:= d + 1;
until r = 0;
label2.caption:=Editl.text;
if d = n
then label2.caption:=label2.caption
+ ' - простое число.' else label2.caption:=label2.caption
+ ' - обычное число.';
bye:
  end;
В литературе по программированию можно встретить суждения о недопустимости
применения инструкции goto, так как она приводит к запутанности программ.
Однако с категоричностью таких утверждений согласиться нельзя. В некоторых
случаях использование goto вполне оправдано. Приведенный пример, когда
goto используется для аварийного завершения процедуры, относится именно к
таким случаям.


  ИНСТРУКЦИИ ВВОДА-ВЫВОДА


  В конце 70-х годов, когда Н. Вирт разработал Pascal, операционная система
Windows еще не существовала. Большинство программистов создавали свои
программы для операционной системы MS DOS, в которой основным устройством
ввода исходных данных была клавиатура, а устройством вывода - монитор,
работающий в режиме отображения символьной информации (буквы, цифры и
специальные знаки). Поэтому в Pascal были введены инструкции,
обеспечивающие ввод данных с клавиатуры (read и readin) и вывод информации
на экран монитора (write и writein). И по сей день эти инструкции остаются
основными инструкциями ввода-вывода при программировании на Pascal,
например, в Turbo Pascal 7.0.
  Необходимо отметить, что хотя данная книга посвящена программированию в
Windows, нельзя обойти вниманием инструкции консольного ввода-вывода
(консоль - это монитор и клавиатура, рассматриваемые как единое устройство
ввода-вывода). При рассмотрении общих вопросов программирования с целью
сосредоточить внимание читателя на сути проблемы и не уделять слишком
много внимания созданию пользовательского интерфейса представляется
возможным использовать примеры программ, которые работают в DOS-стиле.
  С Замечание ^
В литературе, посвященной программированию в Windows, программы,
использующие инструкции консольного ввода-вывода довольно часто приводятся
в качестве примеров. Это еще одна из причин, чтобы познакомиться с этими
инструкциями.
  Инструкции WRITE n WRITELN
Инструкция write предназначена для вывода на экран монитора сообщений и
значений переменных. После слова write в скобках задается список имен
переменных. Кроме имен переменных в список можно включить сообщение -
текст, заключенный в одинарные кавычки.
  Примеры:
  write (Suinma) ;
write('Результат вычислений');
write('Корни уравнения. х1=',х1,' х2=',х2);


  94 Delphi 3. Программирование на Object
Pascal


  После имени переменной через двоеточие можно поместить описание (формат)
поля вывода значения переменной.
  Для переменной типа integer формат - это целое число, определяющее ширину
поля вывода (количество позиций на экране). Например, инструкция write (d:
5); показывает, что для вывода значения переменной d используется 5
позиций. Если число такое, что его изображение занимает меньше позиций,
чем указано в формате, то перед выводом числа добавляется такое количество
пробелов, чтобы общее количество выведенных символов было равно указанному
в формате.
  Например, если значение переменной Kol типа integer равно 15, то в
результате выполнения инструкции
write('Всего изделий:',Kol:5);
на экран будет выведено:
  Всего изделий: 15
Для переменных действительного типа формат представляет собой два целых
числа, разделенных двоеточием. Первое число определяет ширину поля вывода,
второе - количество цифр дробной части. Если задать только ширину поля, то
на экране появится число, представленное в форме с плавающей точкой.
  Например, пусть переменные xl и х2 типа real имеют значения 13.25 и
- 0.3401, тогда в результате выполнения инструкции
write('xl=',xl:5:2,' х2=',х2:12)
на экран будет выведено:
  х1=13.25 х2=-3.40100Е-01
Если ширины поля, указанной в формате, недостаточно для вывода значения
переменной, то выводится число в формате с плавающей точкой и десятью
цифрами после запятой (все поле вывода в этом случае занимает 17 позиций).
  После выполнения инструкции write курсор остается в той позиции экрана, в
которой он находился после вывода последнего сообщения этой инструкции.
Следующая инструкция write начинает вывод именно с этой позиции. Например,
в результате выполнения инструкций
х:=-2.73;
write('Значение перем');
write('енной:') ;
write('х=') ;
write(х:8:5) ;



  Инструкции ввода-вывода_________________________________95


  на экран будет выведено:
  Значение переменной:х=-2.73000
Инструкция writein отличается от инструкции write только тем, что после
вывода сообщения или значений переменных курсор переводится в начало
следующей строки. Например, если значением переменной xi является число
- 3.561, х2 - число ю.345, то результатом выполнения следующих инструкций
writein('Значения корней уравнения:') ;
writeln('xl=',x:7:3);
writeln('x2=',x:7:3) ;
будет'следующий текст на экране:
  Значения корней уравнения:
  х1"-3.5б10 х2= 10.345-
Инструкции READ и READLN
Инструкция read предназначена для ввода с клавиатуры значений переменных
(исходных данных). В общем виде инструкция выглядит так:
  read(Переменная!, Переменная2, ... Переменная^)
где переменная - имя переменной, значение которой должно быть получено с
клавиатуры во время выполнения программы.
  Примеры:
  read (а) ;
read(Cena,Kol) ;
При выполнении инструкции read происходит следующее: программа
приостанавливает свою работу и ждет пока на клавиатуре будут набраны
нужные данные и нажата клавиша "Enter". После нажатия "Enter" введенное
значение присваивается переменной, имя которой указано в инструкции.
Например, в результате выполнения инструкции read(Temperat) и набора на
клавиатуре строки 21, значением переменной Temperat будет число 21.
  Одна инструкция read позволяет получить значения нескольких переменных. В
этом случае вводимые числа должны набираться в одной строке и разделяться
пробелами. Например, если тип переменных а, ь и с - real, то в результате
выполнения инструкции read (а, ь, с) и набора на клавиатуре строки:
  4.5 23 0.17
значение переменной а будет равно 4.5, ь-23.о, с-о.17.


  96_______________________Delphi 3. Программирование на Object Pascal


  Если в строке набрано больше чисел, чем задано переменных в инструкции, то
оставшаяся часть строки будет обработана последующей инструкцией read.
Например, в результате выполнения инструкций
read (А, В);
read (С);
и набора на клавиатуре строки
10 25 18
как реакции на инструкцию read (А, в), переменная А получит значение ю, в
- 25. Инструкция read (С) присвоит переменной с значение 18.
  Инструкция readin отличается от инструкции read тем, что после выделения
очередного числа из набранной на клавиатуре строки и присваивания его
последней переменной из списка инструкции readin, оставшаяся часть строки
теряется и следующая инструкция read или readin будет требовать нового
ввода. Например, в результате выполнения инструкций
readin(А,В);
read(С) ;
при наборе пользователем строки
10 25 18
переменная А получит значение ю, в -25. После чего программа будет ожидать
ввода нового числа, чтобы присвоить его переменной с.
  Перед каждой инструкцией read или readin следует располагать инструкцию
write, чтобы подсказать пользователю, какие данные ожидает от него
программа. Например, фрагмент программы вычисления стоимости покупки может
быть представлен:
  writein('Введите исходные данные.');
write('Цена изделия:') ;
readin(Сепа) ;
write('Количество в партии:') ;
readin(Ко1);
write('Скидка:');
readin(Skidka) ;
Если тип данных, вводимых с клавиатуры, не соответствует или не может быть
приведен к типу переменных, имена которых указаны в инструкции read
(readin), то программа аварийно завершает работу (инструкции, следующие за
read не выполняются) и на экран выводится сообщение об ошибке.



  Инструкции ввода-вывода_________________________________97_


  Консольное приложение
Delphi позволяет программисту создать приложение, в котором для ввода с
клавиатуры можно использовать инструкции read и readin, а для вывода на
экран монитора - инструкции write и writein. Такое приложение называется
консольным.
  Создается консольное приложение следующим образом. После выбора из меню
tile команды New Application сначала надо закрыть ненужные окна:
  окно стартовой формы (Fonnl) и окно модуля приложения (Unitl.pas). При
закрытии окна модуля Delphi выводит запрос Save changes to Unitl.pas?
(Сохранить изменения в Unitl.pas?), на который надо ответить "Нет" щелчком
на командной кнопке No. В результате этого на экране остается главное окно
Delphi и окно инспектора объектов (Object Inspector), которое тоже можно
закрыть. После этого из меню View следует выбрать команду Project Source,
в результате выполнения которой открывается окно Projectl.dpr, в котором
находится сформированный Delphi шаблон главной процедуры приложения.
  В окне главной процедуры приложения (рис. 76) можно набирать инструкции
программы.
  Рис. 76. Окно главной процедуры приложения
( Замечание ^
Консольное приложение создается в Delphi, и, следовательно, в Windows.
Выполняется консольное приложение как программа DOS. Как известно, в DOS
используется кодировка ASCII, в Windows - ANSI, причем буквы русского
алфавита в этих кодировках имеют разные коды. Это приводит к тому, что
вместо сообщений на русском языке консольное приложение выводит
"абракадабру"
Сообщения консольных приложений должны записываться латинскими буквами.
Можно также написать функцию (неплохое упражнение по программированию),
которая будет выполнять перекодировку строки из ANSI в ASCII-кодировку.
Пример процедуры перекодировки приведен ниже.



  98______________________Delphi 3. Программирование на Object Pascal


  Ниже приведен пример программы, которая запрашивает у пользователя вес в
фунтах, пересчитывает его в килограммы и выводит результат на экран.
  {$APPTYPE CONSOLE) program Projects-uses
Classes;
var
f:real; ( вес в фунтах }
wrreal; { вес в граммах }
k:integer; ( кол-во килограмм }
g:integer; ( кол-во грамм )
{ w = f*0,4095 = k*1000 + g }
begin
writein('** From pounds to kilograms. ***');
writein('Enter weight in pounds and press "Enter"') ;
write('-" ');
readln(f);
w:=f*409.5; { один фунт - это 409,5 гр. } if w " 1000 then begin
k:=Trunc(w/1000);
g:=Round(w - k*1000);
end else begin k:=0;
g:=Round(w);
end;
write(f:4:2,' pound(s) is '};
if k "= 1 then write (k,' kg ');
writein(g,' gr') ;
write('To continue press "Enter"');
readln;
end. ,
Начинается текст программы строкой {$APPTYPE CONSOLE), которая хотя и
похожа на комментарий, таковым не является, так как сразу за открывающей
скобкой следует знак денежной единицы. Эта директива предназначена для
компилятора. Следуя ее указаниям компилятор генерирует исполняемую
программу, ориентированную на работу с консолью. Слово program помечает
начало текста программы, а идентификатор, следующий за ним, - это имя
программы. Инструкция uses используется для указания используемых



  Инструкции ввода-вывода 99


  программой модулей (библиотек). Далее, инструкция var отмечает начало
раздела описания переменных, инструкция begin - раздела исполняемых
инструкций программы. Инструкция end, за которой следует точка, указывает
н" конец программы.
  Замечание
Текст, который находится после инструкции end, за которой поставлена
точка, компилятором не обрабатывается, игнорируется.
  Компиляция консольного приложения выполняется обычным образом, т. е.
выбором из меню Project команды Compile.
  После успешной компиляции выбором команды Run из меню Run программа может
быть запущена. При запуске программы на экране появляется стандартное окно
программы DOS. На рис. 77 приведен вид DOS-окна, в котором работает
консольное приложение, созданное в Delphi.
  Рис. 77. Пример DOS-окна, в котором работает консольное приложение,
созданное в Delphi
После вывода информационного сообщения программа ожидает ввода с
клавиатуры, о чем свидетельствует мигающий курсор. Пользователь должен
ввести запрашиваемую программой информацию и нажать "Enter". Ниже приведен
пример результата работы (содержимое окна) программы пересчета веса из
фунтов в килограммы (значение, введенное с клавиатуры, выделено
полужирным).
  *** From pounds to kilograms. ***
Enter weight in pounds and press "Enter"
- " 2.5
2.5 pound(s) is 1 kg 24 gr
To continue press "Enter"


  Символы и СТРОКИ

  Помимо числовой информации, компьютер может обрабатывать символьную
информацию. Язык программирования Object Pascal оперирует с символьной
информацией, которая может быть представлена отдельными символами или
строками символов.
  Символы
Для хранения и обработки отдельных символов используются переменные типа
ansichar, widechar и char. Значением переменных перечисленных типов может
быть любой отображаемый на экране символ: буква русского или латинского
алфавитов, цифра, знак препинания, а также специальный символ, например
"Enter" ("переход на новую строку").
  ( Замечание ^
В дальнейшем для обозначения переменных символьного типа используется
идентификатор char.
  Переменная символьного типа должна быть объявлена в разделе описания
переменных с использованием утверждения
Имя: char;
где .. Имя - имя переменной символьного типа;
char - ключевое слово обозначения символьного типа.
  Примеры:
  otv:char;
ch:char;
Как и любая переменная программы, переменная типа char может получить
значение в результате выполнения инструкции присваивания. Если переменная
типа char получает значение в результате выполнения операции присваивания,
то справа от знака:= должно стоять выражение типа char, например,
переменная типа char или символьная константа - символ, заключенный в
кавычки.



  102_____________________Delphi 3. Программирование на Object Pascal


  Например, в результате выполнения инструкций
с1:='*';
с2:=с1;
Переменная cl получает значение присваиванием значения константы, с 2 -
присваиванием значения переменной cl.
  Переменную типа char можно сравнить с другой переменной типа char или с
символьной константой. Сравнение основано на том, что каждому символу
поставлено в соответствие число (см. приложение), причем символу 'О'
соответствует число меньшее, чем символу '9', символу 'А' - меньшее, чем
'В', символу 'Z' - меньшее, чем 'а'. Таким образом можно записать:
  tO'"tr".."(9'".."'A'"'B'".."'Zf"ia'"iЪ'".."'z'
Символам русского алфавита соответствуют числа большие, чем символам
латинского алфавита, при этом справедливо следующее:
  "A'""Б'"'B'"..."'Ю'"(Я'"'a'"'б'"'в'"...""э'""ю'""я'.
  Каждый символ кодируется числом. Однако не все символы есть на клавиатуре.
На клавиатуре нет служебных символов, например, часто используемого
символа "конец строки", код которого равен 10.
  Если в программе нужен символ, которого нет на клавиатуре, то можно
воспользоваться функцией chr, значением которой является символ, код
которого указывается при обращении к функции. Например, в результате
выполнения инструкции ch:=chr(l0) значением переменной ch будет символ
"конец строки".
  Вместо функции chr можно воспользоваться оператором #, который преобразует
целое число из диапазона О...255 в символ, код которого указан за
оператором. Например, в результате выполнения инструкции ch:=#32
переменная ch будет содержать пробел. Оператор # часто используется в
инструкциях вывода сообщений.
  Ниже приведена процедура обработки события onActivate формы приложения
(рис. 78-о), которая формирует и выводит в поле метки (Label 1) таблицу
кодировки символов. Процедура FormActivate выполняется автоматически сразу
после появления формы на экране.
  procedure TForml.FormActivate(Sender: TObject);
var
st:string; ( таблица формируется как строка символов )
dec: byte; ( код символа }
i,j:integer; ( номер строки и колонки таблицы }
begin



  Символы и строки 103


  dec:=192;
for i:=0 to 15 do { шестнадцать строк } begin
dec:=i+192;
for j:=1 to 4 do ( четыре колоноки } begin
st:=st+chr(dec)+'-'+IntToStr(dec)+' ';
dec:=dec+16;
end;
st:=st+#13; ( переход к новой строке экрана ) end;
Labell.caption:=st;
end;
Форма рассматриваемого приложения содержит только один компонент - поле
метки (Labell). Чтобы колонки таблицы были одинаковой ширины, свойству
Labeil.Font.Name следует присвоить имя непропорционального шрифта,
например Courier New Суг. Вид окна приложения во время работы приведен на
рис. 7&-6.
  Рис. 78. Форма приложения
а) во время разработки б) во время работы
Строки
В языке Object Pascal строки могут быть представлены следующими типами:
  shortstring, longstring И widestring. Различаются ЭТИ ТИПЫ Предельно
допустимой длиной строки и способом выделения памяти для переменных этого
типа. Переменной типа shortstring память выделяется статически, т. е. до
начала выполнения программы, и общее количество символов такой строки не
может превышать 256. Переменным типа longstring и



  104______________________Delphi 3. Программирование на Object Pascal


  widestring память выделяется динамически, во время работы программы, и
длина таких строк практически не ограничена.
  С Замечание J
Object Pascal поддерживает тип string, который используется в Turbo
Pascal. В дальнейшем изложении для обозначения переменных строкового типа
используется идентификатор string.
  Переменная строкового типа должна быть объявлена в разделе описания
переменных с использованием утверждения
Имя: srting;
ИЛИ Имя: string где Имя - имя переменной строкового типа;
string - ключевое слово обозначения строкового типа;
длина - константа целого типа, определяющая максимальную длину
последовательности символов, которая может быть присвоена переменной.
  Пример объявления переменных строкового типа:
  name:stringbuff:string;
Если при объявлении переменной длина не указывается, то предполагается,
что длина строки равняется 255 символам, т. е. объявления
stroka: string эквивалентны.
  В тексте программы последовательность символов, являющаяся строкой,
заключается в одинарные кавычки. Например, чтобы присвоить строковой
переменной parol значение, нужно записать:
  parol:= 'большой секрет'; .
  ИЛИ
parol:= '1998';
Инструкция parol:=i998; неверная, так как тип переменной не соответствует
типу константы.
  Используя операции =, ",", "=,"= и о, переменную типа string можно
сравнить с другой переменной типа string или со строковой константой.



  Символы и строки______________________________________105


  Строки сравниваются посимвольно от первого символа. Если все символы
сравниваемых строк одинаковые, то такие строки считаются равными. Если в
одинаковых позициях строк находятся разные символы, большей считается та
сорока, у которой в этой позиции находится символ с большим кодом. Ниже
приведены примеры сравнения строк.
  Строка 1
Строка 2
Результат сравнения
Иванов
Иванов
Строки равны
Васильев
Васильев
Строка! больше строки 2
Алексеев
Петров
Строка1 меньше строки 2
Иванова
Иванов
Строка 1 больше строки 2

  Кроме операций сравнения, к строковым переменным и константам можно
применить операцию сложения, в результате выполнения которой получается
новая строка. Например, в результате выполнения инструкций
first_name:=''Иванов' ;
1азЬ_пате:='Иван' ;
ful name:=first name+last name;
переменная ful_name получит значение Иванов Иван.
  Язык программирования Object Pascal предоставляет несколько полезных при
работе со строками функций и процедур. Ниже приведено их описание и
примеры использования.
  Функция LENGTH
Функция length возвращает длину строки. У функции один параметр -
выражение строкового типа. Значение функции (целое число) - количество
символов, из которых состоит строка. Например, в результате выполнения
инструкций
n:=length('Иванов') ;
m:=length(' Невский проспект ')
значение переменных n и m будет равно б и 20.
  Процедура DELETE
Процедура delete позволяет удалить часть строки. В общем виде обращение к
процедуре выглядит так:
  delete(Строка, р,п)



  106______________________Delphi 3. Программирование на Object Pascal


  где Строка - переменная строкового типа;
р - номер символа, с которого начинается удаляемая подстрока;
л - длина удаляемой подстроки.
  Например, в результате выполнения инструкций
s:='Город Санкт-Петербург' ;
delete(s,7,б) ;
значением переменной s будет строка город Петербург.
  Функция POS
Функция роз позволяет определить положение подстроки в строке. В общем
виде обращение к функции выглядит так:
  роз{Подстрока,Строка);
где
подстрока - строковая константа или переменная, которую надо найти в
строковой константе или переменной строка.
  Например, в результате выполнения инструкции
р:=роз('Пе','Санкт-Петербург') ;
значение переменной р будет равно 7. Если в строке нет искомой подстроки,
то функция возвращает ноль.
  Ниже приведена инструкция while, в результате выполнения которой удаляются
начальные пробелы из строки st.
  { произвольная строка )
while(роз(' ',3t) = 1) and(length(3t) " 0) do delete(3t,1,1);
( строка без ведущих пробелов }
Пробелы удаляет инструкция delete (3t, 1,1), которая выполняется в цикле
while до тех пор, пока первым символом строки является пробел (в этом
случае значение pos с ' ,st) равно единице). Проверка условия length ^st)
" о нужна, так как возможно, что изначально вся строка состоит из пробелов.
  Функция COPY
Функция copy позволяет выделить фрагмент строки. В общем виде обращение к
функции copy выглядит так:
  copy(Строка,?,л)


  Символы и строки______________________________________707


  где
Строка - выражение строкового типа, содержащее строку, фрагмент которой
надо получить;
р - нбмер первого символа в строке строка, с которого начинается
выделяемая подстрока;
д - длина выделяемой подстроки. Например, в результате выполнения
инструкций
gt:= 'Инженер Иванов';
fam:=copy(st,9,6) ;
значением переменной fam будет строка Иванов.

  МАССИВЫ

  Массив - это структура данных, которую можно рассматривать как набор
переменных одинакового типа, имеющих общее имя. Массивы удобно
использовать для хранения однородной по своей природе информации,
например, таблиц, коэффициентов уравнений, матриц.
  Объявление массива
Перед использованием массив, как и любая переменная, должен быть объявлен
в разделе объявления переменных. В общем виде объявление массива выглядит
так:
  Имя:arrayгде имя - имя переменной-массива;
array - зарезервированное слово языка Object Pascal, обозначающее, что
переменная является массивом;
нижний_индекс и верхнии__ицдекс - целые константы, определяющие диапазон
изменения индекса элементов массива и, неявно, количество элементов
массива - размер массива;
тип - тип элементов массива.
  Примеры объявления массивов:
  temper: arraykoef:arrayname: arrayПри объявлении массива удобно
использовать именованные константы. Именованная константа объявляется в
разделе объявления констант, который располагают перед разделом объявления
переменных. Начинается раздел объявления констант словом const. Например,
массив названий команд-участниц чемпионата по футболу можно объявить так:
  const
NT=18; {число команд } SN=25; {предельная длина названия команды }



  110______________________Delphi 3. Программирование на Object Pascal


  var
team:arrayЧтобы в программе использовать элемент массива, надо указать имя
массива и номер элемента (индекс), заключив его в квадратные скобки.
Индекс может быть константой или выражением целого типа. Например:
  teamd:=koefShowMessage(nametemperНекоторые типичные действия с массивами
Типичными действиями при работе с массивами являются:
  П Вывод элементов
О Ввод элементов
О Поиск заданного элемента
О Поиск максимального или минимального элемента
О Сортировка
Вывод массива
Под выводом массива понимается вывод в диалоговое окно значений элементов
массива. Если в программе необходимо вывести значения всех элементов
массива, то для этого удобно использовать инструкцию for, при этом
переменная-счетчик инструкции for может быть использована в качестве
индекса элемента массива.
  Например, процедура, выводящая названия команд, которые хранятся в массиве
team, может быть реализована следующим образом:
  procedure TForml.ButtonlClickfSender: TObject);
const
NT=5;
var
team:arrayst:string;
i:integer;
begin
teamteamteam

  Массивы 111


  teamteam( формирование списка команд } for'i:=l to NT do
st: ==st+IntToStr (i) +' ' +teain ( вывод списка } ShowMessage(st);
end;
Приведенная выше процедура выводит пронумерованный список команд при
щелчке на командной кнопке формы.
  Ввод массива
Под вводом массива понимается получение от пользователя во время работы
программы значений элементов массива. "Лобовое" решение задачи ввода
элементов массива - для каждого элемента массива создать поле ввода.
Однако если требуется ввести достаточно большой массив, то такое решение
неприемлемо. Представьте форму, например, с десятью полями редактирования!
Очевидно, что вводить последовательность чисел удобно в таблицу, каждое
число на отдельной строке, или в одну строку, отделяя числа одно от
другого пробелами. Ниже рассматриваются два варианта организации ввода
массива: с использованием поля редактирования (компонента Edit) и с
использованием компонента Memo.
  Использование компонента EDIT
Диалоговое окно программы во время ввода элементов массива может выглядеть
так, как показано на рис. 79.
  Рис. 79. Диалоговое окно программы Ввод массива
После щелчка на кнопке Ввод программа должна выделить из введенной строки
первую подстроку (23), преобразовать ее в число и присвоить полученное
значение первому элементу массива, затем выделить вторую подстроку (17),
преобразовать ее в число и присвоить полученное значение второму элементу
массива и так далее для каждого элемента массива.



  112______________________Delphi 3. Программирование на Object Pascal


  Основной цикл процедуры ввода массива может выглядеть следующим образом:
  for i:=l to SIZE do
aгде SIZE - именованная константа, определяющая размер массива, а -
массив, Editi - имя поля ввода-редактирования, GetSubstr - имя
пользовательской функции (ее описание приведено ниже), которая выделяет из
строки подстроку с указанным номером (в данном случае подстрока - это
последовательность символов, расположенная между двумя пробелами).
  ( Функция возвращает подстроку с указанным номером } Function
GetSubStr(st:string; ( строка }
n:integer) ( номер подстроки ) :string; ( подстрока или '' } var
p:integer ;
i:integer;
begin
For i:=l to n-1 do begin
p:=pos(' ',st);
st:=copy(st,p+l,Length(st)-p);
end;
p:=pos(' ',st); // найти конец нужной подстроки if p "" 0
then result:=сору(st,1,p-l) else result:=st;
end;
Для того чтобы из полученной в качестве аргумента строки выделить п-ю
подстроку (элемент массива), функция GetSubstr сначала удаляет, в цикле
for, предшествующие ей n-1 подстроку, затем находит пробел, который
отмечает конец нужной подстроки, выделяет подстроку и возвращает ее в
качестве значения функции.
  Следует отметить, что приведенный вариант функции GetSubstr работает
правильно только в том случае, если перед первым числом, введенным в поле
редактирования нет пробела, а между остальными числами поставлен только
один пробел. Если между числами поставить несколько пробелов, то функция
начинает работать не так, как ожидается. Например, если между первым и
вторым числом поставить два пробела, то первая выделенная строка будет
представлять собой введенное число, а вторая будет содержать пробел. Ниже
приведен второй вариант функции GetSubstr, которая работает правильно вне
зависимости от количества поставленных пробелов меж-



  Массивы__________________________________________113


  ду числами. Она отличается от первого варианта тем, что после выделения
очередной подстроки удаляет ненужные пробелы в начале оставшейся части
строки.
  ( Фунм^ия возвращает подстроку с указанным номером } Function
GetSubStr2(st:string; { строка }
n:integer) ( номер подстроки } :string; { подстрока или '' }
var
p:integer ;
i:integer;
begin
For i:=l to n-1 do begin
p:=pos(' ',st);
st:=copy(st,p+l,Length(st)-p) ;
//если в начале оставшейся части строки //есть пробелы, то удалим их while
(pos(' ',st)=l)and (length(st)"0) do delete(st,1,1) ;
end;
p:=pos(' ',st);
if p о О
then result:=copy(st,1,p-l) else result:=st;
end;
Для проверки работы функции GetSubstr и демонстрации ее использования для
ввода массива нужно создать диалоговое окно, содержащее поле ввода
(Editi), командную кнопку (Buttoni) и метку (Labeli) (рис. 80-о).
  Ниже приведена процедура обработки события Ondick для командной кнопки, а
на рис. SO-6 - пример работы программы (после щелчка на Ввод).
  procedure TFonnl.ButtonlClick(Sender: TObject) ;
const
SIZE=5; { размер массива } var
a:arrayi:integer;
st:string;
begin
{ ввод элементов массива из поля редактирования формы }
for i:=l to SIZE do
a{ вывод введенного массива в окно сообщения } st:=";


  114 Delphi 3. Программирование на. Object Pascal


  for i:=l to SIZE do
st:=st+IntToStr(i)+' '+ aShowMessage(st) ;
end;
Рис. 80. Пример результата использования функции GetSubstr для ввода
массива
Всесторонне проверив работу GetSubstr, можно обнаружить, что если в поле
редактирования введено меньше чисел, чем требуется, то элементы массива,
значения которых не введены, получают значение, равное последнему
введенному числу. Очевидно, что такое поведение функции не корректно.
  Ниже приведен еще один вариант функции GetSubstr, которая, в случае если
подстрока с запрашиваемым номером в исходной строке отсутствует,
возвращает пустую строку.
  ( Функция возвращает подстроку с указанным номером } Function
GetSubStr3(st:string; ( строка )
n:integer) { номер подстроки } :string; f подстрока или '' } var
p:integer;
begin
( если в начале строки есть пробелы, то удалим их } while (post'
',st)=l)and (length(st)"0) do delete(st,1,1) ;
if n"l then
repeat
p:=pos(' ',st);
if p о О then begin
st:=copy(st,p+l,Length(st)-p) ;
//если в начале оставшейся части строки //есть пробелы, то удалим их }
while (posC ',st)=l)and (length(st)"0) do


  Массивы 115


  delete(st,1,1) ;
n:=n-l;
end;
yntil (n=l)or(p=0) ;
( st начинается с нужной подстроки if n"l
then result:=''
else
begin
p:=pos(' ',st);
if p о О
then result:=copy(st,1,p-l) else result:=st ;
end;
end;
Программа, использующая последний вариант функции GetSubstr, может
проконтролировать действительное количество введенных элементов массива.
Ниже приведен фрагмент программы, которая использует последний вариант
функции GetSubst для ввода массива чисел. В случае, если количество
введенных чисел меньше необходимого, выводится сообщение об ошибке.
  // st - строка, содержащая введенные в поле Edit числа // а - массив целых
чисел, SIZE размер массива // buf - строка-буфер
( ввод элементов массива из поля редактирования формы } i:=l;
repeat
buf:=GetSubstr3(Editl.text,i) ;
if Length(buf) о О then a+'Надо ввести ' +IntToStr(SIZE)+' чисел.');
i:=i+l;
until (i"SIZE) or (Length(buf)=0);
Использование компонента MEMO
Если надо ввести символьный массив, причем каждый элемент массива может
состоять из нескольких слов, то вместо компонента Edit удобнее
использовать компонент Memo, который позволяет вводить несколько строк
текста.


  116______________________Delphi 3. Программирование на Object Pascal


  Ниже приведены свойства компонента Memo.
  Свойство
Обозначение
Имя поля. Используется в программе для доступа к содержимому (тексту) поля
Name
Текст, находящийся в поле ввода-редактирования
Text
Расстояние от левой границы поля до левой границы формы
Left
Расстояние от верхней границы поля до верхней границы формы
Top
Высота поля
Height
Ширина поля
Width
Шрифт, используемый для отображения вводимого текста
Font
Признак наследования свойств шрифта родительской формы
ParentFont

  К форме компонент Memo добавляется обычным образом. Его значок находится
на странице Standard палитры компонентов, рядом со значком компонента Edit.
  При использовании компонента Memo для ввода массива, значение каждого
элемента массива печатается на отдельной строке.
  Свойство Text компонента Memo представляет собой строку, состоящую из
находящихся в поле Memo строк, разделенных последовательностью символов с
кодами 10 и 13 (конец строки и переход на новую строку), которую можно
назвать "новая строка".
  С Замечание ^
Последовательность символов "новая строка" добавляется в поле Memo при
нажатии клавиши "Enter".
  Чтобы получить значение i-ro элемента массива (i-ю строку), надо найти i-l
символ с кодом 13, пропустить символ с кодом 10 и выделить подстроку до
следующего символа с кодом 13 или до конца строки.
  Основной цикл процедуры ввода символьного массива из Memo может выглядеть
следующим образом:
  for i:=l to SIZE do
aгде SIZE - именованная константа, определяющая размер массива, а -
массив, Memol - имя Memo-компонента, GetLine - имя пользовательской
функции, которая выделяет из строки, представляющей собой содержимое
компонента Memo, подстроку с указанным номером (в данном случае под-


  Массивы 117


  строка - это последовательность символов, расположенная между двумя
символами "новая строка").
  Ниже приведена функции GetLine, которая выделяет из строки, полученной в
качестве параметра, подстроку с указанным номером. В случае, если
подстрока с запрашиваемым номером в исходной строке отсутствует, функция
возвращает пустую строку.
  ( Функция возвращает подстроку с указанным номером } Function
GetLine(st:string; { строка )
n:integer) { номер подстроки } :string; ( подстрока или '' ) var
р:integer;
begin
( если в начале строки есть пробелы, то удалим их } while (posC
',st)=l)and (length(st)"0) do delete(st,1,1);
if n"l then
repeat
p:=pos(#13,st);
if р о О then begin
st:=copy(st,p+2,Length(st)-p); // разделитель - два символа:
  с кодом 13 и 10
//если в начале оставшейся части строки //есть пробелы, то удалим их }
while (posC ',st)=l)and (length(st)"0) do delete(st,1,1) ;
n;=n-l;
end;
until (n=l)or(p=0) ;
( st начинается с нужной подстроки } if n"l
then result:=''
else
begin
p:=pos(#13,st) ;
if р о О
then result:=copy(st,l,p-l) else result:=st ;
end;
end;
Для проверки работы функции GetLine и демонстрации ее использования для
ввода массива нужно создать диалоговое окно (рис. 81), которое будет


  118 Delphi 3. Программирование на Object Pascal

  содержать поле Memo (метоп), командную кнопку (Buttoni) и метку
(Labell).
  Рис. 81. Диалоговое окно приложения Ввод массива
Ниже приведена процедура обработки события Ondick командной кнопки Ввод.
  procedure TFormI.ButtonlClick(Sender: TObject);
const
SIZE=5; ( размер массива ) var
a:arrayi:integer ;
st:string;
begin
( ввод элементов массива из поля редактирования формы }
for i:=l to SIZE do
a{ вывод введенного массива в окно сообщения } st:=";
for i:=l to SIZE do
st:=st+IntToStr(i)+' '+ aShowMessage(st) ;
end;
Рис. 82. Пример ввода символьного массива с использованием Memo-компонента


  Массивы__________________________________________119


  На рис. 82 приведен вид диалоговых окон приложения Ввод массива после
щелчка на командной кнопке Ввод. Диалоговое окно Fr_memo содержит значения
элементов массива, полученные из Memo-поля.
  Поиск минимального (максимального) элемента массива
Задачу поиска минимального элемента массива рассмотрим на примере массива
целых чисел.
  Алгоритм поиска минимального (максимального) элемента массива довольно
очевиден: сначала делается предположение, что первый элемент массива
является минимальным (максимальным), затем остальные элементы массива
последовательно сравниваются с этим элементом. Если во время очередной
проверки обнаруживается, что проверяемый элемент меньше (больше) принятого
за минимальный (максимальный), то этот элемент принимается за минимальный
(максимальный) и продолжается проверка оставшихся элементов.
  Диалоговое окно приложения поиска минимального элемента массива содержит
поле ввода элементов массива (Editi), два поля меток(ьаЬе11 и Label2),
которые используются для вывода информационного сообщения и результата
работы программы, и командную кнопку (Buttoni), при щелчке на которой
выполняется поиск минимального элемента массива.
  Ниже приведена процедура обработки события ondick на кнопке Buttoni,
реализующая массив, поиск минимального элемента и вывод результата.
  procedure TForml.ButtonlClick(Sender: TObject);
const
SIZE=5;
var
a:arraymin:integer; // номер минимального эл-та массива
i:integer; // номер эл-та сравниваемого с минимальным
begin
// ввод массива for i:=l to SIZE do
a// поиск минимального элемента
min:=l; // пусть первый элемент минимальный
for i:=2 to SIZE do
if a

  120______________________Delphi 3. Программирование на Object Pascal

  // вывод результата
label2.caption:='Минимальный элемент массива:'+IntToStr(aend;
Для ввода массива процедура TForml.Buttoniciick использует рассмотренную
ранее процедуру GetSubstr3. Описание этой процедуры следует поместить в
раздел implementation модуля приложения.
  На рис. 83 приведен вид диалогового окна приложения Поиск минимального
элемента массива во время его работы, после ввода в поле редактирования
массива и щелчка на кнопке Поиск.
  Рис. 83. Пример диалогового окна приложения поиска минимального элемента
массива
Поиск в массиве
При решении многих задач возникает необходимость установить, содержит ли
массив определенную информацию или нет. Например, проверить, есть ли в
массиве фамилий студентов фамилия Петров. Задачи такого типа называются
поиском в массиве.
  Для организации поиска в массиве могут быть использованы различные
алгоритмы. Наиболее простой - это алгоритм простого перебора. Поиск
осуществляется последовательным сравнением элементов массива с образцом до
тех пор, пока не будет найден элемент равный образцу или не будут
проверены все элементы. Алгоритм простого перебора применяется, если
элементы массива не упорядочены.
  Ниже приведен текст программы поиска в массиве целых чисел. Перебор
элементов массива осуществляет инструкцией repeat, в теле которой
инструкция if сравнивает текущий элемент массива с образцом и присваивает
переменной found значение true, если текущий элемент и образец' равны.
Цикл завершается, если в массиве обнаружен элемент, равный образцу
(found=true), или если проверены все элементы массива. По завершении
цикла, проверив значение переменной found, можно определить успешен поиск
или нет.
  Вид диалогового окна программы Поиск в массиве приведен на рис. 84.
Назначение полей ввода очевидно.


  Массивы 121


  Рис. 84. Диалоговое окно программы Поиск в массиве
При щелчке на командной кнопке Поиск (Buttoni) запускается процедура
TFonnl.Buttonldick (ее текст приведен ниже), которая из поля
редактирования Editi вводит массив, из поля Edit2 - число. Затем
выполняется проверка: содержит ли массив введенное число. После завершения
проверки выводится информационное сообщение.
  procedure TFonnl.Buttonldick (Sender: TObject);
const
SIZE=10;
var
a:arrayn:integer; ( образец для поиска)
found:boolean; ( true - совпадение образца с элементом
массива }
i:integer; ( индекс элемента массива )
begin
( ввод массива } for i:=l to SIZE do
a( ввод образца для поиска } n:=StrTo!nt(edit2.text) ;
{ поиска в массиве) found: ==false;
i:=l;
repeat
if athen found=true
else i:=i+l;
until (i " SIZE) or (found = true);
if found
then ShowMessage('Совпадение с элементом номер '
+IntToStr(i)+#13+'Поиск успешен.') else ShowMessage('Совпадений с образцом
нет.');
end;


  122 Delphi 3. Программирование на Object Pascal


  Для ввода массива из поля редактирования используется рассмотренная ранее
функция GetSubstr3. Описание (текст) этой функции следует поместить
В раздел implementation, Перед описанием Процедуры TForml.ButtonlClick.
  Очевидно, что чем больше элементов в массиве и чем дальше расположен
нужный элемент от начала массива, тем дольше будет программа искать нужный
элемент.
  Так как операции сравнения применимы как к числам, так и к строкам, то
данный алгоритм может использоваться для поиска как в числовых, так и в
строковых массивах.
  На практике довольно часто производится поиск в массиве, элементы которого
упорядочены по некоторому критерию. Например, массив фамилий, как правило,
упорядочен по алфавиту, массив данных о погоде упорядочен по датам
наблюдений. В случае если массив упорядочен, применяют другие, более
эффективные, по сравнению с методом простого перебора, алгоритмы, один из
которых - метод бинарного поиска.
  Суть метода бинарного поиска заключается в следующем. Выбирается средний
(по номеру) элемент упорядоченного, например, по возрастанию, массива
(элемент с номером sred), и с этим элементом сравнивается образец (рис.

                                85).


  Рис. 85. Выбор среднего элемента массива при бинарном поиске


  Если средний элемент равен образцу, то задача решена.
  Если средний элемент больше образца, то искомый элемент расположен выше
среднего элемента (между элементами с номерами verh и sred).
  Если средний элемент меньше образца, то искомый элемент расположен ниже
среднего (между элементами с номерами sred и niz).
  После того как определена часть массива, в которой может находиться
искомый элемент, поиск проводят в этой части, выделяя новый средний
элемент. Номер среднего элемента вычисляется по формуле (niz-verh)/2 +
verh.
  Блок-схема алгоритма бинарного поиска в массиве представлена на рис. 86.

  Массивы 123


  Рис. 87. Диалоговое окно программы Бинарный поиск в массиве
Рис. 86. Блок-схема алгоритма бинарного поиска в упорядоченном массиве
Вид диалогового окна программы поиска приведен на рис. 87. Поле метки
Labels используется для вывода результатов поиска и, если переключатель
Выводить протокол установлен во включенное состояние, протокола (значений
переменных verh, niz, sred) поиска (выводимая во время поиска информация
полезна для понимания сути алгоритма).
  В форме приложения появился элемент, который до этого момента в программах
книги не использовался, - флажок (checkBox), или независимый
переключатель. Ниже, в таблице, перечислены свойства элемента CheckBox.
  Свойство
Обозначение
Имя компонента. Используется в программе для доступа к свойствам компонента
Name
Текст, поясняющий назначения переключателя
Caption
Определяет состояние, внешний вид переключателя. Если переключатель выбран
(в квадратике, изображающем переключатель, находится "галочка"), то
Checked=TRUE. Если переключатель не выбран (в квадратике нет "галочки"),
то Checked=FALSE
Checked


  124_____________________Delphi 3. Программирование на Object Pascal


  (окончание)
Свойство
Обозначение
Определяет состояние переключателя. В отличие от свойства Checked
позволяет различать выбранное, невыбранное и промежуточное состояния.
Состояние переключателя определяют константы: cbChecked (выбран), cbGrayed
(серый, неопределенное состояние) и cbUnchecked (не выбран)
State
Определяет, может ли переключатель быть в промежуточном, неопределенном
состоянии. Если AllowGrayed = FALSE, то переключатель может быть только
выбранным или невыбранным. Если AllowGrayed = TRUE, то допустимо
промежуточное состояние
AllowGcayed
Расстояние от левой границы переключателя до левой границы формы
Left
Расстояние от верхней границы переключателя до верхней границы формы
Top
Высота поля вывода поясняющего текста
Height
Ширина поля вывода поясняющего текста
Width
Шрифт, используемый для отображения поясняющего текста
Font
Признак наследования характеристик шрифта формы
ParentFont

  В следующей таблице приведены значения некоторых свойств компонентов формы
приложения.
  Свойство
Значение
CheckBoxl.Name
CheckBoxl
CheckBoxl.Caption
выводить протокол
CheckBoxl.Checked
True
Label3.AutoSize
False
Label3.Wordwrap
True
Label3.Caption

Label3.Width

                                265

  Label3.Height

                                105


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

  Массивы
( Бинарный поиск в массиве )
procedure TForml.ButtonlClick(Sender: TObject);
const
SIZE=10;
var
a:arrayverh:integer; { верхняя граница поиска } niz: integer; ( нижняя
граница поиска ) sred:integer; { номер среднего элемента )
found:boolean;( TRUE - совпадение образца
с элементом массива } n:integer; ( число сравнений с образцом )
i:integer;
begin
( ввод массива } for i:=l to SIZE do
aobr:=StrToInt(Edit2.text) ;
verh:=l;
niz:=SIZE;
n:=0;
found:=FALSE;
label3.caption;='';
if CheckBoxl.State = cbChecked
then Label3.caption:='verh'+#9+'niz'#9'sred'#13;
( бинарный поиск в массиве ) repeat
sred:=Trunc((niz-verh)/2)+verh;
if CheckBoxl.Checked
then Label3.caption:=label3.caption +IntToStr(verh)+#9 +IntToStr(niz)+#9
+IntToStr(sred)+#13 ;
n:=n+l;
if aif obr " athen niz:=sred-l else verh:=sred+l;
until (verh " niz) or found;


  126 __ ___________Delphi 3. Программирование на Object Pascal


  if found
then label3.caption:=label3.caption
+'Совпадение с элементом номер ' + IntToStr(sred)+#13'Выполнено ' +
IntToStr(n)+' сравнений.' else label3.caption:=label3.caption
+'Образец в массиве не найден:';
end;
Ниже приведены примеры диалоговых окон программы (рис. 88) после
выполнения поиска.
  Рис. 88. Примеры работы программы бинарного поиска в массиве
Здесь следует обратить внимание на то, что элемент массива, находящийся на
седьмом месте, программа бинарного поиска находит всего за четыре шага, в
то время как программе, реализующей алгоритм простого перебора,
потребовалось бы семь шагов.
  Повторное использование функций и процедур программиста
Разработав некоторую функцию, программист может использовать ее в другой
программе, поместив текст этой функции в раздел implementation. Однако
этот способ не удобен - приходится набирать текст функции заново или
копировать его из текста другой программы.
  Delphi позволяет программисту поместить часто используемые функции и
процедуры в отдельный модуль и затем применять эти процедуры и функции в
своих программах, указав имя модуля в списке необходимых программе модулей
(инструкция uses).
  Чтобы создать модуль, надо закрыть окна: формы, модуля формы и инспектора
объектов. Затем из меню File выбрать команду New и в появившемся



  Массивы 127


  диалоговом окне New item выбрать тип создаваемого элемента - Unit, после
чего щелкнуть на ОК (рис. 89).
  Рис. 89. Диалоговое окно New Items
В результате этих действий открывается окно редактора кода, в котором
находится сформированный Delphi шаблон модуля, текст которого приведен
ниже.
  unit Uniti;
interface
implementation
end.
  Начинается текст модуля инструкцией unit, за которой следует имя модуля
(во время сохранения модуля это имя автоматически будет заменено на
указанное программистом).
  Слово interface отмечает раздел интерфейса модуля. В этот раздел
программист должен поместить описание находящихся в модуле процедур и
функций, которые могут быть вызваны из других модулей, использующих данный
раздел.
  В раздел implementation (реализация) следует поместить описание функций,
объявленных в разделе interface.
  Ниже приведен пример модуля программиста, который содержит две функции:
GetSubstr3 И GetLine.
  unit my_unit;
interface
//Описание функций и процедур доступных // функциям и процедурам,
использующим этот модуль



  128______________________Delphi 3. Программирование на Object Pascal


  II Функция выделяет из строки подстроку с указанным номером
// Здесь подстрока - последовательность символов
// между пробелами
Function GetSubStr3(st:string; ( строка }
n:integer) { номер подстроки ) :string; ( подстрока или '' }
// Функция возвращает подстроку с указанным номером
// Здесь подстрока - последовательность символов между #13
Function GetLine(st:string; ( строка )
n:integer) { номер подстроки }
:string; { подстрока или '' }
implementation // Реализация процедур и функций модуля
// Функция выделяет из строки подстроку с указанным номером Function
GetSubStr3(st:string; ( строка }
n:integer) ( номер подстроки } :string; ( подстрока или '' }
var
р:integer;
i:integer;
begin
For i:=l to n-1 do begin
p:=pos(' ',st);
st:=copy(st,p+l,Length(st)-p);
//Если в начале оставшейся части строки //есть пробелы, то удалим их while
(pos(' ',st)=l)and (length(st)"0) do delete(st,1,1) ;
end;
p:=pos(' ',st);
if p о О
then result:=copy(st,l,p-l) else result:=st;
end;
( Функция возвращает подстроку с указанным номером } * Function
GetLinefst:string; { строка }
n:integer) { номер подстроки } :string; ( подстрока или '' )
var
p:integer;
begin
( Если в начале строки есть пробелы, то удалим их (



  Массивы 129


  while (posC ',st)=l)and (length(st)"0) do delete(st,1,1) ;
if n"l th^n
repeat
p:=pos(#13,st) ;
if p о О then begin
// Разделитель - два символа: с кодом 13 и 10
st:=copy(st,p+2,Length(st)-p) ;
//Если в начале оставшейся части строки //есть пробелы, то удалим их while
(pos(' ',st)=l)and (length(st)"0) do delete(st,1,1);
n:=n-l;
end;
until (n=l)or(p=0) ;
( st начинается с нужной подстроки } if n"l
then result:=''
else
begin
p:=pos(#13,st) ;
if p о О
then result:=copy(st,1,p-l) else result:=st;
end;
end;
end.
  Сохраняется модуль обычным образом, т. е. выбором команды Save из меню
File.
  С Замечание ^
Для модулей повторно используемых процедур и функций лучше создать
отдельную папку и назвать ее, например, Units (модули).
  Чтобы в программе могли применяться функции и процедуры модуля,
программист должен добавить этот модуль к проекту и указать имя модуля в
списке используемых модулей (обычно имя модуля программиста помещают в
конец сформированного Delphi списка используемых модулей).
  Ниже приведен вариант программы поиска элемента в массиве. Процедура
TFormi.Buttonlciick обращается к функции GetSubstr3, которая находится



  130 ________________Delphi 3. Программирование на Object Pascal


  в модуле my_unit.pa3, поэтому в списке используемых модулей указано имя
МОДУЛЯ my_unit. unit s found_;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, my unit; // Модуль программиста
type
TFormI = class(TForm)
Labell: TLabel;
Editi: TEdit;
Label2: TLabel;
Buttoni: TButton;
Edit2: TEdit;
procedure ButtonlClick(Sender: TObject);
private
( Private declarations } public
( Public declarations ) end;
var
Formi: TFormI;
implementation ($R *.DFM}
( Поиск в массиве перебором } procedure TFormI.ButtonlClick(Sender:
TObject);
const
SIZE=10;
var
a:arrayn:integer; { Образец для поиска) *
found:boolean; ( TRUE - совпадение образца
с элементом массива )
i:integer; ( Индекс элемента массива }
begin
{ Ввод массива } for i:=l to SIZE do
a

  131 Массивы


  { Ввод образца для поиска } n:=StrToInt (edi.t2.text) ;
( Поиска в массиве} found:=FALSE;
i:=l;
repeat
if athen found:=TRUE
else i:=i+l;
until (i " SIZE) or (found = TRUE) ;
if found
then ShowMessage ('Совпадение с элементом номер '
+IntToStr(i)+#13+'rioMCK успешен. ') else ShowMessage('Совпадений с
образцом нет.'it-end;
end.
  После добавления имени модуля в список используемых приложением модулей,
модуль следует добавить к проекту. Чтобы это сделать, надо из меню Project
выбрать команду Add to project, и в появившемся окне Add to project (рис.
90) выбрать имя файла модуля, затем щелкнуть на кнопке Открыть.
  Рис. 90. Диалоговое окно Add to project
В результате добавления модуля к проекту, в верхней части окна редактора
кода, рядом с вкладкой, на которой написано имя модуля формы, появляется
вкладка с именем добавленного модуля. Переход на определенную вкладку
позволяет выбрать необходимый модуль, текст которого будет отображаться в
окне редактора кода.
  После добавления модуля к проекту (рис. 91) и включения его имени в список
используемых модулей (инструкция USES) можно выполнить компиляцию
программы.


  132 Delphi 3. Программирование на Object Pascal


  Рис. 91. Окно редактора кода после добавления к проекту модуля
Сортировка массива
Под сортировкой массива подразумевается процесс перестановки элементов
массива, целью которого является размещение элементов массива в
определенном порядке. Например, если имеется массив целых значений а, то
после выполнения сортировки по возрастанию должно выполняться условие:
  аSIZE - верхняя граница индекса массива.
  Задача сортировки распространена в информационных системах и используется
как предварительный этап задачи поиска, так как поиск в упорядоченном
(отсортированном) массиве проводится намного быстрее, чем в
неупорядоченном.
  Существует много методов (алгоритмов) сортировки массивов, рассмотрим два
из них:
  П Метод прямого выбора D Метод прямого обмена
Сортировка методом прямого выбора
Алгоритм сортировки массива по возрастанию методом прямого выбора может
быть представлен так:
  О Просматривая массив от первого элемента, найти минимальный и поместить
его на место первого элемента, а первый на место минимального
П Просматривая массив от второго элемента, найти минимальный и поместить
его на место второго элемента, а второй на место минимального
П И так далее до предпоследнего элемента



  Массивы 133


  Ниже представлена программа сортировки массива целых чисел по возрастанию,
диалоговое окно которой изображено на рис. 92.
  Рис. 92. Диалоговое окно программы сортировки массива простым выбором
Процедура сортировки, которая запускается щелчком на кнопке Сортировка
(Buttoni), вводит значения элементов массива из поля ввода (Editi). После
выполнения очередного цикла поиска минимального элемента в части массива
процедура выводит массив в поле метки (Label2).
  Ниже приведена процедура обработки события onciick на кнопке Сортировка.
  procedure TForml.ButtonlClick(Sender: TObject);
const
SIZE=10;
var
a:arraymin:integer; ( Номер минимального элемента в части
массива от i до верхней границы массива )
j:integer; { Номер эл-та, сравниваемого с минимальным }
buf:integer; ( Буфер, используемый при обмене эл-тов массива }
i,k:integer;
begin
for i:=l to SIZE do
alabel2.caption:='';
for i:=l to SIZE-1 do begin
( Поиск минимального эл-та
в части массива от аnu.n:=i;
for j:=i+l to SIZE do if a


  134 Delphi 3. Программирование на Object Pascal


  { Поменяем местами aaa( Вывод массива ) for k:=l to SIZE do
LabelZ.caption:=label2.caption+'
'+IntTostr(aLabel2.caption:=label2.caption+#13;
end;
LabelZ.caption:=label2.caption+#13+"Массив отсортирован.';
end;
На рис. 93 приведен пример диалогового окна во время работы программы.
  Рис. 93. Пример диалогового окна программы
Сортировка методом обмена
В основе алгоритма лежит обмен соседних элементов массива. Каждый элемент
массива, начиная с первого, сравнивается со следующим и если он больше, то
элементы меняются местами. Таким образом, элементы с меньшим значением
продвигаются к началу массива (всплывают), а элементы с большим значением
- к концу массива (тонут), поэтому этот метод иногда называют "пузырьковой
сортировкой". Это действие повторяется столько раз, сколько элементов в
массиве.
  На рис. 94 показан пример процесса сортировки массива. Цифрой 1 обозначено
исходное состояние массива и перестановки на первом проходе, цифрой 2 -
состояние после перестановок на первом проходе и перестановки на втором
проходе и так далее.

  Рис. 94. Процесс сортировки массива




  Массивы 135


  На рис. 95 изображено диалоговое окно программы сортировки массива методом
обмена.
  Рис. 95. Диалоговое окно программы сортировки массива методом обмена
Процедура сортировки, текст которой приведен ниже, запускается щелчком на
кнопке Сортировка (Buttoni). Значения элементов массива вводятся из поля
ввода (Editi). Во время сортировки, после выполнения очередного цикла
обменов элементов массива, в поле метки Label2 программа выводит массив.
  procedure TFonnl.ButtonlClick(Sender: TObject);
const
SIZE=5;
var
a:arrayk:integer; ( Текущий элемент массива }
i:integer; ( Индекс для ввода и вывода массива }
changed:boolean; ( TRUE, если в текущем цикле были обмены)
buf:integer; ( Буфер для обмена элементов массива )
begin
( Ввод массива } for i:=l to SIZE do
alabel2.caption:='' ;
( Сортировка массива } repeat
changed:=FALSE ;
for k:=l to SIZE-1 do begin
if a( Обменяем k-й и k+1-й элементы ) buf:=aaa


  136 ______________Delphi 3. Программирование на Object Pascal


  changed:=TRUE;
end;
end;
( Вывод массива } for i:=l to SIZE do
Label2.caption:=label2.caption
+' '+IntTostr(aLabel2.caption:=label2.caption+#13;
until not changed;
Label2.caption:=label2.caption+#13
+'Массив отсортирован.' ;
end;
Следует отметить, что максимальное необходимое количество циклов проверки
соседних элементов массива равно количеству элементов массива минус один.
Вместе с тем возможно, что массив реально будет упорядочен за меньшее
число циклов. Например, последовательность чисел 51234, если ее
рассматривать как представление массива, будет упорядочена за один цикл, и
выполнение оставшихся трех циклов не будет иметь смысла. Поэтому в
программу введена логическая переменная changed, которой перед выполнением
очередного цикла присваивается значение FALSE. Процесс сортировки (цикл
repeat) завершается, если после выполнения очередного цикла проверки
соседних элементов массива (цикл for) ни один элемент массива не был
обменен с соседним, и, следовательно, массив уже упорядочен.
  На рис. 96 приведен пример диалогового окна программы после выполнения
сортировки.
  Рис. 96. Пример диалогового окна программы сортировки методом обмена
Многомерные массивы
Исходные данные для решения многих задач удобно представляются в табличной
форме. Например, результат производственной деятельности сборочных заводов
некоторой фирмы можно представить в виде следующей таблицы.


  Массивы 137


  Продукт!
  Продукт2
ПродуктЗ
Продукт4
Предпр1

  Завод^

  ЗаводЗ


  Колонки и строки таблицы, как правило, состоят из однородной информации.
Поэтому в программе для хранения и обработки табличных данных имеет смысл
использовать массивы. Так приведенная выше таблица может быть представлена
как совокупность одномерных массивов следующим образом:
  zavodi array zavod2 array zavod3 array Каждый из приведенных массивов
может хранить информацию о количестве выпущенной продукции одним заводом.
  Возможно и такое представление:
  producti array product2 array product3 array product4 array В этом случае
каждый массив предназначен для хранения информации о количестве продукции
одного наименования, произведенной каждым заводом.
  Помимо совокупности одномерных массивов, таблица может быть представлена
как двумерный массив.
  В общем виде описание двумерного массива выглядит так:
  Иня:arrayНижняяГраницаИндекса2.. ВерхняяГрающаИцдекса2] of Тип
где
имя - имя массива; array - зарезервированное слово языка Pascal,
указывающее, что объявляемый элемент данных - массив;
НижняяГраницаИндекса!, ВерхняяГраницаИндекса!, НижняяГраницаИндек-са2,
ВерхняяГраницаИндекса2 - целые константы, определяющие диапазон изменения
индексов и, следовательно, число элементов массива;
Тип - тип элементов массива.



  138 __ _______Delphi 3. Программирование на Object Pascal


  Приведенная выше таблица может быть представлена в виде двумерного массива
так:
  product array Этот массив состоит из 12 элементов типа integer. Количество
элементов массива может быть вычислено по формуле:
  (ВерхняяГраницаИндекса1-НижняяГраницаИндекса1+1)*
(ВерхняяГраницаИндекса2-НижняяГраницаИндекса2+1)
Чтобы использовать элемент массива, нужно указать имя массива и индексы
элемента. Первый индекс обычно соответствует номеру строки таблицы, второй
- номеру колонки. Так элемент product В программах таблицы (двумерные
массивы) обычно обрабатывают по строкам и (или) по столбцам. Это удобно
делать при помощи инструкции for. Например, следующий фрагмент программы
вычисляет сумму элементов массива, описание которого приведено выше.
  s:=o;
for i:= 1 to 3 do
for j : = 1 to 4 do
s:=s+product( s содержит сумму элементов массива }
В приведенном фрагменте программы каждый раз, когда внутренний цикл (цикл
по j) завершается, во внешнем цикле увеличивается значение i на единицу, и
внутренний цикл выполняется вновь. Таким образом, к текущему значению
переменной s последовательно прибавляются значения элементов массива
product: productПри описании массивов в программе удобно использовать
именованные константы как значения верхних границ индексов массива.
  Пример программы
Следующая программа обрабатывает результаты спортивных соревнований
(зимней олимпиады в Нагано, 1998 г.). Исходные данные для обработки
представлены в таблице.
  
Результаты зимней олимпиады в Нагано (Япония, 1998)
Страна
Количество медалей

  золотых
серебряных
бронзовых
Австрия 3 5 2
Германия 12 9 8



  Массивы 139


  (окончание)
Страна
Количество медалей

  золотых
серебряных
бронзовых
Италия

                                2

  6

                                2

  Канада

                                6

  5

                                4

  Нидерланды

                                5

  4

                                2

  Норвегия

                                10

  10

                                5

  Россия

                                9

  6

                                3

  США

                                6

  3

                                4

  Финляндия

                                2

  4

                                6

  Швейцария

                                2

  2

                                3

  Япония

                                5

  1

                                4


  Программа должна вычислить общее количество медалей, завоеванное
представителями каждой страны, и соответствующее количество очков
(баллов), которое вычисляется по следующему правилу: за каждую золотую
медаль команда получает семь очков, за серебряную - шесть, за бронзовую -
пять очков.
  Вид диалогового окна программы приведен на рис. 97.
  Рис. 97. Диалоговое окно
программы
Итоги олимпиады
В форме приложения появился компонент, который до сих пор в программах
книги не использовался, - StringGrid (строковая таблица), значок которого
находится на дополнительной (Additional) странице палитры компонентов
(рис. 98).
  Рис. 98. Значок компонента StringGrid



  740______________________Delphi 3. Программирование на Object Pascal


  Ниже, в таблице, перечислены некоторые свойства компонента StringGrid.
  Свойство
Обозначение
Имя компонента. Используется в программе для доступа к
Name
свойствам компонента


  Количество колонок таблицы
ColCount
Количество строк таблицы
RowCount
Соответствующий таблице двумерный строковый массив. Если строки и столбцы
таблицы нумеровать с нуля, то ячейке (cell) таблицы, находящейся на
пересечении i-й колонки и
Cells
j -и строки соответствует cells

  Количество зафиксированных слева колонок таблицы. Зафиксированные колонки
выделяются цветом и при горизонтальной прокрутке таблицы остаются на месте
FixedCols
Количество зафиксированных сверху строк таблицы. Зафик
FixedRows
сированные строки выделяются цветом и при вертикальной прокрутке таблицы
остаются на месте


  Признак допустимости редактирования содержимого ячеек таблицы
Options.goEditing
Ширина колонок таблицы
DefaultColWidth
Высота строк таблицы
DefaultRowHeight
Ширина линий, ограничивающих ячейки таблицы
GridLineWidth
Расстояние от левой границы поля таблицы до левой границы формы
Left
Расстояние от верхней границы поля таблицы до верхней границы формы
Top
Высота поля таблицы
Height
Ширина поля таблицы
Width
Шрифт, используемый для отображения содержимого ячеек таблицы
Font
Признак наследования характеристик шрифта формы
ParentFont

  В следующей таблице приведены значения свойств компонента s^ringGrid,
используемого программой обработки результатов олимпиады для ввода
исходных данных и вывода результата.
  Свойство
Значение
Name
Tab!
  ColCount

                                6





  Массивы________________________________________141


  Свойство Значение
RowCount

                                12



  FixedCols

                                0



  FixedRows

                                1



  Options.goEditing
TRUE


  DefaultColWidth

                                65



  DefaultRowHeight

                                14



  GridLineWidth

                                1




  Ячейки первой, зафиксированной, строки таблицы используются в качестве
заголовков колонок таблицы. Во время создания формы приложения установить
значения элементов массива cells нельзя, так как элементы массива доступны
только во время работы программы. Поэтому значения элементов массива
cells, соответствующих первой строке таблицы, устанавливает процедура
обработки события OnActivate (ее текст приведен ниже), которое происходит
во время активизации формы приложения. Кроме того, эта процедура вписывает
в первую колонку таблицы названия стран-участниц соревнований.
  procedure TForml.FormActivate(Sender: TObject);
begin
tabi .'Cells


























































































stabl.Cellstabl.Cellstabl.Cellstabl.Cellstabl.Cellstabl.Cellstabl.Cellsend;
Программа обработки исходной таблицы, текст которой приведен ниже,
запускается в результате щелчка на командной кнопке Итоги (suttoni).



  142 _____________________Delphi 3. Программирование на Object Pascal


  procedure TFormI.ButtonlClick(Sender: TObject) ;
var
c,r:integer; ( номер колонки и строки таблицы }
s:integer; ( всего медалей у команды )
р:integer; ( очков у команды }
m: integer; ( номер строки с максимальным количеством очков }
buf:arrayi:integer; ( номер строки используется во время сортировки }
begin
for r:=1 to tabi.rowcount do ( обработать все строки ) begin s:=0;
( вычисляем общее кол-во медалей ) for c:=l to 3 do
if tabl.cellsthen s:=s+StrTo!nt(tabl.cells{ вычисляем количество очков }
p:=7*StrToInt(tabl.cells( вывод результата } tabl.cellstabl.cellsend;
( сортировка таблицы }
for r:=l to tabl.rowcount-1 do
begin
m:=r; ( максимальный элемент - в г-й строке ) for i:=r to tabl.rowcount-1
do
if StrToInt(tabl.cellsif r о m then
begin ( обменяем г-ю и m-ю строки таблицы } for с:=0 to 5 do begin
buftabl.Cellstabl.Cellsend;
end;
end;
end



  Массивы 143


  Сначала для каждой страны программа вычисляет общее количество медалей и
соответствующее ему количество очков. Затем, используя метод простого
выбора, программа выполняет сортировку таблицы по убыванию количества
набранных очков. Во время сортировки для обмена строк таблицы используется
строковый массив buf, индекс которого, как и индекс строки таблицы,
меняется от нуля до пяти (см. инструкцию объявления массива в тексте
программы). Такой прием позволяет наиболее просто выполнить копирование
замещаемой строки в буфер и замещение строки содержимым буфера.
  На рис. 99 приведен пример результата работы программы.
  Рис. 99. Пример диалогового окна программы обработки результатов олимпиады
в Нагано
Ошибки при использовании массивов
При использовании массивов наиболее распространенной ошибкой является
выход значения индексного выражения за допустимые границы, указанные в
разделе объявления массива.
  Если в качестве индекса используется константа и ее значение выходит за
допустимые границы, то такая ошибка обнаруживается на этапе компиляции
программы. Например, если в программе объявлен массив
day:arrayто во время компиляции программы инструкция
day будет помечена как ошибочная.
  Если при обращении к элементу массива в качестве индекса используется
переменная или выражение, то возможно возникновение ошибки (исключения) во
время выполнения программы. Например, если в программе объявлен массив
tabi:array

  144 Delphi 3. Программирование на Object Pascal


  то инструкция
for i:=0 to N do
sum:=suin+tabl формально является верной, и ее компиляция будет успешно
выполнена. Однако во время работы программы, при запуске ее из Delphi,
возникнет исключение и на экран, в диалоговое окно, будет выведено
сообщение об ошибке (рис. 100).
  Рис. 100. Пример диалогового окна с сообщением о возникшем исключении
Для завершения программы, вызвавшей исключение, надо, после щелчка на
кнопке ОК, из меню Run выбрать команду Program Reset.
  При запуске программы из Windows, во время выполнения приведенного выше
цикла for, на экран будет выведено сообщение Range check error (ошибка
контроля диапазона) (рис. 101).
  Рис. 101. Сообщение Range check error
Рис. 102. Вкладка Compiler
диалогового окна Project Options

  Массивы 145
( Замечание ^
Поведение программы при выходе индексного выражения за границы диапазона
допустимых значений определяется настройкой компилятора. Чтобы программа
контролировала значения индексных выражений (в этом случае Delphi
добавляет в выполняемую программу инструкции, обеспечивающие этот
контроль), необходимо на вкладке Compiler диалогового окна Project
Options, которое появляется при выборе из меню Project команды Options,
установить во включенное состояние находящийся в группе Runtime errors
переключатель Range checking (рис. 102).

  РЕКУРСИЯ
Понятие рекурсии
Рекурсивным называется объект, частично состоящий или определяемый с
помощью самого себя. Факториал - это пример рекурсивного объекта.
факториал числа п определяется как произведение целых чисел от 1 до п и
обозначается п!
  п!=1*2*3*...*(п-1)*п
Приведенное выражение можно переписать так:
  n!=n*((n-l)*(n-2)*...*3*2*l)=n*(n-l)!
  Очевидно, что факториал п равен произведению числа п на факториал (п-1). В
свою очередь, факториал (n-l) - это произведение числа n-l на факториал
(п-2) и т. д.
  Таким образом, если вычисление факториала п реализовать как функцию, то в
теле этой функции будет инструкция вызова функции вычисления факториала
(n-l), т. е. функция будет вызывать сама себя. Такой способ вызова носит
название рекурсия, а функция, которая обращается сама к себе, называется
рекурсивной функцией.
  Ниже приведен пример рекурсивной функции вычисления факториала.
  ( рекурсивная функция вычисления факториала ) function
factorial(k:integer): integer;
begin
if k = 1
then factorial:= 1 else factorial:=k * factorial(k-1);
end;
Обратите внимание, что функция вызывает сама себя только в том случае,
если значение полученного параметра k больше единицы. Если значение
параметра равно единице, то функция сама себя не вызывает, а возвращает
значение и рекурсивный процесс завершается.
  На рис. 103 приведен вид диалогового окна программы, которая для
вычисления факториала числа, находящегося в поле ввода-редактирования
(Editi), использует рекурсивную функцию factorial.



  148 Delphi 3. Программирование на Object Pascal


  Рис. 103. Диалоговое окно программы
Ниже приведен текст процедуры обработки события Onciick на командной
кнопке Вычислить (Buttoni).
  procedure TForml.ButtonlClick(Sender: TObject);
var
k:integer; // число, факториал которого надо вычислить
f:integer; // значение факториала числа k begin
k:=StrTo!nt(Editl.Text) ;
f:=factorial(k) ;
label2.caption:='Факториал числа '+Editl.Text +' равен '+IntToStr(f) ;
end;

  Замечание
Приведенное выше объявление функции factorial следует поместить в раздел
implementation перед объявлением процедуры TForml.ButtonlClick.
  На рис. 104 приведены два диалоговых окна. Результат вычисления
факториала, представленный на рис. 104-д, соответствует ожидаемому.
  Рис. 104. Примеры работы программы вычисления факториала
Результат, находящийся в диалоговом окне, изображенном на рис. 104-6
несколько неожидан. Факториал числа 44 равен нулю! Произошло это потому,
что значение факториала числа 44 настолько велико, что превысило
максимальное значение для переменной типа integer, и, как говорят
программисты, произошло переполнение с потерей значения.



  Рекурсия____________________________________________149


  ( Замечание ^
Delphi может включить в исполняемую программу инструкции контроля
диапазона значений переменных. Чтобы это произошло, надо на вкладке
Compiler диалогового окна Project Options установить во включенное
состояние переключатель Overflow checking, находящийся в группе Runtime
errors (рис. 105).
  Рис. 105. Вкладка Compiler диалогового окна Project Options
Пример программы: поиск пути
Механизм рекурсии весьма эффективен при программировании задач поиска. В
качестве примера рассмотрим задачу поиска пути между двумя городами. Если
несколько городов соединены дорогами, то очевидно, что попасть из одного
города в другой можно различными маршрутами. Задача состоит в том, что
надо найти все возможные маршруты.
  Карта дорог между городами может быть изображена в виде графа - набора
вершин, означающих города, и ребер, обозначающих дороги (рис. 106).


  Рис. 106. Представление карты дорог между населенными пунктами в виде графа



  150 Delphi 3. Программирование на Object Pascal


  Процесс поиска может быть представлен как последовательность шагов. На
каждом шаге с использованием некоторого критерия выбирается точка, в
которую можно попасть из текущей. Если очередная выбранная точка совпала с
заданной конечной точкой, то маршрут найден. Если не совпала, то делаем
еще шаг. Так как текущая точка может быть соединена с несколькими другими,
то сначала будем выбирать точку с наименьшим номером.
  Например, пусть надо найти все возможные пути из точки 1 в точку 5.
Согласно принятому правилу, сначала выбираем точку 2. На следующем шаге
выясняем, что точка 2 тупиковая, поэтому возвращаемся в точку 1 и делаем
шаг в точку 3. Из точки 3 в точку 4, из 4 в б и из точки 6 в точку 5. Один
маршрут найден. После этого возвращаемся в точку 6 и проверяем, возможен
ли шаг в точку, отличную от 5. Так как это возможно, то делаем шаг в точку
7 и затем в 5. Найден еще один путь. Таким образом, процесс поиска состоит
из шагов вперед и возвратов назад. Поиск завершается, если из узла начала
движения уже некуда идти.
  Алгоритм поиска имеет рекурсивный характер: чтобы сделать шаг, мы выбираем
точку и опять делаем шаг, до тех пор, пока не достигаем цели.
  Таким образом, задача поиска маршрута может рассматриваться как задача
выбора очередной точки (города) и поиска оставшейся части маршрута, т. е.
имеет место рекурсия.
  Граф можно представить двумерным массивом, который назовем тар (карта).
Значение элемента массива map1 2 3 4 5 6 7
1234567

  0

                                1

  1

                                1

  0

                                0

  0

  1

                                0

  0

                                0

  0

                                0

  0

  1

                                0

  0

                                1

  0

                                0

  1

  1

                                0

  1

                                0

  0

                                1

  0

  0

                                0

  0

                                0

  0

                                1

  1

  0

                                0

  0

                                1

  1

                                0

  1

  0

                                0

  1

                                0

  1

                                1

  0

  Содержимое ячейки таблицы на пересечении колонки i и столбца j
соответствует значению тар
Рекурсия 151


  Помимо массива map нам потребуется массив road (дорога) и массив inci (от
include - включать). В road мы будем записывать номера пройденных городов.
В момент достижения конечной точки он будет содержать номера всех
прейденных точек, т. е. описание маршрута.
  В inclТак как мы используем рекурсивную процедуру, то надо обратить особое
внимание на условие завершения рекурсивного процесса. Процедура должна
прекратить вызывать сама себя, если текущая точка совпала с заданной
конечной точкой.
  На рис. 107 приведена укрупненная блок-схема алгоритма процедуры выбора
очередной точки формируемого маршрута.

  Рис. 107. Блок-схема процедуры выбора точки маршрута
Диалоговое окно программы приведено на рис. 108.
  Для ввода массива, представляющего описание карты, используется компонент
stringGridi (значения его свойств приведено ниже), для вывода результата
(найденного маршрута) - поле метки Labell. Начальная и конечная точки
маршрута задаются вводом значений в поля редактирования Editi и Edit2.
Процедура поиска запускается щелчком на кнопке Поиск (Buttoni). Поля меток
Label2, Labels и Labei4 используются для вывода поясняющего текста.



  152 Delphi 3. Программирование на Object Pascal


  Рис. 108. Диалоговое окно программы Поиск маршрута
Свойства компонента StringGridl
Свойство
Значение
Name
StringGridl
ColCount

                                11

  RowCount

                                11

  FixedCols

                                1

  FixedRows

                                1

  Options.goEditing
TRUE
DefaultColWidth

                                16

  DefaultRowHeight

                                14

  Options.goEditing
TRUE
ScrollBars
ssNone

  При запуске программы в момент активизации формы приложения, происходит
событие onActivate, процедура обработки которого заполняет массив
StringGridl. cells значениями, представляющими описание карты,
изображенной на рис. 108. Кроме того, эта процедура, заполняя
зафиксированные ячейки, нумерует строки и столбцы таблицы.
  procedure TFonnl.FonnActivate(Sender: TObject);
var
i:integer;
begin
// нумерация строк
for 1:=1 to 10 do
StringGridl.Cells
Рекурсия 153
II нумерация колонок for i:=l to 10 do
StringGridl.Cells// описание предопределенной карты StringGridl.CellsПоиск
маршрута выполняет запускаемая в результате щелчка на кнопке Поиск
процедура TFormi.Buttonldick (ее текст приведен ниже), которая для поиска
точки, соединенной с исходной точкой, вызывает процедуру step.
  procedure TFormi.Buttonldick (Sender: TObject);
const
ь=10;( кол-во вершин графа) var
map:arrayroad:arrayinci:arraystart,finish:integer; ( Начальная и
конечная точки )
found:boolean ;
i,j:integer;
procedure step(s,f,p:integer) ;
var
с:integer;! Номер точки,в которую делается очередной шаг }
i:integer;
begin
if s=f then
begin
( Точки s и f совпали !}



  154 ____________________Delphi 3. Программирование на Object Pascal


  found:=TRUE;
Labell.caption:=Labell.caption+#13+'Путь:' ;
for i:=l to p-1 do
Labell.caption:=Labell.caption+' '+IntToStr(roadend else begin { выбирем
очередную точку } for c:=l to N do
begin ( проверяем все вершины } if(map( точка соединена с текущей и не
включена в маршрут)
then begin
roadincite]:=FALSE;
roadend;
end;
end;
end;( конец процедуры step )
begin
Labell.caption:='' ;
( инициализация массивов ) for i:=l to N do roadfor i:=l to N do incl(
ввод описания карты из SrtingGrid.Cells) for i:=l to N do
for j : =1 to N do
if StringGridl.Cellsthen mapstart:=StrToInt(Editl.text) ;
finish:=StrToInt(EditZ.text) ;
roadstep(start,finish,2);(ищем вторую точку маршрута }
// проверим, найден ли хотя бы один путь if not found
then Labell.caption:='Указанные точки не соединены!';
end;



  Рекурсия_______________________________________155


  Сначала процедура TForml.Buttonlciick из компонента StringGridi вводит в
массив road описание карты дорог, а из полей редактирования Editi и Edit2
- номера начальной и конечной точек маршрута. После этого, вызовом
процедуры Step выполняется поиск первой точки, соединенной с начальной.
Следующую точку ищет процедура Step, которая вызывает сама себя.
  Пример программы: поиск кратчайшего пути
Обычно задача поиска пути на графе формулируется следующим образом:
  найти наилучший маршрут. Под наилучшим маршрутом, как правило, понимается
кратчайший. Найти кратчайший маршрут можно выбором из всех найденных.
Однако совсем не обязательно искать все .маршруты, можно поступить
по-другому. Нужно во время выбора очередной точки проверить, не превысит
ли длина формируемого маршрута длину уже найденного пути, если эта точка
будет включена в маршрут; если превысит, то эту точку следует пропустить и
выбрать другую. Таким образом, после того как будет найден первый маршрут,
программа будет вести поиск только по тем ветвям графа, которые могут
улучшить найденное решение, отсекая пути, делающие формируемый маршрут
длиннее уже найденного.
  Ниже приведена процедура, которая использует процедуру Step, выполняющую
выбор очередной точки маршрута так, что обеспечивается поиск пути
минимальной длины.
  procedure TFonnl.ButtonlClick(Sender: TObject);
const
N=10;( кол-во вершин графа) var
map:arrayroad:arrayincl:arraystart,finish:integer; { Начальная и
конечная точки }
found:boolean;
len:integer; { длина найденного (минимального) маршрута )
c_len:integer; { длина текущего (формируемого) маршрута }
i,j:integer;
procedure step(s,f,p:integer);
var
с:integer;! Номер точки,в которую делаем очередной шаг } i:integer;



  156 _____________________Delphi 3. Программирование на Object Pascal


  begin
if s=f then begin
len:=c len;{ сохраним длину найденного маршрута } ( вывод найденного
маршрута } for i:=l to p-1 do
Labell.caption:=Labell.caption+'
'+IntToStr(roadLabell.caption:=Labell.caption
+', длина:'+IntToStr(len)+#13;
end else
( выбирем очередную точку }
for c:=l to N do ( проверяем все вершины }
if (map and((len=0)or(с len+mapthen begin ( точка соединена с текущей, но
не включена в маршрут}
roadstep(c,f,p+l) ;
incite]:=FALSE;
roadс len:=c len-mapend;
end;{ конец процедуры step )
begin
Labell.caption:='';
{ инициализация массивов } for i:=l to N do roadfor i:=l to N do incl(
ввод описания карты из SrtingGrid.Cells) for i:=l to N do
for j:=1 to N do
if StringGridl.Cellsthen maplen:=0; // длина найденного (минимального)
маршрута с len:=0; // длина текущего (формируемого) маршрута
start:=StrToInt(Editl.text) ;
finish:=StrTo!nt(Edit2.text) ;
road


  Рекурсия___________________________________________157


  inci// проверим, найден ли хотя бы один путь if not found
then Labell.caption:"'Указанные точки не соединены!';
end;
Диалоговое окно программы и процедура обработки события onActivate ни чем
не отличаются от диалогового окна и соответствующей процедуры программы
поиска всех возможных маршрутов, рассмотренной в предыдущем разделе.



  ВЫВОД В ФАЙЛ


  До этого момента наши программы результат своей работы выводили на экран.
Это не всегда удобно. Pascal позволяет сохранить результаты работы
программы в файле, на диске компьютера.
  Объявление файла
Файл - это структура данных, представляющая собой последовательность
элементов одного типа. Количество элементов практически не ограничено. В
первом приближении файл можно рассматривать как массив переменной длины
неограниченного размера.
  Как и любая переменная программы, файл должен быть объявлен в разделе
описания переменных. При объявлении указывается тип элементов файла. В
общем виде объявление файла выглядит так:
  Имя:file of ТипЭлементов
Примеры:
  res: file of char; ( файл символов )
koef:file of real; ( файл вещественных чисел }
f:file of integer; ( файл целых чисел }
Файл, компонентами которого являются данные символьного типа, называется
символьным или текстовым. Описание текстового файла в общем виде выглядит
так:
  имя:Text File
где имя - имя файловой переменной;
TextFile - обозначение типа, показывающее, что Имя - это файловая
переменная, представляющая текстовый файл.
  Назначение файла
Объявление файловой переменной задает только тип компонентов файла. Чтобы
программа могла выводить данные в файл или считывать данные из файла,
необходимо указать конкретный файл, т. е. задать имя файла. Имя



  160 _________________Delphi 3. Программирование на Object Pascal


  файла задается вызовом процедуры AssignFile, связывающей файловую
переменную с конкретным файлом. Описание процедуры AssignFile выглядит так:
  AssignFile(var f, ИмяФайла:string)
Имя файла задается согласно принятым в Windows правилам. Оно может быть
полным, т. е. состоять не только непосредственно из имени файла, но и
включать путь к файлу. Ниже приведены примеры вызова процедуры AssignFile.
  AssignFile(f,'а:\result.txt');
AssignFile(f,'\students\ivanov\korni.txt') ;
fname:=('otchet.txt') ;
AssignFile(f,fname) ;
Вывод в файл
Непосредственно вывод в текстовый файл осуществляется при помощи
инструкций write или writeln. В общем виде эти инструкции записываются
следующим образом:
  write(ФайловаяПеременная, СписокВывода} writeln(ФайловаяПеременная,
СписокВывода)
где ФайловаяПеременная - переменная, идентифицирующая файл, в который
выполняется вывод.
  СписокВывода - разделенные запятыми имена переменных, значения которых
надо вывести в файл. Помимо имен переменных в список вывода можно включать
строковые константы.
  Например, если переменная f является переменной типа TextFile, то
инструкция вывода значений переменных xi и х2 в файл может быть такой:
  write(f, 'Корни уравнения',х1,х2);
Различие между инструкциями write и writeln состоит в том, что инструкция
writeln после вывода всех значений, указанных в списке вывода, записывает
в файл символ "новая строка".
  Открытие файла для вывода
Перед выводом в файл его необходимо открыть. Если программа, формирующая
выходной файл, уже использовалась, то возможно, что файл с результатами
работы программы уже есть на диске. Поэтому программист



  Вывод в файл_______________________________________161


  должен решить как поступить со старым файлом: заменить старые данные
новыми или новые данные добавить к старым. Способ использования старого
варианта определяется во время открытия файла.
  Возможны следующие режимы открытия файла для записи в него данных:
  П Перезапись (запись нового файла поверх существующего или создание нового
файла)
П Добавление в существующий файл
Чтобы открыть файл в режиме создания нового файла или замены
существующего, необходимо вызвать процедуру Rewrite (f), где f - файловая
переменная типа TextFile.
  Чтобы открыть файл в режиме добавления к уже существующим данным,
находящимся в этом файле, необходимо вызвать процедуру Append (f), где f -
файловая переменная типа TextFile.
  На рис. 109 приведено диалоговое окно программы записи-добавления в файл.
  Рис. 109. Диалоговое окно программы записи-добавления в файл
Ниже приведена процедура, которая запускается в результате щелчка -на
командной кнопке Создать. Она открывает файл в режиме создания нового или
замещения существующего файла и записывает в него 5 строк.
  // создание нового или замещение существующего файла procedure
TForrol.ButtonlClickfSender: TObject) ;
var
f:TextFile;
i:integer;
begin
AssignFile(f,'a:\test.txt');
Rewrite(f) ;
for i:=l to 3 do
writein(f,'Строка ',i) ;
CloseFile(f) ;
end;
В результате выполнения приведенной выше процедуры на диске А: появляется
файл test.txt. Вот его распечатка:



  162_____________________Delphi 3. Программирование на Object Pascal


  Строка 1 Строка 2 Строка 3
Процедура, которая запускается в результате щелчка на командной кнопке
Добавить, открывает созданный процедурой TForml.Buttoniciick файл test.
txt и добавляет в него две строки.
  // добавление в существующий файл procedure TFormI.Button2Click(Sender:
TObject);
var
f:TextFile;
i:integer;
begin
AssignFile(f,'a:Xtest.txt') ;
Append(f) ;
for i:=3 to 5 do
writein(f,'Строка ',i);
CloseFile(f) ;
end;
В результате выполнения программы содержимое файла test. txt изменяется.
Вот его распечатка:
  Строка 1 Строка 2 Строка 3 Строка 4 Строка 5
Следует отметить, что если после щелчка на кнопке Добавить еще раз сделать
щелчок на кнопке Создать, то файл test. txt опять будет состоять из трех
строк, пронумерованных от 1 до 3.
  Ошибки открытия файла
Попытка открыть файл может завершиться неудачей и вызвать ошибку времени
выполнения программы. Причин неудачи открытия файлов, может быть
несколько. Например, программа может попытаться открыть файл на гибком
диске, который не готов к работе (не закрыта дверца накопителя или диск не
вставлен в накопитель). Другая причина - отсутствие открываемого в режиме
добавления файла (файла нет - добавлять некуда).
  Если профамма запущена из Delphi, то при возникновении ошибки во время
открытия файла возникает исключение и на экране появляется диалоговое окно
с сообщением об ошибке (рис. 110).



  Вывод в файл 163


  Рис. 110. Пример сообщения об ошибке открытия файла
Если программа запускается из Windows, то окно с сообщением об ошибке
выглядит по-другому (рис. 111).
  Рис. 111. Пример сообщения об ошибке открытия файла


  Программа может взять на себя задачу контроля результата выполнения
инструкции открытия файла. Сделать это можно, проверив значение функции
lOResult (Input-Output Result - результат ввода-вывода). Функция lOResult
возвращает 0, если операция ввода-вывода завершилась успешно; в противном
случае - не ноль. Однако, чтобы программа могла проверить результат
выполнения операции ввода-вывода, нужно разрешить ей это делать. Для этого
надо перед инструкцией вызова процедуры открытия файла поместить директиву
компилятору - строку {$!-}, которая запрещает автоматическую обработку
ошибок ввода-вывода. После инструкции открытия файла следует поместить
директиву ($!+}, восстанавливающую режим обработки ошибок ввода-вывода.
  На рис. 112 приведена блок-схема алгоритма программы открытия файла для
добавления. Приведенный алгоритм обеспечивает обработку ошибки, которая
может возникнуть, если открываемого для добавления файла на диске еще нет.
  Рис. 112. Алгоритм открытия файла с обработкой возможной ошибки
Вот фрагмент программы, соответствующий приведенному алгоритму:
  AssignFile (f,filename) ;
($1-) Append(f) {$!+) if lOResult о О then Rewrite(f);



  164_____________________Delphi 3. Программирование на Object Pascal


  Закрытие файла

  Перед завершением работы программа должна закрыть все открытые файлы. Это
делается вызовом процедуры close. Процедура close имеет один параметр -
имя файловой переменной. Пример использования процедуры:
  close(f).
  Пример программы
Ниже приведен пример программы, которая ведет простую базу данных. При
каждом запуске программы на экране появляется диалоговое окно, в поля
которого пользователь может ввести дату и температуру воздуха (рис.113).
  Рис. 113. Диалоговое окно программы База данных "Погода"
Дата вводится в поле Edit2 (номер месяца) и в поле Editi (число, номер дня
в месяце). Для ввода температуры предназначено поле Edit3.
  ( Замечание ^
При создании формы программы характеристике Enabled кнопки Добавить
(Buttoni) следует присвоить значение FALSE.
  Файл базы данных открывает процедура TFormi.FonnActivate, которая
запускается автоматически при активизации формы приложения. Если операция
открытия файла завершается успешно, то процедура делает доступной кнопку
Добавить. В противном случае кнопка Добавить остается недоступной и
пользователю ничего не остается делать, как закрыть окно программы.
  procedure TFormi.FonnActivate(Sender: TObject);  begin
AssignFile(f,'a:\weather.db') ;
{$!-} Append(f) ;
if lOResult = 0
then Buttoni.Enabled:=TRUE else


  Вывод в файл_________________________________________765


  begin
Rewrite(f) ;
if lOResult = 0
then Buttonl.Enabled:"TRUE else ShowMessage('Ошибка создания
a:Vweather.db') ;
end;
end;
При щелчке на кнопке Добавить (Buttoni) введенная информация записывается
в базу данных - файл weather, db. Перед выполнением записи программа
проверяет, все ли поля формы заполнены, и, если не все, то выводит
информационное сообщение.
  procedure TForml.ButtonlClick(Sender: TObject);
begin
if (length(editl.text)=0) or (length(edit2.text)=0) or
(length(edit3.text)=0) then ShowMessage('Ошибка ввода данных.'
+#13+'Все поля должны быть заполнены.') else writeln(f,editl.text,'
',edit2.text,' ',edit3.text);
end;
В результате работы процедуры в конец файла weather, db будет добавлена
строка, содержащая три числа: номер месяца, число месяца и температуру.
Здесь следует обратить внимание на пробелы, разделяющие элементы списка
вывода в инструкции writeln. Если их не поставить, то числа,
соответствующие номеру месяца, числу месяца и температуре, сольются в одно.
  Закрывает базу данных процедура TFormi. Formciose, которая обрабатывает
событие Ondose, возникающее при закрытии пользователем формы приложения.
  procedure TForml.FormClose(Sender: TObject; var Action: TCloseAction) ;
begin
CloseFile(f) ;
end;
Так как приведенные процедуры используют общую переменную f, то описание
f:TextFiie следует поместить в раздел описания переменных модуля формы.
  После нескольких запусков программы файл weather, db может быть, например,
таким:
  2 17 -18 2 18 -10 2 19 0 2 20 4



  ВВОД ИЗ ФАЙЛА


  Pascal позволяет вводить исходные данные для программы не только с
клавиатуры, но и из текстового файла. Чтобы воспользоваться этой
возможностью, нужно объявить файловую переменную типа TextFile, назначить
ей при помощи инструкции AssignFile имя файла, из которого будут
считываться данные, открыть файл для чтения (ввода) и прочитать (ввести)
данные, ИСПОЛЬЗУЯ ИНСТРУКЦИЮ read ИЛИ readln.
  Открытие файла
Открытие файла для ввода (чтения) выполняется вызовом процедуры Reset,
имеющий один параметр - файловую переменную. Перед вызовом процедуры
Reset, с помощью функции AssignFile файловая переменная должна быть
связана с конкретным файлом.
  Например, следующие инструкции открывают файл для ввода.
  AssignFile(f,c:\data.txt) ;
Reset(f) ;
Если имя файла указано неверно, т. е. файла с таким именем на диске нет,
то возникает ошибка времени выполнения программы. Следует отметить, что
другой причиной возникновения ошибки при открытии файла, находящегося на
гибком диске, может быть отсутствие готовности дисковода, проще говоря,
отсутствие диска в накопителе (пользователь забыл вставить диск). Поэтому
в программе следует предусмотреть возможность повторной попытки открытия
файла после соответствующего ответа пользователя.
  Как и при открытии файла для записи, программа может взять на себя задачу
обработки возможной ошибки при открытии файла, проверяя значение

  ФУНКЦИИ lOResult.
  Следующий фрагмент программы использует значение функции lOResult для
проверки рузультата открытия файла. Если попытка открыть файл вызывает
ошибку, то программа выводит диалоговое окно с сообщением об ошибке и
запросом на подтверждение повторения попытки открытия файла.
  label bye;



  168_____________________Delphi 3. Программирование на Object Pascal


  var
f:TextFile;
fname:stringfname:= 'a:\test.txt';
AssignFile(f,fname) ;
repeat ($!-}
Reset(f); // открыть файл для чтения ($!+) res:=IOResult ;
if res о О
then answ:=MessageDlg('Ошибка открытия '+ fname+#13 +'Повторить
попытку?',mtWarning, (mbYes, mbNo],0);
until (res= 0) OR (answ = mrNo) ;
if res "" 0 then goto bye;
// здесь инструкции программы, которые выполняются в // случае успешного
открытия файла
bye:


  Чтение данных из файла

  Чтение из файла выполняется при помощи инструкций read и readin, которые в
общем виде записываются так:
  read{ФайловаяПеременная, СписокПеременных) readin(ФайловаяПеременная,
СписокПеременных)
где ФайловаяПеременная - переменная типа TextFile;
списокпеременных - имена переменных, разделенные запятыми.
  Чтение чисел
Следует понимать, что в текстовом файле находятся не числа, а их
изображения. Действие, выполняемое read или readin, фактически состоит из
двух: сначала из файла читаются символы до появления разделителя (пробела
или конца строки), затем, прочитанные символы, если они являются
изображением числа, преобразуются в число, и полученное значение
присваивается переменной.



  Ввод из файла________________________________________169


  Отличие инструкции readin от read состоит в том, что после считывания
очередного числа и присвоения его значения последней переменной списка
инструкции readin происходит переход к следующей строке файла. Например,
пусть файл data.txt содержит следующие строки:
  12 5 98 10 15 5 98 12
Тогда во время выполнения процедуры
Procedure Simple;
var
f:TextFile;
а,Ь,с:integer;
begin
As5ignFile(f,'a:\data.txt');
Reset(f) ;
read(f,a) ;
readin(f,b) ;
read(f,c);
end;
переменная а получит значение l2,b-5,c-i5.
  Если при чтении значения переменной в файле вместо изображения числа будет
какая-то другая последовательность символов, то происходит ошибка.
Например, если файл data. txt для предыдущей программы будет таким
12 мая 96 10 15 мая 98 12
то во время выполнения инструкции readin (f,b) произойдет ошибка, так как
символы "мая" не могут быть преобразованы в число (тип integer).
  Чтение строк
В программе строковая переменная может быть объявлена с указанием длины
ИДИ без указания. Например, strokal: string При чтении из файла значения
строковой переменной, длина которой явно задана в описании, считывается
столько символов, сколько указано в описании, но не больше, чем оставшаяся
непрочитанной часть текущей строки.
  При чтении из файла значения строковой переменной, длина которой явно не
задана в описании переменной, значением переменной становится оставшаяся
после последнего чтения часть текущей строки.
  Пусть текстовый файл groups. txt содержит строки:
  BeatleS Paul Mc'Cartnev Beetles John Lennon



  170 Delphi 3. Программирование на Object Pascal


  В следующей таблице приведены описания переменных, инструкции чтения из
файла groups. txt и значения переменных после выполнения инструкций чтения.
  Описание переменных
Инструкция чтения из файла
Значение переменных после чтения из файла
group:stringread(f,group,f name, 1 name)
group='Beatles '
fname:string

  f name='Paul '
1 name:string

  lname='Mc'Car'
group:string
read(f,group,f name, 1 name)
group=
f name:string


  'Beatles Paul Mc'Cartnev'
1 name:string
f name=''
1 name=''
group:stringread(f,group,f name, 1name)
groups'Beatles ' f name='Paul Me''
1 name:string1 name='Cartnev '
group:stringreadin(f,group);
group='Beatles '
f name:stringreadln(f,f name, 1 name)
fname='Beatl'
1 name:string

  1 name='es Pau'

  Определение конца файла
Пусть на диске есть текстовый файл, содержащий информацию о доходах.
Каждая строка файла начинается с цифры, соответствующей величине дохода,
за которой следует строка символов - комментарий. Файл может быть,
например, таким:
  250 Чтение лекций
1000 Гонорар за книгу
120 Доход по акциям ГАЗПРОМ
Допустим нужно вычислить суммарный доход. Решение задачи довольно
очевидно: надо открыть файл, прочитать число из первой строки и добавить
его к сумме, прочитать число из второй строки и добавить его к сумме, и т.
д. После прочтения последней строки вывести результат.
  Но как определить, что прочитана последняя строка, или, другими словами,
достигнут конец файла?
  Для определения конца файла можно воспользоваться функцией EOF (End Of
File - конец файла). У функции EOF один параметр - файловая переменная.
Значение функции EOF равно FALSE, если прочитанный элемент данных не
является последним в файле, т. е. возможно дальнейшее чтение



  Ввод из файла________________________________________171


  из файла. Если прочитанный элемент данных является последним, то значение
EOF равно TRUE.
  ( .Замечание ^
Значение EOF можно проверить сразу после открытия файла. Если при этом
значение EOF равно TRUE, то это свидетельствует о том, что файл не
содержит ни одного элемента данных и является пустым (размер такого файла
равен нулю).
  Ниже приведена процедура TForml.FormActivate, которая выполняет
поставленную задачу. Процедура запускается при активизации окна приложения
(рис.), которое содержит только один компонент - поле метки (Labell),
используемое для вывода результата работы программы.
  procedure (Sender: TObject) ;
var
fname:stringf:TextFile; f файловая переменная ) incom:integer; ( доход
из очередной строки файла) surnm: integer; { суммарный доход } begin
fname: =' а: \incora. txt';
AssignFile(f,fname) ;
{$!-}
Reset(f); (откроем для чтения) {$!+) if IOResult=0 then begin
suinro:=0;
while NOT EOF(f)do(noKa не конец файла) begin
readin(f,incom) ;
sunro: =summ+incom;
end;
CloseFile(f) ;
label 1.caption:"'Суммарный доход: 4-IntToStr(summ);
end else labe11.caption:"'Ошибка открытия '+fname;
end;
Обратите внимание: для организации обработки файла использована инструкция
цикла while, которая обеспечивает проверку значения EOF перед каждым
чтением, в том числе и перед первым. Перед первым чтением EOF проверяется
потому, что хотя открываемый файл может существовать на диске, однако он
может быть пустым (не содержать строк).


  Типы ДАННЫХ,
ОПРЕДЕЛЯЕМЫЕ ПРОГРАММИСТОМ

  В рассмотренных программах присутствовали стандартные типы данных Pascal.
Вместе с тем Pascal дает возможность программисту определить свой
собственный тип данных и затем использовать в программе данные этого типа.
  Новый тип данных базируется на основе стандартных типов или на основе
других, ранее созданных программистом, типов. Каждый вновь определенный
тип может быть отнесен к перечисляемому, интервальному или составному типу
данных.
  Перечисляемый тип
Определить перечисляемый тип, это значит - перечислить все значения,
составляющие данных тип.
  В общем виде объявление перечисляемого типа выглядит так:
  Тип=(Значение!, Значение2, ... Значение!)
где Тип - имя перечисляемого типа данных;
Значение! - символьная константа, определяющая одно из значений, которое
может принимать переменная типа тип.
  Примеры:
  TDayOfWeek=(MON,TOE,WED,THU,FRI,SAT,SUN) ;
TColor=(Red,Yellow,Green) ;
( Замечание ^
Согласно принятому в Delphi соглашению, имена типов должны начинаться с
буквы Т (от слова Type - тип).
  После объявления типа можно объявить переменную, относящуюся к этому типу.
Например,



  174 __________________Delphi 3. Программирование на Object Pascal


  type
TDayOfWeek = (MON,TUE,WED,THU,FRI,SAT,SUN);
var
ThisDay,LastDay:TDayOfWeek;
Помимо указания значений, которые может принимать переменная, описание
типа задает, как значения соотносятся друг с другом. Считается, что самый
левый элемент списка значений является минимальным, а самый правый -
максимальным. Для элементов типа Dayofweek справедливо:
  MON"TUE"WED"THU"FRKSAT"SUN
Свойство упорядоченности элементов перечисляемого типа позволяет
использовать переменные перечисляемого типа в управляющих инструкциях.
Например, так
if (Day = SAT) OR (Day = SUN) then begin
{ здесь действия, если день суббота или воскресенье } end;
Приведенную инструкцию можно записать и так
if Day " FRI then begin
( здесь действия, если день суббота или воскресенье } end;
Очевидно, что программа, написанная с использованием объявленного
программистом типа, более наглядна, легче читается и, следовательно,
уменьшается вероятность появления ошибки.
  Во время компиляции Delphi проверяет соответствие типа переменной типу
выражения, которое присваивается переменной. Если тип выражения не может
быть приведен к типу переменной, то выводится сообщение об ошибке.
Например, в фрагменте программы:
  type
TDayOfWeek = (MON,TUE,WED,THU,FRI,SAT,SUN);
var
ThisDay:TDayOfWeek;
begin
ThisDay:=1;
if ThisDay = 6 then begin
{ блок инструкций } end;



  Типы данных, определяемые программистом_____________________175


  инструкция ThisDay:=l ошибочна, так как переменная ThisDay принадлежит к
определенному программистом интервальному типу TDayOfWeek, a константа,
значение которой ей присваивается, принадлежит к целому типу. Условие
инструкции if тоже ошибочно.
  ( Замечание ^
Можно утверждать, что объявление перечисляемого типа - это сокращенная
форма записи объявления именованных констант. Например, приведенное выше
объявление типа TDayOfWeek равносильно следующему объявлению:
  const MON=0;
TUE=1;
WED=2;
THU=3 FRI=4 SAT=5 SUN=6
Интервальный тип
С помощью интервального типа определяется отрезок, часть, другого,
называемого базовым, типа. В качестве базового типа допускается
использование типа, в основе которого лежит целый тип данных.
  При объявлении интервального типа указывают нижнюю и верхнюю границы
интервала, т. е. наименьшее и наибольшее значение, которое может принять
переменная объявляемого типа. В общем виде объявление интервального типа
выглядит так:
  Тип=НижняяГраница . . ВерхняяГраница
где Тип - имя объявляемого интервального типа данных;
Нижняяграница - наименьшее значение, которое может принять переменная
объявляемого типа;
верхняяграница - наибольшее значение, которое может принять переменная
объявляемого типа.
  Примеры:
  TIndex=0..100;
TRusChar='A'.. 'я';
В объявлении интервального типа можно использовать именованные константы.
В следующем примере в объявлении интервального типа т index использована
символьная константа HBOUND.



  176_____________________Delphi 3. Программирование на Object Pascal


  const
HBOUND=100;
type
TIndex=l..HBOUND;
Интервальный тип удобно использовать при объявлении массивов. Например,
так:
  type
TIndex=l .. 100;
var
tabi: arrayi:TIndex;
Помимо целого типа в качестве базового можно использовать перечисляемый
тип. В следующем фрагменте на основе типа TMonth объявлен интервальный ТИП
Tsammer.
  type
TMonth=(Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep. Oct, Nov, Dec);
TSairoier=Jun. .Aug;
Запись
В практике программирования довольно часто приходится иметь дело с
данными, которые естественным образом состоят из других данных. Например,
сведения об учащемся состоят из фамилии, имени, отчества, числа, месяца и
года рождения, домашнего адреса и прочей информации. Для представления
подобной информации в Pascal используется структура, которая называется
record (запись).
  Запись - это структура данных, которая, с одной стороны, может
рассматриваться как единая структура, с другой стороны - как набор
отдельных элементов, компонентов. Характерной особенностью записи является
то, что составляющие ее компоненты могут быть разного типа. Другая
особенность записи, как структуры данных, состоит в том, что каждый
компонент записи имеет имя.
  Объявление типа записи
Тип записи должен быть объявлен в разделе type. В общем виде объявление
записи выглядит так:
  имя = record
Поле_1:Тип_1;
Поле 2: Тип 2;



  Типы данных, определяемые программистом_____________________177


  Поле_К:Тип_К;
end;
где . Имя - имя типа записи;
record - зарезервированное слово языка Pascal, означающее, что далее
следует объявление компонентов (полей) записи;
лоле_-1 и тип_1 - имя и тип i-го компонента (поля) записи. Вот примеры
описаний записей:
  type
TPerson = record
f_name:string1_name:stringday:integer ;
month:integer ;
year:integer;
address:stringend;
TDate = record day:integer;
month:integer-year:integer;
end;
После объявления типа записи можно объявить переменную-запись, например:
  var
student:TPerson;
birthday:TDate;
Для доступа к полю записи указывают имя записи и имя поля, отделяя имя
поля от имени записи точкой. Например, инструкция
ShowMessage(' Имя: ',student.f_name+#13 +'Адрес: ',student.address) ;
выводит имя и адрес студента, информация о котором находится в
перемен-ной-записи student.
  Иногда тип переменной-записи объявляют непосредственно в разделе
объявления переменных. В этом случае тип записи указывается сразу за
именем переменной, через двоеточие. Например запись student может быть
объявлена в разделе var следующим образом:



  178 Delphi 3. Программирование на Object Pascal


  student:record
f name:string1 name:stringday:integer;
month;integer-year: integer;
address:stringend;
Инструкция WITH
Инструкция with позволяет использовать в тексте программы имена полей без
указания имени переменной-записи. В общем виде инструкция выглядит так:
  with Имя do begin
( здесь инструкции программы } end;
где
with - зарезервированное слово языка Pascal, означающее, что далее до
слова end при обращении к полям переменной-записи имя можно не указывать
имя записи;
Имя - имя переменной-записи. Например, если в программе объявлена
переменная-запись
student:record // информация о студенте f name:stringи данные о студенте
находятся в полях Editi, Edit2 и Edit3 диалогового окна, то для заполнения
полей записи вместо инструкций
"
student.f_name:=Editl.text;
student.1_name:= Edit2.text;
student.address:=Edit3.text ;
можно записать
with student do begin
f_name:=Editl.text;



  Типы данных, определяемые программистом 179


  1_name:=Edit2.text ;
address:=Edit3.text;
end;
Ввод и вывод записей в файл
Записи можно хранить в файле. Чтобы программа могла сохранить значение
переменной-записи в файле или ввести его из файла, надо объявить файл,
указав в качестве типа его компонентов тип записи (record). Например,
инструкции
type
person == record
f name:string1_naine: string address:stringend;
var
f: file of person;
объявляют файл, компонентами которого являются записи типа person. После
объявления файла, связывания файловой переменной с конкретным
файлом (AssignFile), ОТКрЫТИЯ файла (Append, Reset ИЛИ Rewrite) Пёре-
менные-записи могут записываться в файл и читаться из файла инструкциями
write И read соответственно.
  Следующая программа записывает (добавляет) введенные пользователем данные
о результатах соревнований в файл, формируя таким образом базу данных.
Данные вводятся в поля диалогового окна (рис. 114), и сохраняются в файле,
компонентами которого являются записи типа TMedai.
  Рис. 114. Диалоговое окно программы


  180_____________________Delphi 3. Программирование на Object Pascal


  Ниже приведен листинг модуля формы приложения.
  unit арргес_;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;
type
TFonnl = class(TForm) // описание формы приложения
Label 1: TLabel;
LabelZ: TLabel;
Label3: TLabel;
Editi: TEdit;
Buttoni: TButton;
LabelS: TLabel;
ComboBoxl: TComboBox;
ComboBox2: TComboBox;
RadioGroupl: TRadioGroup;
Label4: TLabel;
procedure FonnActivate(Sender: TObject) ;
procedure FonnClose(Sender: TObject; var Action: TCloseAction);
procedure ButtonlClick(Sender: TObject);
private
( Private declarations ) public
( Public declarations } end;
// тип медали TKind=(GOLD,SILVER,BRONZE) ;
// запись файла TMedal=record
country:stringsport:stringperson:stringkind:TKind;
end;
var
Fonnl: TFonnl;
f: file of TMedal;
iinplementation


  Типы данных, определяемые программистом_____________________181


  {$R *.DFM)
procedure TFonnl.FormActivate(Sender: TObj ect) ;
var
resp*: word;
begin
AssignFile(f,'a:\medals. db') ;
{$!-}
Append(f); // открыть файл для добавления {$!+} if lOResult = О
then buttoni.enabled:=TRUE else begin resp:=MessageDlg('Файл базы данных
не найден.'+
'Создать новую БД?', mtlnformation, if resp = mrYes then begin ($!-}
rewrite(f);
($!+} if lOResult = 0
then buttoni.enabled:=TRUE else ShowMessage('Ошибка создания файла БД.');
end;
end;
end;
procedure TFonnl.ButtoniClick(Sender: TObject);
var
medal: TMedal;
begin
with medal do begin
country:=ComboBoxl.Text ;
sport:=ComboBox2.Text;
person:=Editl.Text ;
case RadioGroupl.Itemlndex of 0:kind:=GOLD;
l:kind:=SILVER;
2:kind:=BRONZE;
end;
end;
write(f,medal);
end;


  182__________________Delphi 3. Программирование на Object Pascal


  procedure TFormi.FormClose(Sender: TObject; var Action: TCloseAction);
begin
CloseFile(f);
end;
Файл базы данных для добавления открывает процедура TFormi. FormActivate.
  Непосредственное добавление записи в файл выполняет процедура
TFormi.Buttoniciick, которая запускается при щелчке на кнопке Добавить
(Buttoni). Поля country и sport добавляемой записи заполняются из свойства
Text комбинированных списков Страна (comboBoxl) и Вид спорта
(ComboBox2).
  С Замечание ^)
Во время создания формы приложения в свойства items компонентов ComboBoxl
и ComboBox2 следует ввести список стран и видов спорта.
  Поле person заполняется из поля Спортсмен (Editi). Значение поля medal
определяется выбранной кнопкой компонента RadioGroupi.
  Закрытие файла базы данных выполняет процедура TFormi. Formdose.
  Так как ТИП TMedai Используется ДВУМЯ Процедурами (TFormi. FormActivate
и TFormi. Buttoniciick), то его описание помещено в раздел type модуля
формы. Объявление файловой переменной f по этой же причине помещено в
раздел объявления переменных модуля формы.
  Следующая программа демонстрирует процесс чтения записей из файла.
Программа открывает сформированный программой Добавление записи в файл
файл и выводит список медалей, выигранных представителями страны,
указанной в окне диалога (рис. 115).
  Рис. 115. Диалоговое окно программы Чтение записей из файла
Для вывода результата (списка медалей) используется компонент Memol,
значения некоторых свойств которого приведены ниже.


  Типы данных, определяемые программистом_____________________183


  Свойство
Значение
Name
Memol
Scrol'i.Bars
ssVertical
Readonly
True

  Чтение записей из файла и вывод списка медалей выполняет процедура,
которая запускается в результате щелчка на кнопке Поиск (Buttoni).
  procedure TFormI.ButtonlClick(Sender: TObject);
type
// тип медали
TKind=(GOLD,SILVER,BRONZE) ;
// запись файла TMedal=record
country:stringsport:stringperson:stringkind:TKind;
end;
var
f:file of TMedal;
rec .TMedal;
n:integer; ( общее количество медалей ) st:stringbegin
AssignFileff,'a:\medals.db') ;
($!-}
Reset(f); // открыть файл для чтения ($!-) if-lOResult "" О
then ShowMessage('Ошибка открытия файла БД.') else begin
// обработка БД buttoni.enabled:=FALSE;
n:=0;
while not EOF(f) do begin
read(f,rec) ;
if rec.country = Editl.Text then begin
if n = 0
then Memol.Lines.Add('*** '+Editl.Text+' ***');



  184_____________________Delphi 3. Программирование на Object Pascal


  n:=n+l;
case rec.kind of GOLD: 5t:='Золотая ';
SILVER:st:='Серебряная ';
BRONZE: st: ='Бронзовая ' ;
end;
st:=st+rec.sport+' '+rec.person;
Memol.Lines.Add(st);
end;
end;
CloseFile(f);
if n = 0
then ShowMessage('В БД нет информации о спортсменах страны '+Editl.Text);
buttoni.enabled:=TRUE ;
end;
end;
Процедура открывает файл и последовательно читает находящиеся в нем
записи. Если прочитанная запись удовлетворяет условию запроса, содержимое
поля country совпадает с названием страны, введенным пользователем в поле
Страна (Editi) диалогового окна, то содержимое записи добавляется в поле
Memol. Добавление информации в поле мелю выполняет инструкция Memo I. Add
(st), которая является инструкцией применения метода Add (добавить) к
компоненту Memol.
  ( Замечание ^
Понятие "метод" подробно будет рассмотрено позже, в разделе, посвященном
объектно-ориентированному программированию. Сейчас можно сказать, что
метод - это процедура, инструкция вызова которой записывается особым
образом с целью показать, что одним из ее параметров является объект.
  Динамические структуры данных
До этого момента мы имели дело только с данными, имеющими статическую, не
изменяемую во время работы программы структуру. При этом во время работы
программы могли изменяться только значения переменных, однако количество
переменных всегда оставалось постоянным (отсюда и название - статические
структуры). Это не всегда удобно. Например, если программа предназначена
для ввода и обработки данных об учениках класса, и для хранения данных
используются массивы, то, определяя размер массива, программист должен
ориентироваться на некоторое, как ему кажется, среднее или предельное
значение количества учеников в классе. При этом, если реально учеников в
классе меньше предполагаемого числа, то не



  Типы данных, определяемые программистом_____________________185


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


  Рис. 116. Переменная-указатель


  Переменная-указатель, как и любая переменная программы, должна быть
объявлена в разделе объявления переменных. В общем виде объявление
пе-ременной-указателя выглядит так:
  Имя: "Тип
где имя - имя переменной-указателя;
тип - тип переменной, на которую может указывать переменная-указатель
Имя.
  Значок А показывает, что объявляемая переменная - указатель.
  Вот примеры объявления переменных-указателей:
  pi: ^integer;
p2:лreal;
Переменная pi - это указатель на переменную типа integer, p2 - на
переменную типа real.
  В начале работы программы переменная-указатель ни на что не указывает, ее
значение равно NIL. Зарезервированное слово (идентификатор) NIL
используется для обозначения значения переменной-указателя, которая ни на
что не указывает. Идентификатор NIL можно использовать в инструкциях
присваивания и в условиях. Например, если переменные pi и p2 объявлены как
указатели, то инструкция
pl:=NIL;
устанавливает значение переменной, а инструкция


  186 ___________________Delphi 3. Программирование на Object Pascal


  if p2 = NIL
then ShowMessage('Указатель р2 ни на что не указывает!');
выводит сообщение, если значение p2 равно NIL.
  Указателю можно присвоить значение другого указателя при условии, что они
являются указателями на переменную одного типа. Например, если переменные
pi и p2 являются указателями на переменную типа integer, то в результате
выполнения инструкции
р2:=р1;
р1 и p2 указывают на одну и ту же переменную.
  Указатель можно использовать для того, чтобы изменить значение переменной,
на которую он указывает. Например, если р указывает на переменную i, то в
результате выполнения инструкции
р":=5;
значение переменной i будет равно пяти. В приведенном примере значок /\
показывает, что значение пять присваивается переменной, на которую
указывает переменная-указатель.
  Динамические переменные
Динамической переменной называется переменная, память для которой
выделяется во время работы программы.
  Выделение памяти для динамической переменной осуществляется вызовом
процедуры new. У процедуры new один параметр - указатель на переменную
того типа, память для которой надо выделить. Например, если р является
указателем на переменную типа real, то в результате выполнения процедуры
new(p), будет создана переменная типа real и ее адрес присвоится
переменной-указателю р.
  У динамической переменной нет имени, поэтому обратиться к ней можно только
при помощи указателя.
  Процедура, использующая динамические переменные, перед завершением своей
работы должна освободить занимаемую этими переменными* память или, как
говорят программисты, уничтожить динамические переменные. Для освобождения
памяти, занимаемой динамической переменной, используется процедура
Dispose, которая имеет один параметр - указатель на динамическую
переменную.
  Например, если р - указатель на динамическую переменную, память для
которой выделена инструкцией new(p), то инструкция dispose (р) освобождает
занимаемую динамической переменной память.


  Типы данных, определяемые программистом_____________________187


  Следующая процедура демонстрирует создание, использование и уничтожение
динамических переменных.
  procedure TFormI.ButtonlClick(Sender: TObject);
var
pl,p2,p3:'''integer; // указатели на переменные типа integer begin
// создадим динамические переменные типа integer
new (pi) ;
new(p2);
new(p3);
pl^^StrToIntfEditl.Text) ;
pS'^StrToInttEd^.Text) ;
p3/^:=pl/\+p2'^;
ShowMessage('Сумма введенных чисел равна '+IntToStr(рЗ"));
// уничтожим динамические переменные dispose(pi);
dispose(p2);
dispose(рЗ);
end;
Процедура создает три динамические переменные. Две переменные, на которые
указывают pi и p2, получают значения из полей редактирования (Editi и
Edit2). Значение третьей переменной вычисляется как сумма первых двух.
  Связанные списки
Указатели и динамические переменные позволяют создавать сложные
динамические структуры данных, такие как связанные списки и деревья.

  Связанный список можно изобразить графически (рис. 117).
  Рис. 117. Графическое изображение связанного списка
Каждый элемент списка (узел) представляет собой запись, состоящую из двух
частей. Первая часть - информационная. Вторая часть обеспечивает связь со
следующим, и возможно с предыдущим, элементом списка. Список, в котором
обеспечивается связь только со следующим элементом, называется односвязным.
  Чтобы программа могла использовать список, надо определить тип компонентов
списка и переменную-указатель на первый элемент списка. Вот пример
объявления компонента списка студентов:


  188 Delphi 3. Программирование на Object Pascal


  type

  TPStudent^TStudent; // указатель на переменную типа TStudent
( описание типа элемента списка } TStudent=record
sumame:string{ имя } { номер группы } ( домашний адрес }
{ следующий элемент списка)
паше:stringgroup:integer;
address:stringnext:TPStudent ;
end;
var

  head:TPStudent; ( указатель на первый элемент списка }
Добавлять данные можно в начало, в конец или в нужное место списка. Во
всех этих случаях необходимо корректировать указатели. На рис. 118
изображен процесс добавления элементов в начало односвязанного списка.

  Рис. 118. Добавление элементов в список


  Следующая программа формирует список студентов, добавляя фамилии в начало
списка. Данные вводятся в поля редактирования (Editi и Edit2) диалогового
окна (рис.119) программы и при щелчке на кнопке Добавить (Buttoni)
добавляются в список.
  Рис. 119. Диалоговое окно программы Динамический список 1



  Типы данных, определяемые программистом_____________________189


  Непосредственное добавление элемента в список выполняет процедура
TForml.Buttoniciick, которая создает динамическую переменную-запись -
присваивает ее полям значения - содержимое полей ввода диалогового окна, и
корректирует значение указателя head.
  procedure TForml.Buttoniciick(Sender: TObject);
var
curr: TPStudent; // новый, текущий элемент списка begin
new(curr); // создание нового элемента списка
curr".rename:"Edit 1.Text ;
curr".1_name:=Edit2.Text ;
// добавление в начало списка
curr".next:=head;
head:=curr;
Editl.text:='';
Edit2.text:ш'';
end;
Процедура TForml.Button2dick, которая запускается при щелчке на кнопке
Список, перемещаясь по списку от начала, на которое указывает переменная
head, формирует строковое представление списка до тех пор, пока значение
поля next очередного элемента списка не будет равно NIL.
  procedure TForml.Button2dick (Sender: TObject);
var
curr: TPStudent; // текущий элемент списка n:integer; // длина (кол-во
элементов) списка st:string; // строковое представление списка begin п:=0;
st:=";
curr: "head;
while curr "" NIL do // пока не конец списка begin n:=n+l;
st:=st+curr".f_name+' '+curr".1_name+#13;
curr:"curr".next ;
end;
if n о О
then ShowMessage('Список:'+#13+st) else ShowMessage('В списке нет
элементов.');
end;
Переменная head и тип TStudent используются обеими процедурами, поэтому их
объявление



  190 Delphi 3. Программирование на Object Pascal


  type
TPStudent="TStudent; //указатель на тип TStudent
TStudent = record
f_name:stringl_name: string(20]; // имя
next: TPStudent; // следующий элемент списка end;
var
head: TPStudent;
// начало (голова) списка
следует поместить в раздел implementation перед объявлением приведенных
выше процедур.
  Как правило, списки упорядочены. Порядок следования элементов в списке
определяется содержимым одного из полей. Например, список с информацией о
людях обычно упорядочен по полю, содержащему фамилию.
  Чтобы добавить узел в упорядоченный список, нужно найти узел, за которым
должен следовать добавляемый элемент, и установить его указатель на новый
элемент, а указатель нового узла установить на узел, перед которым он
вставляется (рис. 120).


  Рис. 120. Добавление элемента в упорядоченный список


  Следующая программа Упорядоченный список 2 формирует список, упорядоченный
по полю "фамилия". Вид диалогового окна программы приведен на рис. 121.
  Рис. 121. Диалоговое окно программы Упорядоченный список 2


  Типы данных, определяемые программистом_____________________797


  Данные вводятся в поля редактирования (Editi и Edit2) и при щелчке на
кнопке Добавить (Buttoni) добавляются в список таким образом, что список
всегда упорядочен по полю "фамилия". Непосредственное добавление узла в
описок выполняет процедура TFonnl .Buttoniciick.
  procedure TFornu.ButtonlClick(Sender: TObject);
var
node: TPStudent; // новый узел списка curr: TPStudent; // текущий узел
списка pre: TPStudent; // предыдущий, относительно curr, узел begin
new(node); // создание нового элемента списка nodeA.f_name:=Editl.Text ;
node".1_name:=Edit2.Text ;
// добавление узла в список
// сначала найдем подходящее место в списке для узла curr:=head;
pre:=NIL;
( Внимание!
  если приведенное ниже условие заменить на (node. f_nanie"curr". f_name)
and (currONIL), то при проверке условия (node.f name"curr".f name) во
время добавления первого узла возникает ошибка времени выполнения, так как
curr = NIL и, следовательно, переменной curr."name нет!
  В используемом варианте условия ошибка не возникает, так как сначала
проверяется условие (curr о NIL), значение которого FALSE, и второе
условие в этом случае не проверяется. )
while (curr о NIL)and(node.f_name " curr".f_name) do begin
// введенное значение больше текущего pre:= curr; '
curr:=curr".next; //к следующему узлу end;
if pre = NIL then begin
// новый узел в начало списка node".next:=head;
head:=node ;
end else begin
// новый узел после pre, перед curr node".next:=pre".next;


  192 Delphi 3. Программирование на Object Pascal


  pre л.next:=node ;
end;
Editl.text:='';
Edit2.text:='';
i
end;
Процедура TForml.Buttonlciick создает динамическую переменную-запись,
присваивает ее полям значения - содержимое полей ввода диалогового окна,
находит подходящее для узла место и коррекцией значения указателя next
узла, после которого должен быть помещен новый узел, добавляет' этот узел
в список.
  Вывод списка выполняет процедура, которая запускается щелчком на кнопке
СПИСОК (Button2).
  procedure TFonnl.Button2Click(Sender: TObject);
var
curr: TPStudent; // текущий элемент списка n:integer; // длина (кол-во
элементов) списка st:string; // строковое представление списка begin п:=0;
st:=";
curr:=head;
while curr "" NIL do begin n: =n+l;
st:^st+curr".f_name+' '+currл.1_name+#13 ;
curr:=currA.next ;
end;
if n о О
then ShowMessage('Список:'+#13+st) else ShowMessage('В списке нет
элементов.') ;
end;
Приведенное ниже описание типа узла списка и переменной head следует
поместить в раздел implementation, перед текстом процедур.
  type
TPStudent=^TStudent; //указатель на тип TStudent
TStudent = record
f name:string1_name: string next: TPStudent; // следующий элемент
списка end;

  Типы данных, определяемые программистом 193
head: TPStudent; // начало (голова) списка
После ^запуска программы и ввода нескольких фамилий, например, в такой
последовательности: Иванов, Яковлев, Алексеев, петров, список выглядит
так, как показано на рис. 122.
  Рис. 122. Пример упорядоченного списка, сформированного программой
Чтобы удалить узел, надо скорректировать значения указателя узла, который
находится перед удаляемым узлом (рис. 123).

  Рис. 123. Удаление элемента из списка


  Узел - это динамическая переменная, которая теперь не нужна; поэтому,
после исключения узла из списка, надо освободить память, занимаемую этой
переменной. Освобождение динамической памяти, или, как иногда говорят,
уничтожение переменной, выполняется вызовом процедуры dispose. У процедуры
dispose один параметр - указатель на переменную, память, занимаемая
которой, должна быть освобождена. Например, в программе:
  var
р ^integer;
begin
new(p) ;
{ здесь инструкции программы )
dispose(p) ;
end
создается динамическая переменная, затем она уничтожается. Освободившуюся
память смогут использовать другие переменные. Если этого не делать, то,
возможно, из-за недостатка свободной памяти в какой-то момент времени
программа не сможет создать очередную динамическую переменную.



  194 Delphi 3. Программирование на Object Pascal


  Следующая программа позволяет добавлять и удалять узлы упорядоченного
списка. Диалоговое окно программы приведено на рис. 124.
  Рис. 124. Диалоговое окно программы Динамический список 3
Процедуры добавления узла в список и вывода списка, а также описание типа
узла списка ни чем не отличаются от соответствующих процедур и описания
рассмотренной ранее программы Упорядоченный список, поэтому они здесь не
приводятся. Удаление узла из списка выполняет процедура, которая
запускается при щелчке на кнопке Удалить (Buttons).
  procedure TForml.Button3Click(Sender: TObject);
var
curr:TPStudent; // текущий, проверяемый узел pre: TPStudent; // предыдущий
узел
found:boolean; // TRUE - узел, который надо удалить, есть в списке begin
if head = NIL
then MessageDlg('Список пустой!',mtError,curr:=head;
pre:=NIL;
found:=FALSE;
// найти узел, который надо удалить while (curr "" NIL) and (not found) do
begin
if (curr^.f_name = Editl.Text) .
  and (curr^.l_name = Edit2.Text) then found:=TRUE // нужный узел найден
else // к следующему узлу begin
pre:=curr;
curr: "^curr^. next ;
end;
end;


  Типы данных, определяемые программистом 195


  if found then
begin // удаляем узел if pre = NIL
then head^curr".next // удаляем первый узел else pre^.next:=curr.next;
dispose(curr) ;
Editl.Text:=";
Editl.Text:='';
end
else // узла, который надо удалить, в списке нет Меззаде01д('Узел'+#13
+'Имя:'+Editl.Text+#13 +'Фамилия:'+Edit2.Text+#13 +'в списке не найден.'
,mtError,end;
Процедура просматривает список от начала и сравнивает содержимое полей
текущего узла с содержимым полей ввода диалогового окна. Если их
содержимое совпадает, то программа исключает узел из списка и освобождает
занимаемую этим узлом память. Если узла, который надо удалить, в списке
нет, то программа выводит сообщение об ошибке.


  ВВЕДЕНИЕ
В ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ


  Исторически сложилось так, что программирование возникло и развивалось как
процедурное программирование, которое предполагает, что основой программы
является алгоритм, процедура обработки данных.
  Объектно-ориентированное программирование (ООП) - это методика разработки
программ, в основе которой лежит понятие объекта, как некоторой структуры,
описывающей объект реального мира, его поведение. Задача, решаемая с
использованием методики ООП, описывается в терминах объектов и операций
над ними, а программа при таком подходе представляет собой набор объектов
и связей между ними.
  ( Замечание ^
Строго говоря, для того, чтобы разрабатывать приложения в Delphi на базе
предоставляемых средой разработки компонентов, знание концепции ООП не
является необходимым. Однако для более глубокого понимания того, как
программа взаимодействует с компонентами, что и почему Delphi добавляет в
текст программы, материал данной главы весьма полезен.
  Класс
Классический язык Pascal позволяет программисту определять свои
собственные сложные типы данных - записи (records). Object Pascal,
поддерживая концепцию объектно-ориентированного программирования, дает
возможность определять классы. Класс - это сложная структура, включающая в
себя помимо описания данных описание процедур и функций, которые могут
быть выполнены над представителем класса - объектом.
  Вот пример описания простого класса:
  TTPerson=class private
fname:stringfaddress:stringpublic
procedure show;
end;



  198_____________________Delphi 3. Программирование на Object Pascal


  Данные класса называются полями, процедуры и функции - методами. В
приведенном примере TTPerson - это имя класса, fname и faddress - имена
полей, show - имя метода.
  С Замечание ^)
Согласно принятому в Delphi соглашению имена полей должны начинаться с
буквы f (от слова field - поле).
  В программе описание класса помещают в раздел описания типов (type).
  Объект
В программе представители класса - объекты, объявляются в разделе var.
Например, так:
  var
student:TTPerson;
professor:TTPerson;
Следует обратить особое внимание на то, что в Object Pascal объект - это
динамическая структура. Переменная-объект содержит не данные, а ссылку на
данные объекта. Поэтому программист должен позаботиться о выделении памяти
для этих данных.
  Выделение памяти осуществляется при помощи специального метода класса -
конструктора, которому обычно присваивают имя create (создать). Чтобы
подчеркнуть особую роль и поведение конструктора, в описании класса вместо
слова procedure используется слово constructor. Ниже приведено описание
класса TTPerson, в состав которого введен конструктор.
  TTPerson = class private
fname:stringfaddress:stringconstructor create; // конструктор public
procedure show; // метод end; .
  Выделение памяти для данных объекта происходит присваиванием значения
результата применения метода-конструктора к типу (классу) объекта.
Например, после выполнения инструкции
professor:=TTPerson.create;
выделяется необходимая память для данных объекта professor .


  Введение в объектно-ориентированное программирование______________199


  Помимо выделения памяти, конструктор, как правило, решает задачу
присваивания полям объекта начальных значений, т. е. осуществляет
инициализацию объекта. Ниже приведен пример реализации конструктора для
объекта TTI^erson.
  constructor TTPerson.create;
begin
fname:='';
faddress:='' ;
end;
Реализация конструктора несколько необычна. Во-первых, в теле конструктора
нет привычных инструкций New, обеспечивающих выделение динамической памяти
(всю необходимую работу по выделению памяти выполняет компилятор).
Во-вторых, формально, конструктор не возвращает значения, хотя в программе
обращение к конструктору осуществляется как к методу-функции.
  После объявления и инициализации объект можно использовать, например,
установить значение поля объекта. Доступ к полю объекта осуществляется
указанием имени объекта и имени поля, которые отделяются друг от друга
точкой. Хотя объект является ссылкой, однако правило доступа к данным с
помощью ссылки, согласно которому после имени переменной, являющейся
ссылкой, надо ставить значок А, на объекты не распространяется. Например,
для доступа к полю fname объекта professor вместо
professor^.fname
надо писать professor.fname
Очевидно, что такой способ доступа к полям объекта более естественен.
  Если в программе некоторый объект больше не используется, то можно
освободить память, занимаемую полями этого объекта. Для выполнения этого
действия используют метод-деструктор free. Например, чтобы освободить
память занимаемую полями объекта professor, достаточно записать
professor.free ;
Метод
Методы класса (процедуры и функции, объявление которых включено в описание
класса) выполняют действия над объектами класса. Чтобы метод был выполнен,
надо указать имя объекта и имя метода, отделив одно имя от другого точкой.
Например, инструкция
professor.show;



  200_____________________Delphi 3. Программирование на Object Pascal


  вызывает применение метода show к объекту professor. Фактически инструкция
применения метода к объекту - это специфический способ записи инструкции
вызова процедуры.
  В программе методы класса определяются точно так же, как обычные процедуры
и функции, за исключением того, что имя процедуры или функции, являющейся
методом, состоит из двух частей: имени класса, к которому принадлежит
метод, и имени метода. Имя класса от имени метода отделяется точкой.
  Ниже приведен пример определения метода show приведенного выше класса
TTPerson.
  // метод show класса TTPerson procedure TTPerson.show;
begin
ShowMessage('Имя:'+fname+#13+'Адрес:'+faddress) ;
end;
Следует обратить внимание на то, что в инструкциях метода доступ к полям
объекта осуществляется без указания имени объекта.
  Инкапсуляция и свойства объекта
Под инкапсуляцией понимается скрытие полей объекта с целью обеспечения
доступа к ним только посредством методов класса.
  В Object Pascal ограничение доступа к полям объекта реализуется при помощи
свойств объекта.' Свойство объекта характеризуется полем, хранящем
значение свойства, и двумя методами, обеспечивающими доступ к полю
свойства. Метод установки значения свойства называется методом записи
свойства (write), метод получения значения свойства называется методом
чтения свойства (read).
  В описании класса перед именем свойства записывают слово property
(свойство). После имени свойства указывается его тип, затем имена методов,
обеспечивающих доступ к значению свойства. После слова read указывается
имя метода, обеспечивающего чтение свойства, после слова write - записи
свойства имя метода. Ниже приведен пример описания класса TTPerson,
содержащего два свойства: Name и Address.
  type
TName=stringTAddress''stringTTPerson = class private
FNaine:Tname; // значение св-ва Name



  Введение в объектно-ориентированное программирование______________201


  FAddress:TAdress; // значение св-ва Address Constructor Create
(Name:Tnan"e);
Procedure Show;
. Function GetNaine:TName;
Function GetAddress:TAddress;
Procedure SetAddress(NewAddress:TAddress);
public
Property Name: Tname read GetName;
Property Address: TAddress read GetAddress write SetAddress;
end;
В программе для установки значения свойства не обязательно записывать
инструкцию применения к объекту метода установки значения свойства, можно
записать обычную инструкцию присваивания значения свойству. Например,
чтобы присвоить значение свойству Adress объекта student, достаточно
записать
student.Address:= 'С.Петербург, ул.Садовая 21, кв.З';
Компилятор перетранслирует приведенную инструкцию присваивания значения
свойству в инструкцию вызова метода
student.SetAddress('С.Петербург, ул.Садовая 21, кв.З');
Внешне использование свойств в программе ничем не отличается от
использования полей объекта. Вместе с тем между свойством и полем объекта
существует принципиальное отличие: при присвоении и чтении значения
свойства автоматически вызывается процедура, которая выполняет некоторую
работу.
  В программе на методы свойства можно возложить некоторые дополнительные
задачи. Например, с помощью метода можно проверить корректность
присваиваемых свойству значений, установить значения других, логически
связанных со свойством, полей, вызвать вспомогательную процедуру.
  Оформление данных объекта как свойства позволяет ограничить доступ к
полям, хранящим значения свойств объекта, например можно разрешить только
чтение. Чтобы инструкции программы не могли изменить значение свойства, в
описании свойства надо указать только имя метода чтения. Попытка присвоить
значение свойству, предназначенному только для чтения, вызывает ошибку
времени компиляции. В приведенном выше описании класса TTPerson свойство
Name доступно только для чтения, а свойство Address - для чтения и записи.



  202_____________________Delphi 3. Программирование на Object Pascal


  Установить значение свойства, защищенного от записи, можно во время
инициализации объекта. Ниже приведены методы класса TTPerson,
обеспечивающие создание объекта класса тт per son и доступ к его свойствам.
  //конструктор объекта TTPerson Constructor TTPerson.Create(Name:TName) ;
begin
FNanie:=Name;
end;
// метод получения значения свойства Name Function TTPerson.GetName;
begin
Result:=FName;
end;
// метод получения значения свойства Address
Function TTPerson.GetAddress; 
begin
Result:=FAddress ;
end;
// метод изменения значения свойства Address Procedure
TTPerson.SetAddress(NewAddress:TAddress) ;
begin
if FAddress =''
then FAddres s:=NewAddres s;
end;

  Приведенный конструктор объекта TTPerson создает объект и устанавливает
значение поля FName, определяющего значение свойства Name.
  Инструкции программы, обеспечивающие создание объекта класса ттрегзоп и
установку его свойства, могут быть, например, такими:
  student:"TTPerson.create('Иванов') ;
student.address:='ул. Садовая, д.З, кв.25';
Наследование
Концепция объектно-ориентированного программирования предполагает
возможность определять новые классы посредством добавления полей, свойств
и методов к уже существующим классам. Такой механизм получения новых
классов называется порождением. При этом новый, порожденный, класс
(потомок) наследует свойства и методы своего базового, родительского
класса.



  Введение в объектно-ориентированное программирование______________203


  В объявлении класса-потомка указывается класс родителя. Например, класс
TEmployee (сотрудник) может быть порожден от рассмотренного выше класса
ттрегзоп путем добавления поля Department (отдел). Объявление класса
TEmployee в этом случае может выглядеть так:
  TEmployee = class(TTPerson)
FDepartment:integer; // номер отдела
constructor Create(Name:TNanie;Dep:integer) ;
end;
Заключенное в скобки имя класса TTPerson показывает, что класс TEmployee
является производным от класса TTPerson. В свою очередь, класс TTPerson
является базовым для класса TEmployee.
  Класс TEmployee имеет свой собственный конструктор, который обеспечивает
инициализацию класса родителя и своих полей. Вот пример реализации
конструктора класса TEmployee:
  constructor TEmployee.Create(Name:Tname;Dep:integer);
begin
inherited Create(Name);
FDepartment:=Dep;
end;
В приведенном примере директивой inherited вызывается конструктор
родительского класса, затем присваивается значение полю класса потомка.
  После создания объекта производного класса в программе можно использовать
поля и методы родительского класса. Ниже приведен фрагмент программы,
демонстрирующей эту возможность.
  engineer:=TEmployee.create('Сидоров',413);
engineer.address:='ул.Блохина, д.8, кв.10';
Первая инструкция создает объект типа TEmployee. Вторая устанавливает
значение свойства, которое относится к родительскому классу.
  Директивы Protectedи Private
Помимо объявлений элементов класса (полей, методов, свойств) описание
класса, как правило, содержит директивы Protected (защищенный) и private
(закрытый), которые устанавливают степень видимости элементов класса в
программе.
  Элементы класса, объявленные в секции protected, доступны только в
порожденных от него классах. Область видимости элементов класса этой сек-



  204_____________________Delphi 3. Программирование на Object Pascal


  ции не ограничивается модулем, в котором находится описание класса. Обычно
в секцию protected помещают описание методов класса.
  Элементы класса, объявленные в секции private, видимы внутри модуля. Эти
элементы не доступны за пределами модуля, даже в производных классах.
Обычно в секцию private помещают описание полей класса, а методы,
обеспечивающие доступ к этим полям, помещают в секцию protected.
  Ниже приведено описание класса ттрегзоп, в которое включены директивы
управления доступом.
  TTPerson = class private
FName: TName; ( значение св-ва Name } FAddress:TAddress; ( значение
св-ва Address) protected
Constructor Create(Name:TName);
Function GetName: TName;
Function GetAddress:TAddress ;
Procedure SetAddress(NewAddress:TAddress) ;
Property Name:TName read GetName;
Property Address:TAddress read GetAddress write SetAddress;
end;
С Замечание ^)
Если надо чтобы Элементы класса были полностью скрыты, то определение
класса следует поместить в отдельный модуль.
  Полиморфизм и виртуальные методы
Полиморфизм - это возможность использовать одинаковые имена для методов,
входящих в различные классы. Концепция полиморфизма обеспечивает при
применении метода к объекту использование именно того метода, который
соответствует классу объекта.
  Пусть определены три класса, один из них является базовым для двух других.
  type
// базовый класс TPerson=class
fname:string;( имя )
constructor Create(name:string);
function info: string; virtual;
end;



  Введение в объектно-ориентированное программирование______________205


  // производный от базового TPerson TStud=class(TPerson)
fgr:integer; { номер группы }
constructor Create(name:string;gr:integer) ;
function info: string; override;
end;
// производный от базового TPerson TProf=class(TPerson)
fdep:string; { название кафедры }
constructor Create(name:string;dep:string);
function info: string; override;
end;
В каждом из этих кяассов определен метод info. В базовом классе при помощи
директивы virtual метод info объявлен виртуальным. Объявление метода
виртуальным дает возможность дочернему классу произвести замену
виртуального метода своим собственным. В каждом дочернем классе определен
свой метод info, который замещает соответствующий метод родительского
класса (метод порожденного класса, замещающий виртуальный метод
родительского класса, помечается директивой override). Ниже приведено
определение метода info для каждого класса.
  function TPerson.info:string;
begin
result:"'' ;
end;
function TStud.info:string;
begin
result:=fname+' rp.'+IntTostr(fgr) ;
end;
function TProf.info:string;
begin
result: =fnaine+' каф.'+fdep;
end;
В программе список людей можно представить массивом объектов класса
TPerson. list:array( Замечание ^
Здесь следует вспомнить, что объект - это указатель.



  206_________________ Delphi 3. Программирование на Object Pascal


  Объявить подобным образом список можно потому, что Object Pascal позволяет
указателю на родительский класс присвоить значение указателя на дочерний
класс. Поэтому элементами массива list могут быть как объекты класса
TStud, так и объекты класса Tprof.
  Вывод списка можно осуществить применением метода info к элементам
массива, например, так:
  st:=";
for i:=l to SZL do // SZL - размер массива-списка if listthen
st:=st+info.listShowMessage(st) ;
Во время работы программы каждый элемент массива может содержать как
объект типа TStud, так и объект типа Tprof. Концепция полиморфизма
обеспечивает применение объекту именно того метода, который соответствует
типу объекта.
  На рис. 125 приведено диалоговое окно программы, которая, используя
рассмотренные выше объявления классов трегзоп, TStud и Tprof, формирует и
выводит список студентов и преподавателей.
  Рис. 125. Диалоговое окно программы Полиморфизм
unit polimor_;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TFonnl = class(TForm) Editi: TEdit;
Edit2: TEdit;
GroupBoxl: TGroupBox;
RadioButtonI: TRadioButton;



  Введение в объектно-ориентированное программирование______________207


  Radi.oBut.ton2: TRadioButton;
Labell: TLabel;
Label2: TLabel;
Buttoni: TButton;
Button2: TButton;
procedure ButtonlClick(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations } public
{ Public declarations } end;
type
TPerson=class
fname:string;{ имя ) constructor Create(name:string);
function info:string; virtual;
end;
TStud=class(TPerson)
fgr:integer; ( номер группы }
constructor Create(name:string;gr:integer) ;
function info:string; override;
end;
TProf=class(TPerson)
fdep;string; { название кафедры }
constructor Create(name:string;dep:string) ;
function info:string; override;
end;
const
SZL=10; // размер списка var
Fonnl: TFonnl ;
List: arrayn:integer; // кол-во людей в списке
implementation
($R *.DFM} constructor TPerson.Create(name:string) ;
begin fname:=name;
end;
constructor TStud.Create(name:string;gr:integer) ;
begin
inherited create(name);



  208______________________Delphi 3. Программирование на Object Pascal


  fgr:=gr;
end;
constructor TProf.create(name:string; dep:string) ;
begin
inherited create(name) ;
fdep:=dep;
end;
function TPerson.Info:string;
begin
result:=fname;
end;
function TStud.Info:string;
begin
result:=fname+' rp.'+IntToStr(fgr) ;
end;
function TProf.Info:string;
begin
result:=fname+' каф.'+fdep;
end;
// добавить элемент в список procedure TForml.ButtonlClick(Sender:
TObject) ;
begin
if n"=SZL then begin
if Radiobuttoni.Checked
then // создадим объект TStud
ListStrToInt(Edit2.Text)) else
Listn:=n+l;
end else ShowMessage('Список заполнен!') ;
end;
procedure TFonnl.Button2Click(Sender: TObject);
var
i:integer ;
st:string;
begin
for i:=l to SZL do
if list


  Введение в объектно-ориентированное программирование 209


  ShowMessage('Список'+#13+st);
end;
end.
  Процедура TForml.Buttonlciick, которая запускается в результате щелчка на
кнопке Добавить (Buttoni), создает объект iistСтудент (RadioButtoni),
Процедура TFormi.Button2dick, которая выполняется в результате щелчка на
кнопке Список (Button2), применяя метод info к каждому объекту списка
(элементу массива), формирует строку, представляющую собой весь список.
  Классы и объекты Delphi
Для реализации интерфейса Delphi использует библиотеку классов, которая
содержит большое количество разнообразных классов, поддерживающих форму и
различные компоненты (командные кнопки, поля редактирования и т. д.).
  Во время проектирования формы приложения Delphi автоматически добавляет в
текст программы необходимые объекты. Если сразу после запуска Delphi
просмотреть содержимое окна редактора кода, то там можно обнаружить
следующие строки:
  type
TFonnl = class(TForm) private
( Private declarations } public
( Public declarations ) end;
var
Fomi: Tfonnl
Это описание класса исходной, пустой, формы приложения и объявление
объекта - формы приложения.
  Когда программист, добавляя необходимые компоненты, создает нужную форму,
Delphi формирует описание класса формы. Когда программист создает функцию
обработки события формы или ее компонента, Delphi добавляет объявление
метода в описание класса формы приложения.
  Помимо 'классов визуальных компонентов в библиотеку классов входит класс
обработки исключительных ситуаций (ошибок), класс общего управления
приложением и другие. Рассмотрение этих классов в задачу данной книги не
входит.



  ПРИМЕРЫ ПРОГРАММ

  Решение квадратного уравнения

  Этот пример демонстрирует использование одной процедуры обработки события
несколькими компонентами, а также применение функции Fioat-ToStrF для
вывода значений дробных чисел.
  Сама по себе задача решения квадратного уравнения довольно тривиальна.
Однако, если необходимо разработать действительно удобное для работы
приложение, которое будет не только вычислять корни уравнения в том
случае, если пользователь ввел правильные данные, но еще и контролировать
вводимую информацию, например, не допускать ввод неверных (не числовых)
данных, то задача разработки программы уже не выглядит столь примитивной.
  На рис. 126 изображено диалоговое окно программы решения квадратного
уравнения.
  Рис. 126. Диалоговое окно программы Решение квадратного уравнения
Для ввода коэффициентов уравнения предназначены поля Editi, Edit 2 и
Edit3. Поле метки Labell (на рисунке изображено темными прямоугольниками)
предназначено для вывода результата. Назначение кнопок Вычислить
(Buttoni), Новое (Button2) и Завершить (Buttons) очевидно. Вид формы
приложения позволяет сформулировать следующие требования к программе:
  П В поля коэффициентов уравнения допускается вводить только дробные
положительные и отрицательные числа. Ввод других символов программа должна
блокировать



  2Y2______________________Delphi 3. Программирование на Object Pascal


  О Во время ввода коэффициента уравнения при нажатии на клавишу "Enter"
курсор автоматически должен перемещаться в поле ввода следующего
коэффициента. Если клавиша "Enter" нажата во время ввода коэффициента с,
то программа должна вычислять корни уравнения
Чтобы программа удовлетворяла вышеприведенным требованиям, для каждого
поля редактирования надо написать процедуру обработки события onKeypress,
которая, в зависимости от того, какую клавишу нажал пользователь, будет
выполнять нужное действие. Например, при нажатии на "Enter" перемещать
курсор в поле ввода следующего коэффициента, а при нажатии запрещенной
клавиши - блокировать появление запрещенного символа в поле редактирования.
  Заготовка процедуры OnKeyPress для Editi, генерируемая Delphi, выглядит
следующим образом:
  procedure FonnI.EditlKeyPress(Sender:Tobject;
var Key:Char) ;
begin
end;
Заголовок процедуры FonnI.EditlKeyPress показывает, что процедура в
качестве параметра получает символьную переменную Key. Эта переменная
содержит символ, соответствующий нажатой клавише. Здесь следует обратить
внимание на то, что параметр принимается по ссылке (перед именем
переменной стоит слово var), поэтому процедура может изменить значение
переменной. Символ, соответствующий нажатой клавише, появляется в поле
редактирования после выполнения процедуры обработки события OnKeypress,
поэтому процедура обработки может заменить введенный символ или,
присвоением переменной кеу значения chr(O), запретить его появление в поле
редактирования.
  Ниже приведен текст процедуры обработки события OnKeypress в поле
редактирования Editi.
  procedure TFormI.EditlKeyPress(Sender: TObject;
var Key: Char) ;
begin
case key of
'0'.. '9', chr (8):;
',': if pos(',',Editi.Text)""0 then key:=chr(0);
'-': if length(Editi.Text)""0 then key:=chr(0);
chr(13): Edit2.SetFocus '.': begin
Mes5ageDlg('Для отделения дробной части' +'числа'+#13 +'от целой
используйте запятую.',


  Примеры программ___________________________________213

  mtlnformation,key:=Chr(0);
end else key:=Chr(0) end;
end;
Процедура TFormi.EditKeypress проверяет, какая клавиша нажата. Если нажата
цифровая или клавиша "BackSpace", то процедура просто завершает свою
работу и символ появляется в поле редактирования или стирается последний
введенный символ. Если нажата ",", то процедура проверяет, есть ли уже в
поле редактирования запятая. Если есть, то появление второй запятой
блокируется. Если нажата клавиша со знаком "минус", то минус появляется
только в том случае, если в поле редактирования нет ни одной цифры. Если
нажата "Enter", то применением метода setFocus к полю редактирования Edit
2 курсор перемещается в это поле.
  Очевидно, что процедуры обработки события OnKeypress полей редактирования
отличаются только способом обработки нажатия клавиши "Enter", в остальном
эти процедуры идентичны. Поэтому, вместо того, чтобы для каждого поля
редактирования писать свою процедуру обработки события onKeypress, можно
написать одну общую процедуру, которая, при нажатии "Enter" будет выбирать
нужное действие в зависимости от того, в каком поле произошло событие.
Получить информацию об источнике события, можно проверкой значения
параметра sender.
  Ниже приведен модуль формы приложения Решение квадратного уравнения.
  unit sqroot ;
interface
uses
SyaUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
type
TFonnl = class(TFonn) Labels: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Editi: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Labell: TLabel;
Buttoni: TButton;


  214______________________Delphi 3. Программирование на Object Pascal


  Button2: TButton;
Button3: TButton;
procedure ButtonlClick(Sender: TObject);
procedure EditKeyPress(Sender: TObject; var Key: Char);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private declarations } public
{ Public declarations ) end;

  var
Formi: TFonnl ;
implementation {$R *.DFM)
procedure SqRoot(Editl,Edit2,Edit3:tEdit;Label2:tLabel) ;
label bye;
var
a,b,c:real; // Коэффициенты уравнения d:real; // Дискриминант
xl,x2:real; // Корни уравнения begin
// Ввод исходных данных
if (Editl.Text=") or (Edit2.Text=") or (Edit3.Text=") then begin
MessageDIg('Необходимо задать все'+#13 +'коэффициенты уравнения.',
mtWarning,goto bye;
end;
a:=StrToFloat(Editl.text) ;
b:=StrToFloat(Edit2.text) ;
с:=StrToFloat(Edit3.text) ;
if a=0 then
begin
Label2.font.color:=clRed;
Label2.caption:=
'Коэффициент при второй степени' +#13+'неизвестного равен нулю!';
end



  Примеры программ ____ __ ___________________215


  else
begin // решение уравнения // Вычисление дискриминанта d:=Sqr(b)-4*a*c;
if d"0 then
begin
Label2.font.color:=clRed;
Label2.caption:=
'Дискриминант меньше нуля.' +#13+ 'Уравнение не имеет корней.' end else
begin
// Вычисление корней xl:=(b+Sqrt(d))/(2*a) ;
x2:=(-b+Sqrt(d))/(2*а) ;
// Вывод результата - значений корней Label2.font.color:=clBlack;
Label2.caption:"'Корни уравнения:'
+#13+'xl='+FloatToStrF(xl,ffGeneral,7,4)
+#13+'x2='+FloatToStrF(x2,ffGeneral,7,4) end;
end;
bye:
  end;
procedure TFormI.EditKeyPress(Sender: TObject;
var Key: Char);
var
buf:stringbegin
if Sender = Editi then
buf:=Editl.Text else if Sender = Edit2 then
buf:=Edit2.Text else buf:=Edit3.Text;
case key of
'О'.. '9', chr (8):;
',': if роз(',',buf)""0 then key:=chr(0);
'-': if length(buf)""0 then key:=chr(0);
chr(13): if Sender= Editi
then Edit2.SetFocus
else if Sender = Edit2



  216______________________Delphi 3. Программирование на Object Pascal


  then Edit3.SetFocus else begin
buttoni.SetFocus ;
sqroot(Editl,Edit2,Edit3,Labell) ;
end;
'.': begin
MessageDlg('Для отделения дробной части ' +'числа'+#13
+'от целой используйте запятую.', mtlnfonnation,key:=Chr(0);
end else key:=Chr(0) end;
end;
procedure TForml.Button2Click(Sender: TObject);
begin
Editl.text:='';
Edit2.text:='';
Edit3.text:='' ;
Labell.font.color:=clBlack;
Labell.caption:='';
Editl.SetFocus;
end;
procedure TForml.Button3Click(Sender: TObject);
begin
Fonnl. Close;
end;
procedure TForml.ButtonlClick(Sender: TObject);
begin
SqRoot(Editl,Edit2,Edit3,Labell) ;
end;
end
Процедура обработки события OnKeypress для поля Editi создается обычным
образом. Процедура Обработки События OnKeyPress ДЛЯ Edit2 И Edit3
назначается путем выбора из списка процедур, который появляется при щелчке
на знаке раскрывающегося списка (рис. 127).
  Для вывода вычисленных значений корней уравнения используется функция
FloatToStrF, которая, как и FloatToStr, преобразует дробное число в его
строковое представление. Однако, в отличие от FloatToStr, она позволяет
получать изображение числа в различных форматах.



  Примеры программ 217


  Рис. 127. Назначение процедуры обработки события путем выбора из списка
В общем виде обращение к функции выглядит так:
  s:=FioatTo3trF(Значение, Формат, Точность, КоличествоЦифр};
где s - строковое представление (изображение) числа Значение;
значение - число, изображение которого надо получить;
Формат - именованная константа, определяющая вид строки s;
точность - определяет точность представления преобразуемого числа.
Значение точность должно быть равно 7 или меньше для типа single, 15 или
меньше для типа Double, 18 или меньше для типа Extended;
Значение количествоЦифр зависит от используемого формата (см. далее).
  Константа
Формат
ffGeneral
Общий цифровой формат. Число изображается с десятичной точкой, если
количество цифр слева от точки меньше или равно заданной точности или если
число больше или равно 0,00001. В противном случае число изображается в
"научном формате" (см. ниже) и количество цифр экспоненты
FfExponent
Научный формат. Число изображается в виде d.ddd.. .Esddd, где s - знак
"плюс" или "минус"; d - десятичная цифра. Общее количество цифр числа,
включая число перед десятичной точкой, равно заданной точности. Параметр
КоличествоЦифр задает минимальное количество цифр представления экспоненты
(0..4)
ffFixed
Формат с десятичной точкой. Число преобразуется к виду: ddd. ddd. .. Если
число отрицательное, то строка, являющаяся изображением числа, начинается
знаком "минус". Перед десятичной точкой всегда находится как минимум одна
цифра. Параметр КоличествоЦифр задает количество цифр после десятичной
точки (0..18). Если количество цифр целой части больше, чем заданная
точность, то число изображается в научном формате




  218______________________Delphi 3. Программирование на Object Pascal


  (окончание)
Константа
Формат
FfNumber
Числовой формат. Числовой формат похож на формат с десятичной точкой
(ffFixed), только в изображении числа используется разделитель групп
разрядов. Например, число 45278,34 будет изображено так: 45 278,34
ffCurrency
Денежный формат. Используемые в изображении числа в денежном формате
разделитель целой и дробной частей, разделитель групп разрядов,
изображение денежной единицы определяются настройкой Windows (см. вкладку
Денежный формат свойства Язык и стандарты панели управления). Параметр
количествоЦифр задает количество цифр после десятичной точки


  Система проверки знаний

  Тестирование широко применяется для оценки уровня знаний в учебных
заведениях, при приеме на работу, для оценки квалификации персонала
учреждений, т. е. практически во всех сферах деятельности человека.
Испытуемому предлагается ряд вопросов (тест), на которые он должен
ответить. Обычно, к каждому вопросу дается несколько вариантов ответа, из
которых надо выбрать правильный. Каждому варианту ответа соответствует
некоторая оценка. Суммированием оценок за ответы получается общий балл, на
основе которого делается вывод об уровне подготовленности испытуемого.
  В этом разделе рассматривается программа, позволяющая автоматизировать
процесс тестирования.
  Требования к программе
В результате анализа различных тестов были сформулированы следующие
требования к программе:
  1. Программа должна обеспечить работу с тестом произвольной длины, т. е.
без ограничений на количество вопросов в тесте.
  2. Каждый вопрос может сопровождаться иллюстрацией.
  3. При каждом вопросе может быть до четырех возможных вариантов ответа со
своей балльной оценкой.
  4. Результат тестирования должен быть отнесен к одному из четырех уровней.
Например, "отлично", "хорошо", "удовлетворительно" или "плохо".
  5. Вопросы теста должны находиться в файле, созданном при помощи
доступного редактора текста.
  6. Программа должна быть инвариантна к различным тестам, т. е. изменения в
тесте не должны вести за собой требований изменения программы.


  Примеры программ_____________________________________219


  7. Программа не должна обеспечивать возврат к предыдущему вопросу. Если
вопрос предложен, то на него должен быть дан ответ.
  На рис. 128 приведен пример диалогового окна программы тестирования во
время ее работы.
  Рис. 128. Диалоговое окно программы тестирования
Файл теста
Тест представляет собой последовательность вопросов, на которые испытуемый
должен ответить путем выбора правильного ответа из нескольких предложенных
вариантов.
  Файл теста состоит из трех разделов:
  D Раздел заголовка D Раздел оценок D Раздел вопросов
Начинается файл теста, как правило, заголовком, который содержит общую
информацию о тесте, например, о его назначении. Заголовок может состоять
из нескольких строк. Признаком конца заголовка является точка, стоящая в
начале строки.
  Вот пример заголовка файла вопросов:
  Сейчас Вам будут предложены вопросы о знаменитых памятниках и
архитектурных сооружениях Санкт-Петербурга. Вы должны из предложенных
нескольких вариантов ответа выбрать правильный.
  За заголовком следует раздел оценок. В нем перечислены названия оценочных
уровней и количество баллов, необходимое для достижения этого уровня.
Название уровня должно располагаться в одной строке. Вот пример раздела
оценок:

  220 Delphi 3. Программирование на Object Pascal
Отлично

                                100

  Хорошо

                                85

  Удовлетворительно

                                60

  Плохо

                                50

  За разделом оценок следует раздел вопросов теста. Каждый вопрос начинается
текстом вопроса, за ним может следовать имя файла иллюстрации, которое
должно располагаться на отдельной строке и начинаться с символа "обратная
косая черта" (\). Имя файла иллюстрации является признаком конца текста
вопроса. Если к вопросу нет иллюстрации, то вместо имени файла ставится
точка. После вопроса следуют альтернативные ответы. За текстом
альтернативного ответа, который может занимать несколько строк, на
следующей строке, располагается оценка (количество баллов) за его выбор.
Если альтернативный ответ не является последним для текущего ответа, то
перед оценкой ставится запятая, если последний, то точка.
  Вот пример вопроса:
  Какую формулу следует записать в ячеку В5, чтобы
вычислить сумму выплаты?
  \tabl.brnp
=сумма(В2,ВЗВ4)
,0
=сумма(Ь2:Ь4)
,2
=В2+ВЗ+Ь4
.1
В приведенном вопросе второй и третий ответы помечены как правильные
(оценка за их выбор не равна нулю). При этом видно, что выбор второго
альтернативного ответа дает более весомый вклад в общую сумму баллов.
  Ниже в качестве примера приведен листинг файла вопросов теста контроля
знания памятников и архитектурных сооружений Санкт-Петербурга.
  Сейчас Вам будут предложены вопросы о знаменитых памятниках и
архитектурных сооружениях Санкт-Петербурга. Вы должны из предложенных
нескольких вариантов ответа выбрать правильный.
  Вы прекрасно знаете историю Санкт-Петербурга!
  10
Вы много знаете о Санкт-Петербурге, но на некоторые вопросы ответили не
верно.
  7


  Примеры программ____________________________________221


  Вы, наверное, только начали знакомиться с историей Санкт-Петербурга?
  6
Вы, наверное, только начали знакомиться с историей Санкт-Петербурга?
  5
Архитектор Исаакиевского собора:
  Usaak.fcmp Доменико Трезини ,0
Огюст Монферран ,1
Карл Росси .0
Александровская колона воздвигнута в 1836 году по проекту Огюста
Монферрана как памятник, посвященный:
  \aleks.bmp
деяниям императора Александра I. ,1
подвигу народа в Отечественной войне 1812 года. .0
Архитектор Зимнего дворца \henn.bnip
Франческо Бартоломео ,0
Огюст Монферран ,0
Карл Росси .0
Михайловский (Инженерный) замок - жемчужина архитектуры Петербурга
построен по проекту русского зодчего
Воронихина Андрея Никифоровича
: '1
Старова Ивана Егоровича
.0
Баженова Василия Ивановича  .0
Остров, на котором находится Ботанический сад, основанный императором ;
Петром I, называется:
  t \bot.bmp I Заячий
I 'ш I Медицинский

                                I 'ш

  Аптекарский
.1



  222______________________Delphi 3. Программирование на Object Pascal


  Невский проспект получил свое название
по имени реки, на которой стоит Санкт-Петербург.
  ,0
по имени близко расположенного монастыря Александро-Невской лавры.
  ,1
в память о знаменитом полководце - Александре Ярославовиче (Невском).
  .0
Создатель конной группы Аничкова моста
\faIkone.bmp
Петр Клодт
,1
Фальконе
.0
Скульптура знаменитого памятника Петру I выполнена
Фальконе ,1
Клодтом .0
( Замечание ^
Файл теста может быть подготовлен при помощи редактора Notepad или
Microsoft Word. В случае использования Microsoft Word, при сохранении
текста, следует указать, что надо сохранить только текст. Для этого из
списка Тип файла следует выбрать строку Только текст (*.txt).


  Форма приложения


  На рис. 129 приведен вид стартовой формы Fnnl во время разработки
программы. Эта форма будет использоваться как для вывода вопросов теста и
ввода ответов пользователя, так и для вывода начальной информации о тесте
и результатов тестирования.
  Поле метки Label 5 предназначено для вывода текста вопроса, начальной
информации о тесте и результатов тестирования.
  Поля Labeli, Label 2, Labels и Label 4 созданы для вывода текста альтерна-
ТИВНЫХ Ответов, а радиокнопки RadioButtonI, RadioButton2, RadioButton3
и RadioButton4 - для выбора ответа.
  Командная кнопка Buttoni предназначена для подтверждения выбора
альтернативного ответа и перехода к следующему вопросу теста.
  Следует обратить внимание на то, что под панелью Pane ll находится
недоступная во время работы программы радиокнопка RadioButton5, о
назначении которой будет сказано немного позже.



  Примеры программ 223


  Рис. 129. Форма приложения Test
Создается форма обычным образом. Порядок добавления к форме большинства
элементов не имеет значения. Однако перед добавлением к форме кнопки
Buttoni и панели panel! следует создать RadioButton5. А элементы
Panell И Buttoni Надо поместить Поверх RadioButtonS.
  Ниже, в таблицах, приведены значения свойств формы и ее компонентов.
Свойства стартовой формы
Свойство
Значение
Пояснение
Border-Icons. biSystemMenu
True
Есть кнопка системного меню
Borderlcons.biMinimize
False
Нет кнопки "Свернуть окно"
Borderlcons.biMaximize
False
Нет кнопки "Развернуть окно"
BorderStyle
bsSingle
Тонкая граница окна, нельзя изменить размер окна
Caption




  Color
clWhite


  Font. Name
Arial Cyr


  Height

                                362



  Left

                                40



  Name
Fonnl


  Top

                                70



  Width

                                562







  224 Delphi 3. Программирование на Object Pascal


  Следует обратить внимание на то, что хотя для свойств
BorderIcons.biMinimize И Borderlcons.biMaximize задано значение False,
т. е. форма не должна иметь кнопок минимизации и разворачивания окна, эти
кнопки отображены в форме. Реальное воздействие значения этих свойств на
вид окна проявляется только во время работы программы. Значение свойства
BorderStyle также проявляет себя только во время работы программы.
  Свойства полей меток


  Lab"l1
Lab"l2
Labels
Label4
Labels
AutoSize
True
True
True
True
True
Caption
Labell
Label2
Label3
Label4
Label5
Left

                                32

  32

                                32

  32

                                32

  Name
Labell
Label2
Label3
Label4
Label 5
Top

                                64

  96

                                128

  160

                                8

  Wordwrap True True True True True

  Свойства радиокнопок


  RadioButtonI
RadloButton2
RadloButton3
RadioButton4
RadioButtonS
Caption










  Left

                                8

  8

                                8

  8

                                8

  Name
RadioButtonI
RadioButton2
RadioButton3
RadioButton4
RadioButton5
Top

                                64

  96

                                128

  160

                                300


  Свойства командной кнопки But ton l Свойства панели pan ell

  Caption
Ok
Height

                                28

  Left

                                13

  Name
Buttoni
Top

                                273

  Width

                                82




  Align
alBottom
Caption


  Name
Panel-)
Height

                                46





  Примеры программ 225


  Вывод иллюстрации
Для вывода иллюстрации в форму добавлен компонент image, значок которого
(рис. 130) находится на дополнительной (Additional) странице палитры
компонентов.
  Рис. 130. Значок
компонента Image
Ниже, в таблице, приведены свойства компонента image.
  Свойство
Комментарий
Name
Имя компонента
Picture
Свойство, являющееся объектом типа TBitmap, определяющее выводимую картинку
Left
Расстояние от левого края формы до левой границы области картинки
Top
Расстояние от верхней границы формы до верхней границы области картинки
Height
Высота картинки
Width
Ширина картинки
AutoSize 
Признак автоматического изменения высоты и ширины области вывода картинки
в зависимости от реального размера картинки. Если значение AutoSize равно
TRUE, то при установке значения свойства Picture автоматически меняется
размер области так, чтобы была видна вся картинка. Если размер картинки
превышает размер области и значение AutoSize равно FALSE, то отображается
только часть картинки
Stretch
Признак автоматического сжатия или растяжения картинки таким образом,
чтобы она была видна полностью в области с заданными свойствами Width и
Height размерами

  Задать отображаемую в области image картинку можно во время создания формы
или во время работы программы. Во время создания формы картинка задается
установкой значения свойства picture. Во время работы программы -
применением метода LoadFromFile. Например, для разрабатываемого приложения
инструкция вывода иллюстрации, находящейся в файле isaak-bmp (изображение
Исаакиевского собора), может быть такой:
  Image!.Picture.LoadFromFile('isaak.bmp') ;
Очевидно, что размер области формы, которая может использоваться для
вывода иллюстрации, зависит от длины (количества слов) вопроса, длины и



  226 Delphi 3. Программирование на Object Pascal


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

  Рис. 131. Вычисление размера области, доступной для вывода иллюстрации
Затем, если реальный размер иллюстрации превышает размер области, в
которую иллюстрация должна быть выведена, вычислить коэффициент
масштабирования и установить максимально возможные, пропорциональные
ширине и высоте иллюстрации, значения свойств width и Height области
вывода иллюстрации.
  Реальные размеры загруженной в imagel иллюстрации можно получить из
СВОЙСТВ Imagel. Picture. Bitmap. Width И Imagel. Picture .Bitmap. Height.
  Открытие файла теста
Передать программе имя файла теста можно настройкой свойств ярлычка,
изображающего программу на рабочем столе или в одной из папок. Например,
если ярлычок программы тестирования называется проверка знаний, то для
настройки программы тестирования, которая находится в файле test.exe, на
работу с файлом теста peterb.txt, в поле Файл диалогового окна Свойства:
Проверка знании после имени файла программы надо дописать имя файла теста-
peterb.txt, заключив его в двойные кавычки (рис.132).
  Замечание
Текст, находящийся в поле Файл вкладки Ярлык диалогового окна Свойства,
называется командной строкой.



  Примеры программ_____________________________________227


  Рис. 132. Диалоговое окно Свойства: Проверка знаний
Программа может получить параметр из командной строки, используя значение
глобальной переменной paramcount (число параметров) и функцию paramstr(n),
возвращающую параметр командной строки с указанным, равным п, номером. Для
приведенного выше примера командной строки запуска программы тестирования
значение paramcount равно i, a paramstr(i) - peterb.txt.
  Ниже приведен фрагмент программы, обеспечивающий прием параметра из
командной строки.
  if ParamCount=0 then begin
ShowMessage('Ошибка! Не задан файл вопросов теста.');
goto bye; // аварийное завершение программы end;
FileName:=ParamStr(l); // имя файла из командной строки
Рис. 133. Диалоговое окно Run parameters



  228______________________Delphi 3. Программирование на Object Pascal


  При запуске программы, использующей параметры командной строки, из среды
программирования Delphi строку-параметр следует записать в поле Ron
parameters (параметры запуска) диалогового окна Ron parameters (рис. 133),
которое появляется при выборе команды Parameters из меню Run.
  Текст программы
После создания формы в окно редактора кода следует поместить описание
глобальных переменных программы и процедур общего назначения (см. текст,
помещенный ниже). Затем можно приступить к созданию процедур обработки
событий. В данной программе их три: обработки события OnActivate для
стартовой формы, обработки события onciick для командной кнопки Buttoni, и
процедура обработки события onciick - одна, общая для радиокнопок выбора
ответа. Ниже приведен полный текст программы.
  unit testl_;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls, ExtCtrls;
const
N_LEV=4; ( четыре уровня оценки ) N ANS=4; ( четыре варианта ответов } type
TFormI = class(TForm)
// альтернативные ответы
Labell: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
// вопрос
Label5: TLabel;
// радиокнопки выбора ответа
RadioButtonI: TRadioButton;
RadioButton2: TRadioButton;
RadioButton3: TRadioButton;
RadioButton4: TRadioButton;
RadioButtonS: TRadioButton;
Buttoni: TButton;
Panell: TPanel;
Imagel: TImage;
procedure FonnActivate(Sender: TObject);

  Примеры программ
procedure ButtonlClick(Sender: TObject);
procedure RadioButtonClick(Sender: TObject);
private
{ Private declarations } public
( Public declarations ) end;
var
Formi: TFonnl; // форма f:TextFile;
fn:string; { имя файла вопросов )
level:arraymes:arrayscore:arraysumma:integer; ( набрано очков)
vopros:integer; ( номер текущего вопроса )
n_otv:integer; ( число вариантов ответа }
otv:integer; { номер выбранного ответа )
implementation
( вывод начальной информации о тесте } procedure infofvar
f:TextFile;l:TLabei);
var
s,buf:string;
begin
buf:='';
repeat
readln(f,s) ;
if sthen buf:=buf+s+' ';
until s1.caption:=buf ;
end;
( прочитать информацию об оценках за тест } Procedure GetLevel(var
f:TextFile);
var
i:integer ;
buf:string;
begin ( заполняем значения глобальных массивов ) i:=l;
repeat
readln(f,buf);
if buf


  230______________________Delphi 3. Программирование на Object Pascal


  mesreadin(f,leveli:"i+l;
end;
until bufend;
// масштабирование иллюстрации Procedure ScaleImage(Imagel:TImage) ;
var
w,h:integer; // максимально допустимые размеры картинки
scaleX:real; // коэф. масштабирования по Х
scaleY.'real; // коэф. масштабирования по Y
scale:real; // общий коэф. масштабирования
begin
// вычислить максимально допустимые размеры картинки w: =Fonnl.
ClientWidth-10 ;
h:=Fonnl.ClientHeight
  - Fonnl.Panell.Height -5
  - Forml.Label5.Top
  - Fonnl.Label5.Height - 5;
if Formi.Label 1.Caption о ''
then h:=h-Fonnl.Labe11.Height-5;
if Forml.Label2.Caption о ''
then h:=h-Fonnl.Label2.Height-5;
if Fonnl.Label3.Caption "" ''
then h:=h-Fonnl.Label3.Height-5;
if Fonnl.Label4.Caption "" ''
then h:=h-Fonnl.Label4.Height-5;
// определить масштаб if w"Imagel.Picture.Bitmap.Width then scaleX:=l else
scaleX:=w/Imagel.Picture.Bitmap.Width;
if h"Imagel. Picture. Bitmap. Height then scaleY:=l else
scaleY:=h/Imagel.Picture.Bitmap.Height;
if ScaleY"ScaleX
then scale:=scaleY else scale:=scaleX;
// здесь масштаб определен
Imagel.Top:=Forml.Label5.Top+Fonnl.Label5.Height+5 ;
Imagel.Width:=Round(Imagel.Picture.Bitmap.Width*scale) ;
Iinagel.Height:=Round(Imagel.Picture.Bitmap.Height*scale) ;
end;



  Примеры программ___________________________________23?


  // вывод вопроса на экран Procedure VoprosToScr(var
f:TextFiie;fnn:TFonnl;var vopros:integer);
var i:integer;
code:integer;
s,buf:string;
ifn:string; // файл иллюстрации begin
vopros:=vopros+l ;
str(vopros:3,s);
fnn.caption:='Вопрос' + s;
(Выведем текст вопроса } buf:=";
repeat
readln(f,s) ;
if (suntil (sfrm.Labels.caption:=buf;
if sthen Formi.Imagel.Tag:=0 else // к вопросу есть иллюстрация begin
Formi.Imagel.Tag:=1 ;
ifn:=copy(s,2,length(s)) ;
try
Formi.Imagel.Picture.LoadFromFile(ifn);
except
on E:EFOpenError do frm.tag:=0;
end; { try ) end;
// читаем варианты ответов i:=l;
repeat
buf:=";
repeat // читаем текст варианта ответа readln(f,s);
if (suntil (s// прочитан альтернативный ответ val(scase i of



  232______________________Delphi 3. Программирование на Object Pascal


  1: frm.Labell.caption:=buf;
2: f rm.Label2.caption:=buf;
3: frm. Label3.caption:=buf;
4: frm.Label4.caption:=buf;
end;
i:=i+l;
until s// здесь прочитана иллюстрация и альтернативные ответы // текст
вопроса уже выведен
if fnn.Tag =1 // есть иллюстрация к вопросу then begin
Scalelmage(Fonnl.Imagel);
Formi.Imagel.Visible:=TRUE;
end;
// вывод альтернативных ответов if Forml.Labell.Caption "" '' then begin
if Formi.Imagel.Tag =1
then frm.Labell.top:=frm.Imagel.Top+frm.Imagel.Height+5 else
frm.Labell.top:=frm.Label5.Top+frm.Label5.Height+5;
frm.RadioButton!.top:=frm.Labell.top;
frm.Labell.visible:=TRUE;
frm.RadioButtonl.visible:=TRUE;
end;
if Fonnl.Label2.Caption о '' then begin
frm.Label2.top:=frm.Labell.top+ frm.Labell.height+5;
frm.RadioButton2.top:=frm.Label2.top;
frm.Label2.visible:=TRUE;
frm.RadioButton2.visible:=TRUE;
end;
if Formi.Label3.Caption о '' then begin
frm.Label3.top:=frm.Label2.top+ frm.Label2.height+5 ;
frm.RadioButton3.top:=frm.Label3.top ;
frm.Label3.visible:=TRUE;
frm.RadioButton3.visible:=TRUE;
end;
if Fonnl.Label4.Caption о '' then begin
frm.Label4.top:=fnn.Label3.top+ frm.Label3.height+5;
frm.RadioButton4.top:=frm.Label4.top;
frm.Label4.visible:=TRUE;



  Примеры программ_____________________________________233


  frm.RadioButton4.visible:=TRUE;
end;
end;
Procedure ResetForm(frm:TForml) ;
begin // сделать невидимыми все метки и радиокнопки
fnn.Labell.Visible:=FALSE;
frm.Labell.caption:='';
frm.Labell.width:=frm.ClientWidth-frm.Labell.left-5;
frm.RadioButtonl.Visible:=FALSE;
frm.Label2.Visible:"FALSE;
frm.Label2.caption:"'' ;
frm.Label2.width:=frm.ClientWidth-fnn.Label2.1eft-5;
frm.RadioButton2.Visible:=FALSE;
frm.Label3.Visible:-FALSE ;
frm.Label3.caption:='' ;
frm. Label3.width:=frm.ClientWidth-frm.Label3.left-5;
frm.RadioButton3.Visible:=FALSE;
frm.Label4.Visible:"FALSE;
frm.Label4.caption:"'' ;
f rm.Label4.width:=frm.ClientWidth-frm.Label4.1eft-5;
frm.RadioButton4.Visible:=FALSE;
frm.Label5.width:=frm.ClientWidth-frm.Label5.left-5;
f nn.Imagel.Visible:"FALSE;
end;
// определение достигнутого уровня procedure
Itog(sunroa:integer;frm:TFormI) ;
va'r i:integer;
buf:string;
begin buf:=";
str (surnma:5,buf) ;
buf:='Результаты тестирования'+chr(13) +'Всего баллов: '+buf;
i:=l;
while (summa " levelbuf:=buf+chr(13)+mesfrm. Label5.caption:=buf;
end;



  234______________________Delphi 3. Программирование на Object Pascal


  ($R *.DEM)
procedure TFonnl.FonnActivate(Sender: TObj ect) ;
begin
ResetFom(Formi) ;
if ParamCount = 0 then begin
Label5.font.color:=clRed;
Label5.caption:= 'He задан файл вопросов теста.' ;
Buttonl.caption:"'Ok';
Buttoni.tag:=2 ;
Buttoni.Enabled:=TRUE end else begin
fn:=ParamStr(l) ;
AssignFile(f,fn) ;
($1-) reset(f) ;
(I+) if IOResult=0 then begin
Info(f,Label5); // прочитать и вывести информацию о тесте GetLevel(f);
// прочитать информацию об уровнях оценок end;
end;
end;
procedure TFonnl.ButtonlClick(Sender: TObject) ;
begin
case Buttoni.tag of 0: begin
Buttoni.caption:='Дальше' ;
Buttoni.tag:=1;
RadioButtonS.Checked:=TRUE ;
( вывод первого вопроса ) Buttoni.Enabled:=False ;
ResetForm(Formi) ;
VoprosToScr(f,Fonnl,vopros) end;
1: begin ( вывод остальных вопросов }
summa:=summa+scoreRadioButton5.Checked:=TRUE;
Buttoni.Enabled:=False ;
ResetForm(Formi) ;
if not eof(f)



  Примеры программ 235


  then VoprosToScr(f,Forml,vopros) else
begin
suitima:=suinnia+score closefile(f) ;
Buttoni.caption: =' Ok' ;
Fonnl.caption:='Результат';
Buttoni.tag:=2;
Buttoni.Enabled:=TRUE ;
Itog(summa,Fonnl) ;
end;
end;

  2: begin ( завершение работы } Fo mil. close;
end;
end; ( case } end;
procedure TFormI.RadioButtonClick(Sender: TObject);
begin
if sender = RadioButtonI then otv:=l
else if sender = RadioButtonI then otv:=2
else if sender = RadioButton3 then otv:=3 else otv:=4;
Buttoni.enabled:=TRUE;
end;
end.

  После запуска программы и вывода на экран стартовой формы происходит
событие onActivate. Процедура FormActivate сначала вызывает процедуру
ResetForm, которая, присваивая значение False характеристикам visible,
делает невидимыми поля вывода альтернативных ответов и радиокнопки. Точно
так же делается невидимой область иллюстрации. Кроме того, процедура
устанавливает максимально возможную ширину полей меток альтернативных
ответов.
  После очистки формы проверяется, указан ли при запуске программы параметр
- имя тестового файла. Если параметр не указан (значение paramCount в этом
случае равно нулю), то присвоением значения характеристике Caption метки
Labels выводится сообщение Не задан файл вопросов теста и
характеристике tag кнопки Buttoni присваивается значение 2.


  236______________________Delphi 3. Программирование на Object Pascal


  Если параметр задан, то выполняются действия по открытию файла теста.
Программа тестирования получает имя файла теста как результат функции
paramStr(l). Реализация программы предполагает, что если имя файла теста
задано без указания пути доступа к нему, то файл теста и файлы с
иллюстрациями находятся в том каталоге, что и программа тестирования. Если
путь доступа указан, то файлы с иллюстрациями должны находиться в том же
каталоге, что и файл с тестом. Такой подход позволяет сгруппировать все
файлы одного теста в одном каталоге.
  Открывается файл теста обычным образом. Сначала обращением к процедуре
AssignFile имя файла связывается с файловой переменной. Затем вызывается
инструкция открытия файла для чтения.
  После успешного открытия файла вызывается процедура info, которая
считывает из файла информацию о тесте и присваиванием прочитанного текста
характеристике caption поля метки Label5 выводит ее.
  Затем вызывается процедура GetLevel, которая считывает из файла теста
информацию об уровнях оценки. Она заполняет массивы level и тез.
  После вывода информационного сообщения, программа ожидает щелчка
пользователя на кнопке Ok (Buttoni).
  Командная кнопка Buttoni используется для аварийного завершения работы
приложения (в случае, если не задано имя файла теста), начала тестирования
(после прочтения информационного сообщения), перехода к следующему вопросу
(после выбора одного из ответов) и завершения работы программы (после
прочтения результатов тестирования).
  Характеристика tag кнопки Buttoni используется для идентификации текущего
состояния формы и выбора действия при щелчке на кнопке Buttoni.
Предопределенное значение tag - ноль. После успешного вывода информации о
тесте значение tag равно нулю, поэтому после щелчка на кнопке Buttoni
выполняется та часть программы, которая обеспечивает вывод первого
вопроса, замену текста "Ok" кнопки на текст "Дальше", делает выбранным
переключатель RadioButtonS, который закрыт панелью и не виден
пользователю. Кроме того, установкой характеристики Enabled кнопки
But-tc.nl в значение False, кнопка Buttoni делается недоступной, тем самым
блокируется переход к следующему вопросу до тех пор, пока не выбран
альтернативный ответ. Записью 1 в Buttoni. Tag производится подготовка к
обработке следующего щелчка на кнопке Buttoni.
  После выбора ответа и щелчка на кнопке Дальше (Buttoni), в этом случае
значение Buttoni. Tag равно единице, к набранной сумме баллов добавляется
количество баллов за выбранный ответ. Затем, если не достигнут конец
файла, вызывается процедура вывода очередного ответа. Если достигнут конец
файла, то сначала закрывается файл вопросов, изменяется текст на кнопке
Buttoni и значение Buttoni. Tag, затем посредством процедуры itog
выводятся результаты тестирования.



  Примеры программ_____________________________________237


  Если значение Buttonl.Tag равно двум, то применением метода close к форме
Formi закрывается окно программы, в результате чего программа завершает
работу.
  Вывод вопроса и альтернативных ответов выполняет процедура
voprosToScr. Сначала процедура увеличивает счетчик вопросов vopros и
присвоением значения характеристике Caption формы выводит номер текущего
вопроса в заголовок окна. Затем процедура читает строки из файла вопросов
до тех пор, пока первым символом очередной прочитанной строки не будет
точка или обратная наклонная черта. После вывода текста вопроса делается
проверка: какой символ в качестве признака конца вопроса. Если наклонная
черта, что свидетельствует о том, что к вопросу есть иллюстрация, то в
Forml.imagel.Tag записывается единица и затем из прочитанной строки
выделяется имя файла с иллюстрацией. Загрузка иллюстрации осуществляется
применением метода LoadFromFile к свойству imagel. picture. Однако после
загрузки иллюстрация на экране не появляется, так как значение imagel.
visible равно False. После считывания иллюстрации процедура считывает
вопросы. После обработки последнего вопроса, если была загружена
иллюстрация, вызовом процедуры Scaieimaga вычисляется и устанавливается
размер области иллюстрации. После этого, установкой значения imagel. тор
задается положение верхней границы области иллюстрации и установкой
imagel. visible в True иллюстрация делается видимой. Так как количество
символов в тексте вопроса и число альтернативных ответов от вопроса к
вопросу может меняться и, следовательно, на экране они могут занимать
разное количество строк, то каждый раз перед выводом текста очередного
ответа устанавливается значение свойства тор, как расстояние от нижней
границы предыдущего альтернативного ответа. Для поля вывода первого
альтернативного ответа (Labeil) значение тор вычисляется от нижней границы
поля вопроса (Labelb) или, если к вопросу есть иллюстрация, от нижней
границы поля иллюстрации (imagel).
  Выбор ответа пользователь осуществляет щелчком на одной из радиокнопок.
После вывода вопроса ни один из переключателей, соответствующии
альтернативному ответу, не является выбранным. Выбран переключателе
RadioButtonS, который находится за панелью panel l и, поэтому, не виден.
ДЛЯ обработки события OnClick на RadioButtonI, RadioButtor.C.
  RadioButtonS и RadioButton4 в программе используется общая процедура -
TForml.RadioButtonClick. Процедура получает в качестве параметра объект,
на котором произошло событие. Сравнивая полученное значение с именами
объектов-кнопок выбора, она присваивает значение глобальной переменной
otv, которая используется процедурой VoprosToScr для увеличения набранной
суммы баллов. Кроме того, процедура делает доступной кнопку перехода к
следующему вопросу (Buttoni), которая после вывода очередного вопроса
недоступна.



  238______________________Delphi 3. Программирование на Object Pascal


  Процедура itog, сравнивая набранную сумму баллов зшшп со значением
элементов массива level, определяет, какого уровня достиг испытуемый и
присвоением значения свойству Label5. Caption выводит соответствующее
сообщение.
  Усовершенствование программы
Очевидно, что приведенный выше текст программы был бы намного проще и
изящней, если бы поля вывода альтернативных ответов и радиокнопки выбора
ответов были бы объединены в массивы. Тогда программа могл^ бы обращаться
к полям и радиокнопкам не по имени, а по индексу.
  Delphi позволяет объединить компоненты в массив, однако создаваться такие
компоненты должны не во время создания формы приложения, а динамически, во
время работы программы.
  На рис. 134 приведен вид формы усовершенствованного приложения.
  Рис. 134. Форма приложения Тест,версия 2
На форме отсутствуют радиокнопки выбора ответов и поля меток для вывода
ответов, они будут созданы во время работы приложения.
  Объявление массива компонентов ничем не отличается от объявления обычного
массива - указывается имя массива, диапазон изменения индекса и тип
компонентов. Ниже приведено объявление массивов компонентов формы
разрабатываемой программы.
  answer: arrayЕсли компонент должен реагировать на события, то программист
должен написать процедуру обработки события и поместить ее описание в
объявление типа формы приложения.



  Примеры программ_____________________________________239


  Например, объявление процедуры обработки события ondick для радиокнопок
разрабатываемого приложения выглядит так:
  procedure SeiectorClick(Sender: TObject);
С Замечание j
При создании процедуры обработки события для обычного компонента,
заготовка и описание процедуры создавались автоматически. Программист
должен был написать только инструкции процедуры. В случае создания
процедуры для динамически создаваемого компонента, программист должен сам
поместить описание процедуры в объявление типа формы приложения и
полностью написать текст процедуры обработки события.
  Однако, для того чтобы компонент появился в форме, одного объявления
недостаточно. Компонент - это объект Delphi, и его объявление - это только
указатель на область памяти, который, без наличия объекта ни на что не
указывает. Создается компонент применением метода create к указателю на
компонент, в нашем случае, к элементу массива. Например, инструкции
answeranswerсоздают компонент и помещают его в форму приложения.
  После создания компонента программа должна выполнить его настройку, т. е.
ту работу, которую во время создания формы приложения, используя Object
Inspector, выполняет программист. Под настройкой понимается присваивание
начальных значений тем свойствам компонента, предопределенные значения
которых не отвечают предъявляемым требованиям.
  Здесь же следует определить необходимые процедуры обработки событий.
Определяется процедура обработки события путем присвоения свойству, имя
которого совпадает с именем события, для которого надо задать процедуру
обработки, имени процедуры обработки. Например, инструкция
selectorзадает процедуру обработки события Ondick для компонента
selectorunit test2_;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls, ExtCtrls;
type
TFonnl = class(TForm)



  240______________________Delphi 3. Программирование на Object Pascal


  Labels: TLabel; // поле вывода вопроса
Image 1: Т Image; // область вывода иллюстрации
Pane 11: Т Panel;
Buttoni: TButton; // кнопка "Ok", "Дальше", "Завершить"
procedure FormActivate(Sender: TObject);
procedure FonnCreate(Sender: TObject);
procedure ButtonlClick(Sender: TObject);
procedure SelectorClick(Sender: TObject);
private
( Private declarations } public
( Public declarations ) end;
const
N_ANSWERS=4; // четыре варианта ответов ) N LEVEL=4; // четыре уровня
оценки }
var
Formi: TFonnl; // форма
answer: arrayf:TextFile;
fn:string; // имя файла вопросов
level:arraymes:arrayscore:arraysumma:integer; ( набрано очков)
vopros:integer; ( номер текущего вопроса }
n otv:integer; { число вариантов ответа }
otv:integer; ( номер выбранного ответа }
implementation
( установка формы в исходное состояние } Procedure ResetFonn(frm:TFoml) ;
var i:integer;
begin
for i:=l to N_ANSWERS do begin
answeranswerSelectorend;



  Примеры программ___________________________________241


  frm.Labels.width:=fm.ClientWidth-frm.Label5.1eft-5;
frm.Imagel.Visible:=False;
end;
( Определение достигнутого уровня } procedure
Itog(summa:integer;frm:TFormI) ;
var i:integer;
buf .-strings-begin buf:='';
str (sunima: 5, buf) ;
buf:='Результаты тестирования'+chr(13) +'Всего баллов: '+buf;
i:=l;
while (sunima " level buf:=buf+chr(13)+mesfrm.Labels.caption:"butt-end;
procedure TForml.FonnCreate(Sender: TObject);
var
i: integer;
begin
// Создадим пять меток для вывода вопроса и альтернативных ответов
for i:=l to N_ftNSWERS do
begin
answeransweransweranswerend;
// Создадим радиокнопки для выбора ответа
for i:=l to N_ANSWERS+1 do
begin
selectorselectorselectorselectorselectorselectorselectorselectorend;



  242 _______________Delphi 3. Программирование на Object Pascal


  ResetForm(Fonnl);
end;
{ Вывод начальной информации о тесте } procedure info(var
f:TextFile;l:TLabel);
var
s,buf:string;
begin
buf:=";
repeat
readln(f,s) ;
if sthen buf:=buf+s+' ';
until sFormi.Label5.caption:=buf;
end;
{ Прочитать информацию об оценках за тест } Procedure GetLevel(var
f:TextFile);
var
i:integer;
buf:strings-begin ( заполняем значения глобальных массивов } i: =1 ;
repeat
readln(f,buf) ;
if bufreadin(f,leveli: =i+l ;
end;
until bufend;
// Масштабирование иллюстрации Procedure ScalePicture;
var
w,h:integer; // максимально допустимые размеры картинки
scaleX:real; // коэф. масштабирования по Х
scaleY:real; // коэф. масштабирования по Y
scale:real; // общий коэф. масштабирования
i:integer;
begin
// Вычислить максимально допустимые размеры картинки
w:=Forml.ClientWidth-Formi.Label5.Left ;
h:=Forml.ClientHeight
  - Formi.Panel 1.Height -5



  Примеры программ_____________________________________243


  - Forml.Label5.Top
  - Forml.Label5.Height - 5;
for i:=l to N_ANSWERS do
if answerthen h:=h-answer// Определена максимально допустимая величина
иллюстрации
// Определить масштаб if w"Foml. Imagel. Picture. Width
then scaleX:=l
else scaleX:=w/Forml.Imagel.Picture.Width;
if h"Forml.Imagel.Picture.Height
then scaleY:=l
else scaleY:=h/Forml.Imagel.Picture.Height;
if ScaleYOcaleX
then scale:=scaleY
else scale:=scaleX;
// Масштаб определен
Fonnl.Imagel.Top:=Fonnl.Labels.Top+Fonnl.Labels.Height+S;
Fonnl. Imagel. Left: =Foml. Labels. Left ;
Formi.Imagel.Width:=Round(Fonnl.Imagel.Picture.Width*scale);
Fonnl.Imagel.Height:=Round(Fonnl.Imagel.Picture.Height*scale);
Fonnl.Labels.Visible:=TRUE;
end;
// Вывод вопроса на экран Procedure VoprosToScr(var
f:TextFile;fnn:TForml;var vopros:integer);
var i:integer;
code:integer;
s,buf:string;
ifn:string; // файл иллюстрации begin
vopros:=vopros+l ;
str(vopros:3,s) ;
fnn.caption:"'Вопрос' + s;
(Выведем текст вопроса } buf:=";
repeat
readln(f,s) ;
if (suntil (sfnn.Labels.caption:"butt-if sthen // к вопросу есть
иллюстрация



  244 _________________Delphi 3. Программирование на Object Pascal


  begin
frm. Iinagel. Tag: =1 ;
ifn:=copy(s,2,length(s)) ;
try
fnn.Imagel.Picture.LoadFromFile(ifn) ;
except
on E:EFOpenError do frm.tag:=0;
end { try } end else frm.Imagel.Tag:=0;
// Читаем варианты ответов for i:=l to N_ANSWERS do begin
answeranswerend;
i:=l;
repeat
buf:='';
repeat // Читаем текст варианта ответа readlntf,s) ;
if .(suntil (s// Прочитан.альтернативный ответ
val(sansweri:=i+l;
until s// Прочитана иллюстрация и альтернативные ответы
if Formi. Imagel.Tag =1 // есть иллюстрация к вопросу ? then begin
ScalePicture;
Fonnl.Imagel.Visible:=TRUE ;
end;
// Вывод альтернативных ответов i:=l;
while (answerif i = 1
then
if frm.Imagel.Tag =1



  Примеры программ_____________________________________245


  then answeranswerseiectorselectoransweri:=i+l;
end;
end;
($R *.DFM)
procedure TForml.FormActivate(Sender: TObject);
begin
ResetForm(Fonnl) ;
if ParamCount = 0 then begin
Labels.font.color:=clRed;
Label5.caption:"'He задан файл вопросов теста.';
Buttoni.caption:='Ok' ;
Buttonl.tag:=2;
Buttoni.Enabled:=TRUE end else'begin
fn:=ParamStr(l) ;
assignfile(f,fn) ;
($1-) reset(f) ;
(I+) if IOResult=0 then begin
Info(f,Label5) ;
GetLevel(f) ;
end;
end;
end;
procedure TFonnl.ButtonlClick(Sender: TObject);
begin
case Buttoni.tag of 0: begin
Buttoni.caption:='Дальше' ;
Buttoni.tag:=1 ;
Selector


  246______________________Delphi 3. Программирование на Object Pascal


  { вывод первого вопроса } Buttonl.Enabled:=False;
ResetForm(Forml) ;
VoprosToScr(f,Formi,vopros) end;
1: begin ( вывод остальных вопросов ) surnma:=surnma+score
SelectorButtonl.Enabled:=False;
ResetFormtFormi);
if not eof(f)
then VoprosToScr(f,Formi,vopros) else
begin
surnma:=sunTOa+score closefile(f) ;
Buttonl.caption: =' Ok';
Formi.caption:='Результат' ;
Buttonl.tag:=2;
Buttonl.Enabled:=TRUE ;
Itog(summa,Formi);
end;
end;

  2: begin ( завершение работы ) Formi.Close;
end;
end; ( case ) end;
procedure TForml.SelectorClick(Sender: TObject) ;
var
i:integer ;
begin i:=l;
while selectorotv:=i;
Buttonl.enabled:=TRUE;
end;
end.
  По сравнению с первым вариантом программы, данный обладает существенным
преимуществом. Для его модернизации, например для увеличения количества
альтернативных ответов, достаточно изменить только описание именованной
константы N ANSWERS.



  СПРАВОЧНАЯ СИСТЕМА ПРИЛОЖЕНИЯ


  Желательно, чтобы каждая программа имела справочную систему. Физически
справочная система представляет собой набор файлов определенной структуры,
используя которые программа Winhelp, являющаяся составной частью Windows,
выводит справочную информацию в стандартном виде.
  Процесс создания справочной системы можно представить как
последовательность следующих шагов:
  П Создание файла документа справочной системы О Создание файла справочной
системы
Создание файла документа справочной системы
Файл документа справочной системы представляет собой rtf-файл, создать
который можно при помощи текстового процессора, например, Microsoft Word.
  Сначала следует набрать текст разделов справки, оформив заголовки разделов
одним из стилей Заголовок, например Заголовок 1. При этом, текст каждого
раздела справки должен находиться на отдельной странице документа
(заканчиваться символом "разрыв страницы").
  После набора текста следует при помощи сносок пометить заголовки разделов
справки (сноски используются компилятором справочной системы для
преобразования rtf-файла в Ыр-файл, файл справки). Один заголовок может
быть помечен несколькими сносками. Наиболее часто используемые сноски
перечислены в таблице.
  Сноска
Назначение
#
Задает идентификатор раздела справки, который может использоваться в
других разделах для перехода к помеченному этой сноской разделу
$
Задает имя раздела, которое будет использоваться для идентификации раздела
справки в списке поиска и в списке просмотренных тем во время
использования справочной системы
К
Задает список ключевых слов, при выборе которых из списка диалога поиска
осуществляется переход к разделу справки, заголовок которой помечен этой
сноской




  248 Delphi 3. Программирование на Object Pascal


  Чтобы пометить заголовок раздела справки, надо установить курсор перед
первой буквой текста заголовка раздела справки и из меню Вставка выбрать
команду Сноска. В появившемся диалоговом окне Сноски (рис. 135) в поле
Вставить сноску установить переключатель Обычную, а в поле Нумерация -
Другая. В поле ввода номера сноски ввести символ # и щелкнуть на кнопке ОК
Рис. 135. Диалоговое окно Сноски
В результате этого в документ будет вставлена сноска # и в нижней части
окна документа появится окно ввода текста сноски, в котором рядом со
значком сноски следует ввести идентификатор помечаемого раздела справки
(рис.136).
  Рис. 136. Вставка в документ сноски, помечающей заголовок раздела справки
В качестве идентификатора можно использовать аббревиатуру заголовка
раздела справки или сквозной номер раздела, поставив перед ним, например,
буквы TI (topic identifier).
  Замечание
Лучше чтобы идентификатор раздела справки начинался с префикса IDH_. В
этом случае во время компиляции rtf-файла будет проверена корректность

  Справочная система приложения 249
ссылок на разделы справки. Компилятор выведет список идентификаторов,
которые перечислены в разделе Как правило, разделы справки содержат ссылки
на другие разделы. Понятия (слова), выбор которых вызывает переход к
другому разделу справки, выделяются отличным от основного текста справки
цветом и подчеркиваются. При подготовке текста справки, слово, выбор
которого должен обеспечить переход к другому разделу справки, следует
подчеркнуть двойной линией и сразу за ним, без пробела, поместить
идентификатор раздела справки, к которому должен быть выполнен переход.
Вставленный идентификатор следует оформить как скрытый текст. На рис. 137
приведен пример файла документа справочной системы со словом
"дискриминант", помеченным как ссылка на другой раздел справки (здесь
предполагается, что раздел справки, в котором находятся сведения о
дискриминанте, помечен сноской #, имеющей идентификатор юн_2).
  Рис. 137. Пример оформления ссылки на другой раздел справки
Замечание
Чтобы подчеркнуть фрагмент текста двойной линией или оформить его как
скрытый текст, надо сначала выделить этот фрагмент, затем из меню Формат
выполнить команду Шрифт и в открывшемся диалоговом окне (рис. 138) на
вкладке Шрифт выбрать в поле Подчеркивание - двойное или в поле Эффекты
установить флажок Скрытый.
  Помимо ссылки, обеспечивающей переход к другому разделу справки, в
документ можно вставить ссылку на комментарий - текст, появляющийся в
всплывающем окне. Во время работы справочной системы ссылки на комментарии
выделяются цветом и подчеркиваются пунктирной линией. При



  250 Delphi 3. Программирование на Object Pascal


  подготовке документа справочной системы комментарии, как и разделы
справки, располагают на отдельной странице, однако текст комментария не
должен начинаться заголовком, оформленным одним из стилей Заголовок.
Сноска # должна быть поставлена вначале текста комментария. Ссылка на
комментарий оформляется следующим образом: сначала надо подчеркнуть
одинарной линией слово, выбор которого должен вызвать появление
комментария, затем сразу после этого слова вставить идентификатор
комментария и оформить его как скрытый текст.
  Рис. 138. Диалоговое окно Шрифт
Создание файла справочной системы
После того как создан файл документа справочной системы (rtf-файл), можно
приступить непосредственно к созданию справочной системы. Для этого удобно
воспользоваться программой Microsoft Help Workshop, которая поставляется
вместе с Delphi и находится в файле Hcw.exe подкаталога \HELP\TOOLS
каталога, - в котором установлен Delphi.
  Запустить Microsoft Help Workshop можно из Windows или выбрав команду Help
Workshop из меню Tools.
  Замечание
Если в меню Tools отсутствует команда Help Workshop, то надо выбрать
команду Configure Tools, затем в появившемся диалоговом окне Tool Options
(рис. 139) щелкнуть на кнопке Add... и в следующем диалоговом окне Tool
Properties (рис. 140) ввести: в поле Title - текст Help Workshop, в поле
Program - имя исполняемого файла программы Microsoft Help Workshop. Для
поиска имени файла можно воспользоваться кнопкой Browse....



  Справочная система приложения 251


  После щелчка на кнопке ОК становится доступным окно Configure Tools, в
списке которого появляется строка Help Workshop. Процесс настройки меню
Tools заканчивается щелчком на кнопке Close.
  После запуска Help Workshop на экране появляется главное окно программы
(рис.141).
  Чтобы приступить к созданию новой справочной системы, надо из меню File
выбрать команду New, затем в появившемся диалоговом окне - тип
создаваемого файла - Help Project. В результате этих действий открывается
окно Project FUe Name.(рис. 142).
  Рис. 139. Диалоговое окно Tool Options
Рис. 140. Диалоговое окно Tool Properties
Рис. 141. Главное окно программы Help Workshop



  252 Delphi 3. Программирование на Object Pascal


  Рис. 142. Диалоговое окно Project File Name
В этом окне сначала надо выбрать папку, где находится программа, для
которой создается справочная система, и где уже должен находиться файл
документа справочной системы (rtf-файл); затем ввести имя файла проекта
справочной системы и щелкнуть на кнопке Сохранить. В результате этих
действий открывается окно проекта справочной системы (рис. 143).
  Рис. 143. Окно проекта справочной системы
Используя это окно, можно добавить необходимые компоненты в проект, задать
характеристики окна справочной системы, выполнить компиляцию проекта и
пробный запуск созданной справочной системы.
  Сначала к проекту надо добавить файл документа справочной системы
(rtf-файл). Для этого следует щелкнуть на кнопке Files, затем на кнопке
Add... появившегося диалогового окна Topic Files. В результате этих
действий откроется стандартное окно Открытие файла, используя которое
можно выбрать нужный rtf-файл.
  Затем следует в файл проекта добавить описание окна справочной системы.
Для этого надо щелкнуть на кнопке Windows, затем на кнопке Add...
появившегося диалогового окна Window Properties. В результате этих действий



  Справочная система приложения_____________________________253


  появляется диалоговое окно Add a New Window Type (рис. 144), в поле Create
a window named
(создать окно с именем) надо ввести слово main и щелкнуть на кнопке ОК.
  Рис. 144. Диалоговое окно Add a New Window Type
После этого в поле Title bar text вкладки General следует ввести заголовок
для главного окна создаваемой справочной системы (рис. 145).
  Используя вкладку Position (рис. 146), можно задать положение и размер
окна справочной системы. На этой же вкладке находится кнопка Auto-Sizer,
при щелчке на ней появляется окно Help Window Auto-Sizer (рис. 147),
размер и положение которого определяется содержимым полей вкладки.
  Рис. 147. Окно Help Window Auto-Sizer

  ОСЛ
- ------------------_____Delphi 3. Программирование на Object Pascal
SaTa кноТк^оТ0 менять размер и "^"ие этого окна. После
бТ^ап^нТв^вкя^^^^^^^ окна ^ wndow А"10-^
Используя вкладку Color (рис. 148), можно задать цвет фона для области
заголовка раздела справки (Nonscrolling area color) и д^облТсти текста
STchS агеа С010Г)- для этого над0 щeлкнУrь на соответствуй кнопке
Change... и из стандартного окна Цвет выбрать нужный цвет.
  с^Тв^^^^^^^^^ для которой создается справочная
система"^чтобь^^тТнуж^^^^^^^^
^рТис ^ТкТ" числовые значения ^"-Фик-рам ра^ел"в в' ок^ ^р^^^^^^^^^^^^^^
в результате щелчка на ---- Map ок-
^нтТ^Тп^0^ ^^ "^Ф^РУ Раздела справки, надо щелкнуть на кнопке Add.... В
появившемся диалоговом окне (рис. 150) в поле Topic ID следует ввести
идентификатор раздела справки, а в поле Mapped numeric value
соответствующее идентификатору числовое значение.
  Рис. 150. Диалоговое окно Add Map Entry



  Справочная система приложения 255


  На рис. 151 приведен пример окна проекта справочной системы после
добавления rtf-файла, установки характеристик окна справочной системы и
назначения числовых значений идентификаторам разделов.
  Рис. 151. Пример окна проекта справочной системы
Первый раз компиляцию проекта справочной системы лучше выполнить выбором
команды Compile из меню File, в результате выполнения которой появится
диалоговое окно Compile a Help File (рис. 152).
  Рис. 152. Диалоговое окно Compile a Help File
В этом окне следует установить во включенное состояние переключатель
Automatically display Help file in WinHelp when done (по завершении
компиляции автоматически показать созданную справочную систему), затем
щелкнуть на кнопке Compile. По завершении компиляции на экране появляется
окно с информационным сообщением о результатах компиляции и, если
компиляция выполнена успешно, окно созданной справочной системы.
  Замечание
Повторную компиляцию можно выполнить щелчком на кнопке Save and Compile
окна проекта справочной системы.



  256 Delphi 3. Программирование на Object Pascal


  Использование справочной системы


  Чтобы пользователь во время работы программы мог обращаться к справочной
системе, надо с помощью Object Inspector в свойство HelpFile формы
приложения записать имя файла справочной системы, а в свойство HelpContext
- число, соответствующее номеру раздела справочной системы, который должен
быть выведен при нажатии на клавишу "F1" (рис. 153).
,.
  Рис. 153. Определение файла справочной системы приложения
(, Замечание J
Файл справочной системы приложения лучше поместить в ту папку, в которой
находится файл исполняемой программы.
  Для каждого компонента можно задать свой раздел справки. Раздел справки,
который появляется, если фокус находится на компоненте и пользователь
нажимает клавишу "F1", определяется значением свойства HelpContext этого
компонента. Если значение свойства HelpContext элемента управления равно
нулю, то при нажатии на "F1" появляется тот раздел справки, который задан
для формы приложения или родительского компонента.
  Другой способ вывода справки используется, когда в диалоговом окне есть
кнопка Справка. В этом случае для этой командной кнопки создается
процедура обработки события Ondick, которая обращением к функции winhelp
запускает программу Windows Help (WINHELP.EXE). При вызове winhelp
указывается идентификатор окна, которое запрашивает справочную информацию,
имя файла справочной системы, константа, определяющая действие, которое
должна выполнить программа Windows Help и уточняющий действие параметр.
  Замечание
Идентификатор окна определяет свойство Handle, которое доступно только во
время работы программы.



  Справочная система приложения_____________________________257


  Если необходимо вывести раздел справки, то используется константа
HELP_CONTEXT. Уточняющий параметр в этом случае задает раздел справки,
который будет выведен на экран.
  Ниже, в качестве примера, приведена процедура обработки события ondick на
кнопке Справка (Button4) диалогового окна программы решения квадратного
уравнения.
  procedure TFonal.Button4Click(Sender: TObject);
begin
winhelp(Foml. Handle, 'sqroot.hip' ,HELP_CONTEXT, 1) ;
end;



  СОЗДАНИЕ
КОМПОНЕНТА ПРОГРАММИСТА


  Delphi предоставляет возможность программисту создать свой собственный
компонент, поместить его на одну из страниц палитры компонентов и
использовать при разработке приложений точно так же, как и другие
компоненты Delphi.
  Процесс создания компонента может быть представлен как последовательность
следующих этапов:
  О Определение назначения компонента и выбор базового класса
О Создание модуля компонента
О Тестирование компонента
П Добавление компонента в пакет компонентов
Процесс создания компонента программиста рассмотрим на примере разработки
компонента, назовем его NEdit, предназначенного для ввода и редактирования
дробного числа.
  Определение назначения компонента и выбор базового класса
Приступая к разработке нового компонента, следует четко сформулировать
назначение компонента. Затем необходимо определить, какой из компонентов
Delphi наиболее близок по своему назначению, виду и функциональным
возможностям к компоненту, который будет разрабатываться. Именно этот
компонент следует выбрать в качестве базового.
  Создание модуля компонента

  ( Замечание ^

  Перед началом работы по созданию компонента следует создать новый каталог
для модуля компонента.
  Чтобы создать модуль компонента, надо из меню Component выбрать команду
New Component и в поля появившегося диалогового окна New.Component (рис.
154) ввести информацию о создаваемом компоненте.



  260 Delphi 3. Программирование на Object Pascal


  Рис. 154. Диалоговое окно New Component
Поле Ancestor type должно содержать базовый тип для создаваемого
компонента, задать который можно непосредственным вводом имени типа или
выбором из раскрывающегося списка. Для разрабатываемого компонента базовым
компонентом является компонент Edit (поле редактирования). Поэтому базовым
типом для типа компонента является тип TEdit.
  В поле Class Name нужно ввести имя класса разрабатываемого компонента,
например, TNEdit.
  В поле Palette Page надо ввести имя палитры компонентов, в которую после
создания компонента будет добавлен его значок. Название палитры можно
выбрать из раскрывающегося списка. Если в поле Palette Page ввести имя еще
не существующей палитры, то непосредственно перед добавлением компонента
палитра с указанным именем будет создана.
  В поле Unit file name находится автоматически сформированное имя файла
модуля создаваемого компонента. Delphi присваивает модулю компонента имя,
совпадающее с именем типа компонента, но без буквы Т.
  После щелчка на кнопке Create Unit к текущему проекту добавляется
сформированный Delphi-модуль, представляющий собой заготовку модуля
компонента. Текст этого модуля приведен ниже.
  unit NEdit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TNEdit = class(TEdit) private
( Private declarations ) protected
( Protected declarations )



  Создание компонента программиста 261


  public
{ Public declarations } published
{ Published declarations } end;
procedure Register-implementation
procedure Register-begin
RegisterComponents('Samples', end;
end.
  В объявлении нового класса указан только тип родительского класса. В
раздел реализации помещена процедура Register, которая используется во
время установки созданного программистом компонента в указанную палитру
Delphi для регистрации нового класса.
  В сформированное Delphi объявление класса нового компонента нужно внести
дополнения: объявить поле данных свойства, функцию доступа к полю данных и
процедуру установки значения поля данных, свойство, конструктор,
деструктор. Если на некоторые события компонент должен реагировать не так,
как базовый, то в объявление класса нужно поместить описание
соответствующих процедур обработки событий.
  Ниже приведен текст модуля NEdit после внесения всех необходимых изменений.
  // Publised должно быть Single, Double unit nedit;
interface
uses
Windows, Messages, SysOtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TNEdit = class(TEdit) private
( Private declarations }
FNumb:single; // число, находящееся в поле редактирования
// Это описание функции доступа
//и процедуры установки поля FNumb
function GetNumb:single;



  262______________________Delphi 3. Программирование на Object Pascal


  procedure SetNumb(value:single);
protected
{ Protected declarations ) procedure Keypress(var Key: Char); override;
public ( Public declarations }
published
( Published declarations ) constructor Create(AOwner:TComponent); override;
property Numb: single read GetNumb write SetNumb;
end;
procedure Register;
implementation 
procedure Register;
begin
RegisterComponents('Samples',end;
constructor TNEdit.Create(AOwner:TComponent) ;
begin
// don't forget to call the ancestors' constructor
inherited Create(AOwner) ;
end;
function TNEdit.GetNumb:singlet-begin
try
Result:=StrToFloat(text) ;
except
on EConvertError do begin
Result:=0;
text:='' ;
end;
end;
end;
procedure TNEdit.SetNumb(Value:single) ;
begin
FNumb:=Value;



  Создание компонента программиста 263


  Text:=FloatToStr(value);
end;
procedure TMEdit.Keypress(var key:char);
begin
case key of
'0'.. '9', #8, ИЗ:;
(Для России стандартный разделитель целой и дробной частей числа - запятая
}
',': if Pos(',',text)""0 then key:=#0;
'-': if Length(text)""0 then key:=#0;
else key:=#0;
end;
inherited Keypress(key) ;
end;
end.
  В описание класса TNEdit добавлено объявление свойства Numb, которое
представляет собой число, находящееся в поле редактирования. Для хранения
значения свойства Numb используется поле FNumb. Функция GetNumb необходима
для доступа к полю FNumb, а процедура setNumb - для установки значения
свойства.
  Конструктор класса TNEdit сначала вызывает конструктор родительского
класса (TEdit), присваивает значение свойству Text, затем устанавливает
значение свойства Numb.
  Реакция компонента NEdit на нажатие клавиши клавиатуры определяется
событийной процедурой TNEdit.Keypress, которая замещает соответствующую
процедуру базового класса. В качестве параметра TNEdit.Keypres.s получает
код нажатой клавиши. Перед вызовом процедуры обработки события OnKeypress
родительского класса код нажатой клавиши проверяется на допустимость. Если
нажата недопустимая для компонента NEdit клавиша (не цифра, не запятая, не
знак "минус" и не "Enter"), то код символа заменяется на ноль.
  ( Замечание ^
В тексте программы дробная часть числовой константы от целой части
отделяется точкой. Во время работы программы, при вводе исходных данных,
пользователь может отделить дробную часть числа от целой точкой или
запятой. Какой из этих двух символов является допустимым, зависит от
настройки Windows (рис. 155).
  Так, например, если в настройке Windows указано, что разделитель целой и
дробной частей числа - запятая (для России это стандартная настройка), и



  264 Delphi 3. Программирование на Object Pascal



  если во время работы приложения пользователь введет в поле редактирования,
например, строку 12.34, то при выполнении инструкции
p:=StrToFloat(Editi.Text)
возникает исключительная ситуация, так как при указанной выше настройке
Windows аргумент функции StrToFloat, содержимое поля ввода, не является
дробным числом. (Предполагается, р- это переменная типа Real, a Editi -
имя одного из полей ввода приложения.)
Рис. 155. Диалоговое окно Windows Свойства: Язык и стандарты
Тестирование модуля компонента
Перед добавлением нового компонента в палитру необходимо всесторонне его
проверить. Для этого надо создать приложение, использующее данный
компонент.
  Во время создания формы приложения нельзя добавить к форме компонент,
значка которого нет на палитре. Однако такой компонент может быть добавлен
к форме динамически, то есть во время работы приложения.
  Создается тестовое приложение обычным образом: сначала форма приложения,
затем - модуль приложения.
  Вид формы приложения тестирования компонента NEdit приведен на рис.156.



  Создание компонента программиста _______________________265


  Рис. 156. Форма приложения тестирования компонента NEdit
Форма содержит две метки и командную кнопку. Первая метка - информационное
сообщение, вторая метка (на рисунке она выделена) используется для вывода
числа, введенного в поле редактирования. Самого поля редактирования
компонента NEdit, в форме нет, он будет создан динамически во время работы
программы, но для него оставлено место над полем метки.
  После создания формы в образованный с помощью Delphi модуль приложения
надо внести следующие изменения:
  1. В список используемых модулей добавить имя модуля тестируемого
компонента
2. В объявление класса формы приложения, в раздел public declaration,
добавить объявление тестируемого компонента
3. Для формы приложения создать процедуру обработки события oncreate,
которая вызовом конструктора тестируемого компонента создаст компонент и
установит значения его свойств
Ниже приведен модуль приложения тестирования компонента NEdit.
  unit test_u;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
NEdit, StdCtrls;
type
TFonnl = class(TForm) Labell: TLabel;
Buttoni: TButton;
Label2: TLabel;
procedure ForrnCreatefSender: TObject);
procedure ButtonlClick(Sender: TObject);
private
( Private declarations }



  266 Delphi 3. Программирование на Object
Pascal


  public
( Public declarations } end;
var
Fonnl: TFormI ;
n:TNedit;
implementation
($R *.DFM}
procedure TFormI.FormCreate(Sender: TObject);
begin
n:=TNEdit.Create(self) ;
n.parent:=self;
n.left:=150;
n.top:=10;
end;
procedure TFormI.ButtonlClick(Sender: TObject);
begin
labell.caption:=FloatToStr(n.numb);
end;
end.
  Тестируемый компонент создается процедурой обработки события FormCreate
(создание, формы) посредством вызова конструктора компонента, которому в
качестве параметра передается значение self, показывающее, что владельцем
компонента является форма приложения. После создания компонента
обязательно должен быть выполнен важный шаг:
  свойству parent присвоено значение. В данном случае тестируемый компонент
находится в форме приложения, поэтому свойству parent присваивается
значение self.
  Установка компонента
Чтобы значок компонента появился на палитре, компонент должен быть
добавлен в один из пакетов (Packages) компонентов Delphi. Пакет
компонентов - это файл с расширением DPK (Delphi PacKage file). Например,
в пакете dclstd30.dpk находятся стандартные компоненты Delphi.
  Во время добавления компонента в пакет, Delphi использует модуль
компонента и файл ресурсов компонента, в котором должен находиться битовый
образ значка компонента. Необходимо, чтобы имя файла ресурсов компонента
совпадало с именем файла модуля компонента, расширение - DCR



  Создание компонента программиста 267


  (Dynamic Component Resourse). Битовый образ, находящийся внутри файла
ресурсов, должен иметь имя, совпадающее с именем класса компонента.
  Создание файла ресурсов компонента
Создать файл ресурсов компонента можно при помощи программы Image Editor,
которая запускается выбором команды Image Editor из меню Tools.
  Чтобы создать файл ресурса, надо из меню File выбрать команду New. Затем,
из появившегося списка, тип создаваемого файла - Component Resourse File
(рис.157).

  Рис. 157. Выбор типа создаваемого файла

  Рис. 158. Установка характеристик битового образа кнопки компонента

  После этого из меню Resourse надо выбрать команду New, и из появившегося
списка тип ресурса - Bitmap. В результате этих действий на экране
появляется диалоговое окно Bitmap Properties в котором надо установить
характеристики, битового образа кнопки компонента (размер 24 на 24
пикселя, количество цветов - 16) и щелкнуть на кнопке ОК (рис. 158).
  В результате этих действий в создаваемый файл ресурсов будет добавлен
новый ресурс - битовый образ с именем Bitmapl. При двойном щелчке на имени
ресурса (Bitmapl) раскрывается окно редактирования битового образа, в
котором можно, используя инструменты и палитру Image Editor, нарисовать
нужную картинку.
  Изображение в окне графического редактора можно увеличить. Для этого надо
из меню View выбрать команду Zoom In.
  Замечание
Цвет правого нижнего пикселя определяет "прозрачный" цвет. Элементы значка
компонента, закрашенные этим цветом, после помещения значка на палитру
компонентов Delphi не видны.
  Перед сохранением файла ресурсов битовому образу надо присвоить имя,
которое должно совпадать с именем класса компонента. Чтобы задать имя
битового образа, надо щелкнуть правой кнопкой мыши на имени битового
образа (Bitmapl), выбрать Rename, ввести новое имя и нажать "Enter".
  Созданный файл ресурсов сохраняется на диске обычным образом, то есть
выбором команды Save из меню File.



  268______________________Delphi 3. Программирование на Object Pascal


  ( Замечание ^
Файл ресурсов компонента надо сохранить в том каталоге, где находится файл
модуля компонента.
  На рис. 159 приведен вид окна Image Editor, в котором находится файл
ресурсов компонента TNEdit.
  Рис. 159. Окно Image Editor
Следует еще раз обратить внимание на то, что имя файла ресурсов должно
совпадать с именем модуля компонента, а имя битового образа - с именем
класса компонента.
  Установка компонента
После создания файла ресурса можно приступить к установке компонента. Для
этого надо из меню Component выбрать команду Install Component и заполнить
поля в появившемся диалоговом окне (рис. 160).
  Рис. 160. Диалоговое окно InstoH Component



  Создание компонента программиста__________________________269


  Поле Unit file name (имя файла модуля) должно содержать имя файла модуля
компонента, которое можно ввести непосредственно с клавиатуры или, после
щелчка на кнопке Browse..., при помощи стандартного диалога выбора файла.
  Поле Search path (путь поиска) должно содержать разделенные точкой с
запятой имена каталогов, в которых Delphi во время установки компонента
будет искать необходимые файлы, в частности, файл ресурса компонента. Если
имя файла модуля в поле Unit file name было введено выбором файла из
списка, полученного при помощи кнопки Browse..., то Delphi автоматически
добавляет в поле Search path имя каталога, в котором находится модуль
компонента.
  ( Замечание ^
Файл ресурса компонента должен находиться в однс?м из каталогов
перечисленных в поле Search path. Если его там нет, то компоненту будет
назначен значок его родительского класса.
  Поле Package file name должно содержать имя пакета, в который будет
установлен компонент. Предопределенным пакетом для создаваемых
программистом компонентов является пакет dclusr30.dpk.
  Поле Package description содержит краткое описание пакета. Для пакета
dclusr30.dpk это текст: Delphi User's Components (компоненты пользователя
Delphi).
  После заполнения перечисленных полей и щелчка на кнопке ОК начинается
процесс установки. Сначала на экране появляется окно Confirm (рис. 161), в
котором Delphi просит подтвердить обновление пакета: Package ... will be
rebuilt. Continue? (Пакет... будет обновлен. Продолжить?).
  После выбора Yes процесс установки продолжается. Если он завершается
успешно, то на экране появляется информационное сообщение (рис. 162) о
том, что в результате обновления пакета палитра компонентов обновлена, то
есть в нее добавлен значок нового компонента, и новый компонент
зарегистрирован.
  После установки компонента в пакет на экране появляется окно Package, окно
редактора пакета, в котором перечислены компоненты, находящиеся в пакете.



  270_____________________Delphi 3. Программирование на Object Pascal


  На этом процесс установки компонента заканчивается, в указанной при
создании модуля компонента палитре появляется значок компонента (рис.163).
  Рис. 163. Палитра Samples после установки компонента NEdit
Ошибки при установке компонента
Во время работы над новым компонентом, наиболее частой ошибкой является
попытка установить (переустановить) компонент, который уже находится в
одном из пакетов (обычно такое желание возникает после внесения изменений
в модуль компонента). В этом случае Delphi выводит сообщение:
  The package already contains unit named... (Пакет уже содержит модуль,
который называется...) и процесс установки завершается. Для того чтобы
преодолеть эту ошибочную ситуацию и установить компонент в нужный пакет
или установить в пакет обновленную версию компонента, надо сначала удалить
компонент из пакета, затем установить его снова.
  Тестирование компонента
После добавления компонента в пакет нужно проверить его поведение во время
разработки использующего этот компонент приложения.
  ( Замечание ^
Поведение компонента во время работы приложения было проверено раньше, во
время работы приложения, в котором компонент добавлялся к форме
динамически, во время работы программы.
  Можно считать, что компонент работает правильно, если во время разработки
приложения удалось поместить этот компонент в форму разрабатываемого
приложения и при помощи Object Inspector установить значения свойств
компонента, причем как новых, так и унаследованных от родительского класса.
  Проверить работоспособность компонента NEdit можно, использовав его,
например, в приложении "Решение квадратного уравнения (тест компонента),
вид формы которого приведен на рис. 164.
  Внешне форма разрабатываемого приложения почти ни чем не отличается от
формы приложения Решение квадратного уравнения, рассмотренного в одном из
предыдущих разделов. Однако, если выбранным компонентом яв-



  Создание компонента программиста__________________________271


  ляется поле ввода одного из коэффициентов уравнения, то в заголовке Object
Inspector указано, что текущим компонентом является компонент класса
TNEdit, а в списке свойств можно увидеть новое (по сравнению со списком
свойств стандартного компонента Edit) свойство - Numb (рис. 165).
  Рис. 164. Форма приложения Решение Рис. 165. Свойства компонента
класса квадратного уравнения (тест компонента) TNEdit в окне Object
Inspector
На листинге приведен модуль приложения Решение квадратного уравнения (тест
компонента).
  unit TestOfComp_u;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls, nedit;
type
TCompTestFm = class(TForm) Labels: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Roots: TLabel;
CalcBtn: TButton; ( кнопка "Вычислить" } NewBtn: TButton; ( кнопка
"Новое" } CloseBtn: TButton; ( кнопка "Завершить" } a: TNEdit;
b: TNEdit;
c: TNEdit;
procedure CalcBtnClick(Sender: TObject);



  Создание компонента программиста__________________________271


  ляется поле ввода одного из коэффициентов уравнения, то в заголовке Object
Inspector указано, что текущим компонентом является компонент класса
TNEdit, а в списке свойств можно увидеть новое (по сравнению со списком
свойств стандартного компонента Edit) свойство - Numb (рис. 165).
  Рис. 164. Форма приложения Решение Рис. 165. Свойства компонента
класса квадратного уравнения (тест компонента) TNEdit в окне Object
Inspector
На листинге приведен модуль приложения Решение квадратного уравнения (тест
компонента).
  unit TestOfComp_u;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls, nedit;
type
TCompTestFm = class(TForra) Labels: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Roots: TLabel;
CalcBtn: TButton; ( кнопка "Вычислить" } NewBtn: TButton; ( кнопка
"Новое" ) CloseBtn: TButton; { кнопка "Завершить" } a: TNEdit;
b: TNEdit;
c: TNEdit;
procedure CalcBtnClick(Sender: TObject);



  272_____________________Delphi 3. Программирование на Object Pascal


  procedure NewBtnClick(Sender: TObject);
procedure CloseBtnClick(Sender: TObject);
procedure FonnActivate(Sender: TObject);
procedure aKeyPress(Sender: TObject; var Key: Char);
procedure bKeyPress(Sender: TObject; var Key: Char);
procedure cKeyPress(Sender: TObject; var Key: Char);
private
( Private declarations }
public
( Public declarations }
end;
var
CompTestFnn: TConipTeatFnn;
implementation ($R *.DFM)
procedure SqRoot(a,b,c:tNEdit;Roots:tLabel) ;
( a,b,c - коэффициенты уравнения } var
d:real; ( Дискриминант } xl,x2:real; ( Корни уравнения } begin
if a.Numb = 0 then begin Roots.font.color:"cIRed;
Roots.caption:"
'Коэффициент .при второй степени' +#13+'неизвестного равен нулю!';
end else begin ( решение уравнения )
( Вычисление дискриминанта ) d:=Sqr(b.Numb)-4*а.Numb*c.Numb;
if d"0 then begin
(Label2.color:=clRed;) Roots.font.color:"cIRed;
Roots.caption:= 'Дискриминант меньше нуля.'+#13+ 'Уравнение не имеет
корней.' end else begin
{ Вычисление корней ) xl:=(b.Numb+Sqrt(d))/(2*a.Numb) ;
x2:=(-b.Numb+Sqrt(d))/(2*a.Numb) ;
{ Вывод результата - значения корней} Roots.font.color:=clBlack;



  Создание компонента программиста__________________________273


  Roots.caption:"'Корни уравнения:' +#13+'xl='+FloatToStr(xl)
+#13+'x2='+FloatToStr(x2) ;
end;
end;
end;
procedure TCoinpTestFnn.NewBtnClick(Sender: TObject);
begin
a.text:=";
b.text:=";
c.text:"'';
Roots. font. color: =clBlack;
Roots.caption:='' ;
a.Set Focus;
end;
procedure TCompTestFrm.CloseBtnClick(Sender: TObject);
begin
Closet-end;
procedure TConpTestFrm.CalcBtnClick(Sender: TObject);
begin
SqRoot(a,b,c,Roots);
end;
procedure TCoinpTestFrm.FonnActivate(Sender: TObject);
begin
a.SetFocus;
end;
procbdure TConpTestFrm.aKeyPress(Sender: TObject; var Key: Char);
begin
if key = #13 then b.SetFocus;
end;
procedure TConpTestFnn.bKeyPress(Sender: TObject; var Key: Char);
begin
if key = #13 then c.SetFocus;
end;
procedure TCompTestFnn.cKeyPress(Sender: TObject; var Key: Char);
begin
if key = #13 then begin
SqRoot(a,b,c,Roots);



  274 Delphi 3. Программирование на Object Pascal


  CalcBtn.SetFocus ;
end;
end;
end.


  Удаление компонента

  Удалить компонент из пакета можно при помощи редактора пакета.
  Чтобы запустить редактор пакета, надо из меню Component выбрать команду
Install Packages (установленные пакеты), в появившемся окне (рис. 166), из
списка Design packages, выбрать нужный пакет и щелкнуть на командной
кнопке Edit....
  Рис. 166. Выбор пакета для редактирования
В появившемся окне, в ответ на запрос Close this dialog and open...
(Закрыть этот диалог и открыть пакет...), надо щелкнуть на кнопке Yes. В
результате этого открывается окно редактора пакета (рис. 167), в котором
на вкладке Contains (содержимое) перечислены компоненты пакета.
  Чтобы удалить компонент из пакета, надо выбрать этот компонент и щелкнуть
на командной кнопке Remove.
  Замечание
После удаления компонента из пакета щелчком на кнопке Remove нужно
обязательно выполнить перекомпиляцию пакета, для чего надо щелкнуть на
командной кнопке Compile. После перекомпиляции пакета Delphi информирует о
том, что удаленный компонент больше не зарегистрирован (рис. 168).



  Создание компонента программиста 275



  Рис. 167. Редактор пакета

  Рис. 168. Информационное окно

  После перекомпиляции пакета надо закрыть окно редактора пакета, подтвердив
сохранение изменений в пакете, из которого был удален компонент.
  Настройка палитры компонентов
Delphi позволяет изменить название страницы палитры компонентов. Для того
"чтобы это сделать, надо из меню Component выбрать команду Configure
Palette, на вкладке Palette открывшегося диалогового окна Environment
Options (рис. 169) в списке Pages выбрать страницу, название которой
подлежит изменению, и щелкнуть на командной кнопке Rename.
  Затем в появившемся диалоговом окне Rename page (переименование страницы)
ввести новое имя для выбранной страницы и щелкнуть на ОК (рис.170).
  Используя вкладку Palette диалогового окна Environment Options, можно
изменить порядок следования страниц на палитре компонентов. Например, если
надо, чтобы страница System следовала за страницей Standard, то в списке
Pages следует выделить название искомой страницы и несколькими щелчками на
командной кнопке Move Up (переместить вверх), затем переместить имя
выбранной страницы на вторую позицию в списке (командная



  276 Delphi 3. Программирование на Object Pascal


  кнопка Move Down (переместить вниз) перемещает выделенный элемент на один
шаг вниз, к концу списка).
  Рис. 169. Вкладка Palette диалогового окна Environment Options
Рис. 170. Диалоговое окно Rename page



  ЗАКЛЮЧЕНИЕ


  Очевидно, что в одной книге, тем более ориентированной на начинающих
программистов, нельзя рассмотреть все вопросы, связанные с
программированием на Object Pascal в Delphi. Многие интересные темы,
например создание мультимедийных и Internet-приложений, баз данных, задачи
динамического обмена данными (DDE) между приложениями и другие, остались
за рамками книги. Вместе с тем, в книге рассмотрены основополагающие,
базисные понятия и методы программирования вообще и программирования в
Delphi в частности.
  Работая над книгой, я старался выстроить материал таким образом, чтобы в
тот момент, когда читатель перевернет последнюю страницу, он был бы в
состоянии написать вполне приличную программу, которая бы не "ломалась" от
неверно введенных данных и которая могла бы произвести впечатление на
коллег-программистов, пускай тоже начинающих, например, наличием
справочной системы. Согласитесь, что когда программа не "ломается", это не
производит особого впечатления (так и должно быть). Но когда у программы
есть справочная система, то она выглядит вполне профессионально!
  О литературе. Научиться программировать не владея общими вопросами теории
и практики программирования практически невозможно. Книги, заглавия
которых начинаются фразами типа "Практическое руководство ...", "Наиболее
полное описание ...", как правило, рассматривают узкие специфические
вопросы конкретного языка или среды программирования. Они, безусловно,
полезны. Однако следует обращать внимание и на книги, посвященные общим
вопросам теории и практики программирования. Авторами этих книг, как
правило, являются ведущие специалисты в области программирования. Здесь
хочется порекомендовать работы Вирта, Зелкови-ца, Гринзоу (см. раздел
приложения "Рекомендуемая дополнительная литература").
  В заключение еще раз хочется повторить, что научиться программировать
можно только программируя, решая конкретные задачи. Поэтому ищите задачи и
программируйте!



  ПРИЛОЖЕНИЕ


  Язык Pascal (краткий справочник) Структура модуля
Модуль состоит из последовательности разделов. Каждый раздел начинается
ключевым словом и продолжается до начала следующего раздела.
  unit ИмяМодуля;
interface // интерфейсный раздел ( Здесь находятся описания процедур
и функций этого модуля, которые могут использоваться другими модулями }
const // раздел объявления констант
( Здесь находятся объявления глобальных констант модуля, которые могут
использоваться процедурами и функциями модуля}
type // раздел объявления типов
( Здесь находятся объявления глобальных типов модуля, которые могут
использоваться процедурами и функциями модуля }
var // раздел объявления переменных { Здесь находятся
объявления глобальных . переменных модуля, которые могут
использоваться процедурами и функциями
модуля }
implementation // раздел реализации ( Здесь находятся описания процедур
и функций модуля) end.
  Основные типы данных
К основным типам данных Pascal относятся:
  О Целые числа D Числа с плавающей точкой

  D Символы (char)
D Строки (string)
О Логический тип (boolean)
Целые числа и числа с плавающей точкой могут быть представлены в различных
форматах.
  Целые числа


  Формат
Диапазон


  Shortint
- 128..127


  Integer
- 32 768..32 767


  Longint
- 2 147 483 648..2 147 483 647


  Byte
0..255


  Word
0..65 535



  Числа с плавающей точкой
Формат
Диапазон
Значащих цифр
Real
2.9e-39.. 1.7е38
11-12
Single
1.5е-45..3.4е38

                                7-8

  Double
5.0е-324.. 1.7е308
15-16
Extended
3.4е-4932.. 1.1е4932
19-20

  Строки
Вариант 1.
  Иия:string;
Объявлена переменная-строка длиной 256 символе! Вариант 2.
  имя: string Объявлена переменная-строка указанной длины.



  Приложение_________________________________________281


  Массивы

  Объявление одномерного массива:
  ИмяМассива: array Объявление двумерного массива:
  ИмяМассива: array Нижюо1Индекс2. . .ВерхнийИндекс2} of ТипЭлементов
Запись
Вариант 1.
  ПеременнаяЗапись: record Поле!:Тип1;
.Поле2;Тип2;
HoneJ: TwiJ;
end;
Вариант 2. type
Имя Типа За .писи=гвсогс1 Поле!:Тип1;
Поле2;Тип2;
noneJ:TunJ;
end;
var
П^ременнаяЗапись:ИмяТипаЗаписи;
Сначала описывается тип записи. Затем объявляется переменная-запись.


  Выбор

  Инструкция if
Вариант 1.
  if Условие then begin
( Блок инструкций, который выполняется, } { если условие истинно } end

  282 Delphi 3. Программирование на Object
Pascal
else
begin
( Блок инструкций, который выполняется, } ( если условие ложно } end;
Вариант 2.
  if Условие then
begin
( Блок инструкций, который выполняется, } { если условие истинно ) end;
С Замечание ^
Если между begin и end находится только одна инструкция, то слова begin и
end можно не писать.
  Инструкция case
Вариант 1.
  case Выражение of
Список1_Констант: begin
( инструкции ) end;
Список2 Констант: begin
{ инструкции } end;
Список J__KOHCTBHT: begin
( инструкции } end;
end;
Вариант 2.
  case Выражение of
Список! Констант: begin
( инструкции 1} end;
Список2 Констант: begin
{ инструкции 2} end;



  Приложение________________________________________283


  Список".Г_Констант: begin
( инструкции J) end;
else
begin
{ инструкции } end;
end;
Инструкции между begin и end выполняются, если значение выражения после
case совпадает с константой из соответствующего списка. Если это не так,
то выполняются инструкции между begin и end, расположенными после else.
  С Замечание ^
Если между begin и end находится только одна инструкция, то слова begin и
end можно не писать.
  Циклы
Инструкция for
Вариант 1 ( с увеличением счетчика).
  for Счетчик:=НачальноеЗначею1е to КонечноеЗначение do begin
{ здесь инструкции } end;
Инструкции между begin и end выполняются (КонечноеЗначение -
Началь-ноеЗначениё) + 1 раз.
  Если НачалъноеЗначение больше, чем КонечноеЗначение, то инструкции между
begin и end не выполняются.
  ( Замечание ^
Если между begin и end находится только одна инструкция, то слова begin и
end можно не писать.
  Вариант 2 ( с уменьшением счетчика).
  for Счетчик:=НачальноеЗначение downto КонечноеЗначение do begin
( здесь инструкции } end;
Инструкции между begin и end выполняются (НачольноеЗначение -
КонечноеЗначение) + 1 раз.



  284_____________________Delphi 3. Программирование на Object Pascal


  Если НачольноеЗначенче меньше, чем КонечноеЗначение, то инструкции между
begin И end не ВЫПОЛНЯЮТСЯ.
  ( Замечание ^
Если между begin и end находится только одна инструкция, то слова begin и
end можно не писать.
  Инструкция repeat
repeat
begin
( инструкции )
end until Условие;
Сначала выполняются инструкции цикла, которые расположены между begin и
end. Затем проверяется значение выражения Условие, и если оно равно False,
то инструкции цикла выполняются еще раз. И так до тех пор, пока Условие не
станет истинным.
  С Замечание ^)
Если между begin и end находится только одна инструкция, то слова begin и
end можно не писать.
  Инструкция while
while Условие do begin
( инструкции } nd;
Проверяется Условие, если оно истинно, то выполняются инструкции между
begin и end. Итак до тех пор, пока Условие не станет ложным.
  ( Замечание ^
Если между begin и end находится только одна инструкция, то слова begin и
end можно не писать.
  Безусловный переход Инструкция GoTo
GoTo Метка;
Инструкция осуществляет переход к инструкции, перед которой стоит метка.
Метка должна быть объявлена в разделе label.



  Приложение 285


  Объявление функции

  Function Иквфункции(уаг Параметр!: Тип1:
  var Параметр2: Тип2;
var Параметр J: TunJ) : Тип;
const
( описание констант ) var
{ описание переменных ) begin
( инструкции функции }
Result:"Значение;
end;
Объявление процедуры
Procedure ИмяПроцедуры(чгах Параметр!: Тип!;
var Параметр2:Тип2;
var Параметр^. KwrJ);
const
( описание констант ) var
( описание переменных ) begin
{ инструкции процедуры } end;.
  Встроенные функции и процедуры
При описании функций и процедур приняты следующие обозначения:
  О Имена функций и процедур выделены жирным
О Параметры изображены наклонным шрифтом. В качестве параметра могут
использоваться константы, переменные или выражения соответствующего типа.
Если параметром обязательно должна быть переменная, то перед ним
поставлено слово var. После параметра указывается его тип
О После списка параметров функций через двоеточие указан тип результата,
возвращаемого функцией



  286 Delphi 3. Программирование на Object Pascal


  Математические


  АЬз{Выражение)
Абсолютное значение аргумента (целый или вещественный тип)
5су{Выражение)
Квадрат аргумента (целый или вещественный тип)
5уъ(Выражение: real): real
Квадратный корень аргумента
81п(Быражение:геа1):геа1
Синус
Соз(Выражение: real): real
Косинус
Агс1ап(быражение:геа1):геа1
Арктангенс
Ехр(Выражение: real) :геа1
Экспонента
^(Выражение: real): real

  Натуральный логарифм

  Преобразования


  lnt( Выражение: real): real
Целая часть
Тг\1пс(Выражение: real): long int
Целая часть
Round(6b/paxeHHe:real):longint
Округление к ближайшему целому
1.пътозъ1:(Выражение)
Преобразование числового выражения целого типа в строку
ЕЧоаЬТоЗЬг(быражение)
Преобразование вещественного числа в его изображение
FloatToStrF(Bb/paxeHMe, Формат, Точность, КоличествоЦифр)
Преобразование вещественного числа в его изображение с возможностью выбора
способа изображения
StrTolnt(Crpo"a: string)
Преобразование строки, изображающей целое или вещественное число, в число
s trToFloat( Строка: string)
Преобразование строки, изображающей вещественное число, в число

  Для работы со строками и символами
Concat( Строка 1: string, ... ,Crpcwa/V:string):string Объединение
нескольких строк в одну
Copy(Crpo;(a;string,/-/oMepCt"Mso/7a;integer, Выделение подстроки
Длиналпедег): string




  Приложение________________________________________^7


  Delete(var CrpoKa:srting, /-/oMepCnMBo/7a:integer, Сколько: integer)
Удаление части строки
Length( Строка: string): integer
Длина строки
Роз(Сгрока: string, Подстрока: string):byte
Позиция подстроки в строке
СЬг(/"одСимво/7а:Ьу1е)
Символ с указанным кодом


  Кодировка символов в Windows


  В Windows используется кодировка, которая называется ANSI. Разновидность
набора ANSI, содержащая символы русского алфавита, называется Windows-1251.
  Некоторые служебные символы:
  Код символа Символ

                                9

  Табуляция

                                11

  Новая строка

                                13

  Конец параграфа

                                32

  Пробел

  Символы с кодами 32-127:
  32 44 , 56 8 68 D

                                33

  !
  45
-

                                57

  9

                                69

  Е

                                34

  "

                                46



  58


  70
F

                                35

  #

                                47

  /

                                59

  ',

                                71

  G

                                36

  $

                                48

  0

                                60

  "

                                72

  Н

                                37

  %

                                49

  1

                                61

  =

                                73

  I

                                38

  &

                                50

  2

                                62

  "

                                74

  J

                                39

  

                                51

  3

                                63

  ?
  75
К

                                40

  (

                                52

  4

                                64

  @

                                76

  L

                                41

  )

                                53

  5

                                65

  А

                                77

  М

                                42

  *

                                54

  6

                                66

  В

                                78

  N

                                43

  +

                                55

  7

                                67

  С

                                79

  0



  285_____________________Delphi 3. Программирование на Object Pascal


  80
Р

                                92

  \

                                104

  h

                                116

  t

                                81

  Q

                                93

  ]

                                105

  i

                                117

  U

                                82

  R

                                94

  ^

                                106

  i

                                118

  V

                                83

  S

                                95



  107
k

                                119

  W

                                84

  Т

                                96

  

                                108

  I

                                120

  X

                                85

  U

                                97

  а

                                109

  m

                                121

  У

                                86

  V

                                98

  b

                                110

  n

                                122

  z ,

                                87

  W

                                99

  с

                                111

  о

                                123

  88

                                X

  100
d

                                112

  P

                                124

  I

                                89

  Y

                                101

  e

                                113

  q

                                125

  ]

                                90

  Z

                                102

  f

                                114

  г

                                126

  ~

                                91

  103

                                9

  115
s

                                127




  Символы с кодами 192-255:


  192
А

                                208

  P

                                224

  а

                                240

  P

                                193

  Б

                                209

  С

                                225

  6

                                241

  с

                                194

  В

                                210

  Т

                                226

  в

                                242

  т

                                195

  Г

                                211

  У

                                227

  г

                                243

  У

                                196

  Д

                                212

  ф

                                228

  Д

                                244

  Ф

                                197

  Е

                                213

  X

                                229

  e

                                245

  X

                                198

  Ж

                                214

  ц

                                230

  ж

                                246

  Ц

                                199

  3

                                215

  ч

                                231

  3

                                247

  ч

                                200

  И

                                216

  ш

                                232

  и

                                248

  ш

                                201

  и

                                217

  щ

                                233

  и

                                249

  щ

                                202

  к

                                218

  b

                                234

  к

                                250

  ъ

                                203

  л

                                219

  ы

                                235

  л

                                251

  ы

                                204

  м

                                220

  b

                                236

  м

                                252

  ь

                                205

  н

                                221

  э

                                237

  н

                                253

  э

                                206

  о

                                222

  ю

                                238

  о

                                254

  ю

                                207

  п

                                223

  я

                                239

  п

                                255

  я




  Приложение_________________________________________259


  Представление информации в компьютере
Десятичные и двоичные числа
В обыденной жизни человек имеет дела с десятичными числами. В десятичной
системе счисления для представления чисел используются цифры от О до 9.
Значение числа определяется как сумма произведений цифр числа на весовой
коэффициент, определяемый местом цифры в числе. Весовой коэффициент самой
правой цифры равен единице, цифры перед ней - десяти, затем ста и т. д.
Например, число 2703 равно 2*1000+7*100+0*10+3*1.
  Если места цифр пронумеровать справа налево и самой правой позиции
присвоить номер ноль, то можно заметить, что вес i-ro разряда равен i-й
степени десяти.

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

  1*128 + 1*64 +0*32 + 0*16 + 1*8 + 1*4 + 0*2 + 1*1 = 205
или
(11001101)2= (205)ю


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



  290 Delphi 3. Программирование на Object Pascal


  ца. Восемь бит объединены в байт. Максимальное число, которое можно
записать при помощи восьми двоичных цифр - это 11111111, что соответствует
десятичному числу 255, минимальное - ноль. Поэтому значением байта может
быть число от нуля до 255.
  Память используется для хранения переменных. Так как переменные различного
типа могут принимать различные значения, то для их хранения нужно разное
количество памяти. Память под переменные выделяется целым числом байт.
Например, значением переменной типа char может быть любой из 256 символов.
Поэтому для хранения переменной этого типа достаточно одного байта.
Значением переменной типа integer может быть число от -32 768 до 32 767
(65 535 значений), для хранения переменной этого типа надо два байта.
Очевидно, что чем больше диапазон чисел типа, тем больше байт нужно для
хранения переменной этого типа (см. таблицу ниже).
  Тип переменной
Занимаемая память (байт)
Диапазон значения
Char

                                1

  любой символ
String

                                256

  строка до 256 символов
String1 *n
строка до п символов
Byte

                                1

  0..255
Word

                                2

  0..65 535
Integer

                                2

  - 32 768..32 767
Longint

                                4

  - 2 147 483 648..2 147 483 647
Real

                                6

  2.9е-39.. 1.7е38
Single

                                4

  1.5е-45..3.4е38
Double

                                8

  5.0е-324.. 1.7е308
Extended

                                8

  3.4е-4932.. 1.1е4932

  В программе для хранения одного и того же значения могут применяться
переменные разного типа (при этом будет использоваться разное количество
памяти). Например, если в программе имеется переменная Day, хранящая число
месяца, то для ее хранения можно использовать переменную типа byte,
integer или longin. В первом случае будет занят один байт памяти, во
втором - два, в третьем - четыре. Но реально будет задействован только
один байт, а остальные будут только заняты. Поэтому, выбирая тип для
переменной, следует подбирать наиболее подходящий тип для каждой
конкретной ситуации. Особо необходимо обращать внимание на описание
строковых переменных и массивов.



  Приложение__________________________________291


  Выделяя память для строковых переменных следует помнить, что если не
указана предельная длина строки, то переменной выделяется 256 байт.
Объявляя переменную, предназначенную для хранения имени человека, надо
писать name:stringКаждому массиву программы выделяется объем памяти,
который определяется как типом элементов массива, так и их количеством.
Например, для хранения двумерного массива, например 20 на 20, вещественных
чисел нужно более трех килобайт памяти (20*20*8=3200).
  Хотя память компьютера кажется неограниченной, но если ее не использовать
рационально, то в некоторый момент может возникнуть ситуация, связанная с
нехваткой памяти.


  Рекомендуемая дополнительная литература


  1. Вирт Н. Алгоритмы и структуры данных: пер. с англ. - М.: Мир, 1989. -
360 с., ил.
  2. Зелковиц М., Шоу А., Гэннон Дж. Принципы разработки программного
обеспечения: пер. с англ. - М.: Мир, 1982. - 386 с., ил.
  3. Практическое руководство по программированию: пер. с англ./ Б. Мик, П.
Хит, Н. Рашби и др.; под ред. Б. Мика, П. Хит, Н. Рашби. - М.: Радио и
связь, 1986. - 168 с., ил.
  4. Фоке Дж. Программное обеспечение и его разработка: пер. с англ. - М.:
  Мир, 1985. - 368 с., ил.
  5. Язык компьютера. Пер. с англ. под ред. и с предисл. В. М. Курочкина. -
М.: Мир, 1989. - 240 с., ил.
  6. Дж. Мэтчо и др. Delphi 2. Руководство для профессионалов: пер. с англ.
  - Спб.: BHV-Санкт-Петербург, 1997. - 784 с., ил.
  7. Дарахвелидзе Г. П., Марков Е. П. Delphi - среда визуального
программирования. - СПб.: BHV-Санкт-Петербург, 1996. - 352 с.
  8. Эндрю Возневич Delphi. Освой самостоятельно: пер. с англ. - М.:
Восточная книжная компания, 1996. - 736 с., ил.
  9. Гринзоу Лу. Философия программирования для Windows 95/NT: пер. с англ.
  - СПб.: Символ-Плюс, 1997. - 640 с., ил.


  ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ

  Н
Help-компилятор, 250

 I

  Image Editor, 267
Б
Бинарный поиск, 122 Блок-схема алгоритма, 10
В
Ввод
записи,179
из файла, 167
с клавиатуры, 95 Виртуальный метод, 204 Вывод
записи, 179
на экран, 93
д
Деструктор, 199

                                3

  Запись, 176

  м
Microsoft Help Workshop, 250
w
Windows Help (winhelp), 256
И
Идентификатор
раздела справки, 254 Иллюстрация
добавление к форме, 225
загрузка из файла, 225 Инкапсуляция, 200 Инструкция
Case, 75
For, 83
Goto, 90
If, 69
Read, Readin, 95
Repeat... Until, 87
While, 85
with, 178
write, 160
Write, Writein, 93
writein, 160
безусловного перехода, 90
ввода, 95
выбора, 69
множественного выбора, 75 Источник события (Sender), 213

  294
Delphi 3. Программирование на Object Pascal



  К
Класс, 197
Командная строка, 227 Компиляция, 53 Компонент
Image, 225
StrringGrid, 139
динамический, 238
программиста, 259 Конструктор, 198
м
Массив
ввод, 111
вывод, 110
компонентов, 238
многомерный, 136
объявление, 109
ошибки при использовании, 143
поиск максимального элемента, 119
поиск минимального элемента, 119
поиск элемента, 120
сортировка, 132 Машинный код, 12 Метод
Create, 198
Free, 199
LoadFromFile, 225
SetFocus, 213 Метод класса, 199
О
Объект, 198 Объявление
записи,176
файла, 159 Оператор, 18
AND, 69
DIV, 18
MOD, 18
NOT, 69
OR, 69
логический, 69 Операнд,18 Ошибка
открытия файла, 162

  п
Пакет компонентов, 266 Переменная
динамическая, 186
указатель, 185 Пиктограмма
создание, 60 Программа
исходная, 11 Программировани
объектно-ориентированное, 197 Процедура
Append, 161
AssignFile, 160
Close, 164
Rewrite, 161
обработки события, 48
Р
Редактор
образов, 267
пакета компонентов, 274 Рекурсия, 147 Ресурс, 266
С
Свойство, 200
HelpContext, 256
HelpFile, 256
Stretch, 225
наследование, 202
объекта, 200 Символы, 101 Событийная процедура
динамического компонента, 239 Список
добавление в упорядоченный список, 190
добавление элемента, 188
односвязный, 187
удаление элемента, 193 Ссылка
на раздел справки, 249 Структура
проекта Delphi, 64

  Предметный указатель_________________________________ 295



  Т
Тип
char, 101
TextFile, 159
интервальный, 175
определяемый программистом, 173
У
Условие, 67
Ф
Файл hip, 247

  Файл
rtf,247
пакет компонентов (DPK), 266 проекта справочной системы, 251 ресурсов
компонента, 266 справочной системы, 247 Функция
FloatToSrtF, 216 lOResult, 163
Ц
Цикл For, 83
Repeat... Until, 87 While, 85

  СОДЕРЖАНИЕ


ПРЕДИСЛОВИЕ............................................... З
СОГЛАШЕНИЕ ОБ ОБОЗНАЧЕНИЯХ................................ 4
ВВЕДЕНИЕ.................................................. 5
ОСНОВЫ ПРОГРАММИРОВАНИЯ................................... 7
ЭТАПЫ РАЗРАБОТКИ ПРОГРАММЫ ............................... 7
АЛГОРИТМ И ПРОГРАММА...................................... 8
КОМПИЛЯЦИЯ................................................ 11
ЯЗЫК ПРОГРАММИРОВАНИЯ OBJECT PASCAL....................... 12
Типы данных............................................... 12
Переменные................................................ 14
Константы................................................. 16
Инструкция присваивания................................... 17
Стандартные функции....................................... 20
Ввод данных............................................... 22
Вывод данных.............................................. 23
Программирование в Delphi................................. 27
DELPHI - СРЕЦА ВИЗУАЛЬНОГО ПРОГРАММИРОВАНИЯ .............. 31
УСТАНОВКА DELPHI ......................................... 31
ЗАЙУСК DELPHI ............................................ 37
НАЧАЛО РАБОТЫ В DELPHI.................................... 39
ПЕРВЫЙ ПРОЕКТ............................................. 40
Форма приложения ......................................... 41
Компоненты формы.......................................... 43
Событие и процедура обработки события..................... 47
Редактор кода Delphi...................................... 49
Сохранение проекта........................................ 51
Компиляция ............................................... 53
Запуск приложения из среды программирования............... 56
Ошибки времени выполнения приложения...................... 5б
Окончательная настройка приложения ....................... 58
Установка приложения ..................................... 61
Структура простого проекта Delphi......................... 64
УПРАВЛЯЮЩИЕ СТРУКТУРЫ OBJECT PASCAL....................... 67
УСЛОВИЕ .................................................. 67
ВЫБОР .................................................... 69
Инструкция IF............................................. 69
Инструкция CASE........................................... 75
ЦИКЛЫ..................................................... 82
Инструкция FOR............................................ 83
Инструкция WHILE.......................................... 85
Инструкция REPEAT...UNTIL................................. 87
Инструкция GOTO........................................... 90
ИНСТРУКЦИИ ВВОДА-ВЫВОДА................................... 93
Инструкции WRITE и WRITELN................................ 93
Инструкции READ и READLN.................................. 95
Консольное приложение .................................... 97
СИМВОЛЫ И СТРОКИ.......................................... 101
Символы................................................... 101
СТРОКИ.................................................... 103
Функция LENGTH............................................ 105
Процедура DELETE.......................................... 105
Функция POS............................................... 106
Функция COPY.............................................. 106
МАССИВЫ................................................... 109
ОБЪЯВЛЕНИЕ МАССИВА........................................ 109
НЕКОТОРЫЕ ТИПИЧНЫЕ ДЕЙСТВИЯ С МАССИВАМИ .................. 110
Вывод массива............................................. 110
Ввод массива.............................................. 111
Поиск минимального (максимального) элемента массива....... 119
Поиск в массиве .......................................... 120
Повторное использование функций и процедур программиста... 126
Сортировка массива........................................ 132
МНОГОМЕРНЫЕ МАССИВЫ ...................................... 136
ОШИБКИ ПРИ ИСПОЛЬЗОВАНИИ МАССИВОВ......................... 143
РЕКУРСИЯ.................................................. 147
ПОНЯТИЕ РЕКУРСИИ.......................................... 147
ПРИМЕР ПРОГРАММЫ: ПОИСК ПУТИ ............................. 149
ПРИМЕР ПРОГРАММЫ: ПОИСК КРАТЧАЙШЕГО ПУТИ.................. 155
ВЫВОДВФАЙЛ................................................ 159
ОБЪЯВЛЕНИЕ ФАЙЛА ......................................... 159
НАЗНАЧЕНИЕ ФАЙЛА.......................................... 159
ВЫВОД В ФАЙЛ.............................................. 160
ОТКРЫТИЕ ФАЙЛА ДЛЯ ВЫВОДА................................. 160
ОШИБКИ ОТКРЫТИЯ ФАЙЛА..................................... 162
ЗАКРЫТИЕ ФАЙЛА............................................ 164
ПРИМЕР ПРОГРАММЫ.......................................... 164
ВВОДИЗФАЙЛА............................................... 167
ОТКРЫТИЕ ФАЙЛА............................................ 167
ЧТЕНИЕ ДАННЫХ ИЗ ФАЙЛА.................................... 168
Чтение чисел.............................................. 168
Чтение строк.............................................. 169
Определение конца файла................................... 170
ТИПЫ ДАННЫХ, ОПРЕДЕЛЯЕМЫЕ ПРОГРАММИСТОМ................... 173
ПЕРЕЧИСЛЯЕМЫЙ ТИП......................................... 173
ИНТЕРВАЛЬНЫЙ ТИП.......................................... 175
ЗАПИСЬ.................................................... 176
Объявление типа записи.................................... 176
Инструкция WITH........................................... 178
Ввод и вывод записей в файл............................... 179
ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ ............................ 184
Переменные-указатели...................................... 185
Динамические переменные................................... 186
Связанные списки.......................................... 187
ВВЕДЕНИЕ В ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ...... 1?
КЛАСС..................................................... 197
ОБЪЕКТ-................................................... 198
МЕТОД..................................................... 199
ИНКАПСУЛЯЦИЯ И СВОЙСТВА ОБЪЕКТА .......................... 200
НАСЛЕДОВАНИЕ..........-................................... 202
ДИРЕКТИВЫ PROTECTED И PRIVATE. ........................... 203
ПОЛИМОРФИЗМ И ВИРТУАЛЬНЫЕ МЕТОДЫ ......................... 204
КЛАССЫ И ОБЪЕКТЫ DELPHI................................... 209
ПРИМЕРЫ ПРОГРАММ.......................................... 211
РЕШЕНИЕ КВАДРАТНОГО УРАВНЕНИЯ ............................ 211
СИСТЕМА ПРОВЕРКИ ЗНАНИЙ .................................. 218
Требования к программе.................................... 219
Файл теста................................................ 219
Форма приложения ......................................... 222
Вывод иллюстрации......................................... 225
Открытие файла теста...................................... 226
Текст программы........................................... 228
Усовершенствование программы.............................. 238
СПРАВОЧНАЯ СИСТЕМА ПРИЛОЖЕНИЯ............................. 247
СОЗДАНИЕ ФАЙЛА ДОКУМЕНТА СПРАВОЧНОЙ СИСТЕМЫ .............. 247
СОЗДАНИЕ ФАЙЛА СПРАВОЧНОЙ СИСТЕМЫ ........................ 250
ИСПОЛЬЗОВАНИЕ СПРАВОЧНОЙ СИСТЕМЫ ......................... 256
СОЗДАНИЕ КОМПОНЕНТА ПРОГРАММИСТА.......................... 259
ОПРЕДЕЛЕНИЕ НАЗНАЧЕНИЯ КОМПОНЕНТА И ВЫБОР БАЗОВОГО КЛАССА. 259
СОЗДАНИЕ МОДУЛЯ КОМПОНЕНТА................................ 259
ТЕСТИРОВАНИЕ МОДУЛЯ КОМПОНЕНТА............................ 264
УСТАНОВКА КОМПОНЕНТА...................................... 266
Создание файла ресурсов компонента........................ 267
Установка компонента...................................... 268
Ошибки при установке компонента........................... 270
ТЕСТИРОВАНИЕ КОМПОНЕНТА................................... 270
УДАЛЕНИЕ КОМПОНЕНТА....................................... 274
НАСТРОЙКА ПАЛИТРЫ КОМПОНЕНТОВ ............................ 275
ЗАКЛЮЧЕНИЕ................................................ 277
ПРИЛОЖЕНИЕ................................................ 279
ЯЗЫК PASCAL (КРАТКИЙ СПРАВОЧНИК).......................... 279
Структура модуля.......................................... 279
Основные типы данных...................................... 279
Массивы................................................... 281
Запись.................................................... 281
Выбор..................................................... 281
Циклы..................................................... 283
Безусловный переход ...................................... 284
Объявление функции........................................ 285
Объявление процедуры...................................... 285
Встроенные функции и процедуры............................ 285
КОДИРОВКА СИМВОЛОВ В WINDOWS.............................. 287
ПРЕДСТАВЛЕНИЕ ИНФОРМАЦИИ В КОМПЬЮТЕРЕ..................... 289
РЕКОМЕНДУЕМАЯ ДОПОЛНИТЕЛЬНАЯ ЛИТЕРАТУРА................... 291
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ...................................... 293