Uploaded by mvalera45

Delphi Books

advertisement
Федеральное агентство по образованию
Дальневосточный государственный технический университет
( ДВПИ им. В.В. Куйбышева )
Т.Д. Шейкер
РАЗРАБОТКА ПРИЛОЖЕНИЙ В СИСТЕМЕ DELPHI
Рекомендовано Дальневосточным региональным учебнометодическим центром в качестве учебного пособия для студентов
специальностей 071900 «Информационные системы и технологии»,
210100 «Управление и информатика в технических системах»,
220100 «Информатика и вычислительная техника», 220200
«Автоматизированные системы обработки информации и
управления» вузов региона
Владивосток
2006
Одобрено редакционно-издательским советом университета
УДК 681.3.06
Ш
Шейкер, Т.Д. Разработка приложений в системе Delphi: учеб. пособие/
Т.Д. Шейкер. – Владивосток: Изд-во ДВГТУ, 2006 – 172 с. ISBN 5-7596-0587-9
Пособие содержит сведения по созданию приложений различного
характера и уровня сложности в среде визуального программирования Delphi,
даёт лаконичный, хорошо структурированный материал, который необходим
при освоении системы Delphi в процессе выполнения лабораторных работ
студентами специальностей 071900, 210100, 220100, 220200. В пособии
приводится большое количество фрагментов кода, который может быть полезен
как при выполнении лабораторных работ, так и при решении реальных задач.
Методика изложения материала позволяет использовать пособие для
самостоятельной работы, при наличии знаний по основам языка Object Pascal.
Рецензенты: А.Е. Шумский, проф. кафедры менеджмента Дальневосточной гос.
академии экономики и управления, д-р техн. наук;
Г.В. Алексеев, зав. кафедрой информатики и компьютерных
технологий ДВГТРУ (Дальрыбвтуза), д-р физ.-мат. наук, проф.
Отпечатано с оригинал-макета, подготовленного автором
ISBN 5-7596-0587-9
© Т.Д. Шейкер, 2006
© ДВГТУ, изд-во ДВГТУ, 2006
2
ВВЕДЕНИЕ
Системы быстрой разработки приложений, к которым относится Delphi,
существенно облегчают разработку программ. Однако сами эти системы с
каждым годом становятся всё сложнее. Изучение всех возможностей и
особенностей системы Delphi требует значительных усилий, очень больших
затрат времени и постоянной работы в этой среде. Вузовские программы
рассчитаны на знакомство с системой, с используемым в ней языком
программирования и приобретение навыков решения достаточно простых
задач. Студент в процессе обучения должен получить базовые знания, которые
позволят ему в дальнейшем самостоятельно освоить возможности системы,
необходимые в профессиональной деятельности. Следует учитывать, что в
большинстве случаев язык Pascal предварительно не изучается и при освоении
системы Delphi приходится значительное внимание уделять языковым
конструкциям и правилам их использования.
В настоящее время имеется большое количество учебной литературы,
посвящённой системе Delphi и программированию в ней. Кроме того, много
полезной информации можно извлечь из Internet. Всё это очень хорошо, так как
позволяет осваивать дополнительные возможности, знакомиться с опытом
профессиональных программистов. Однако на первых этапах знакомства с
системой и языком программирования трудно найти нужную информацию,
подходящие примеры и рекомендации по целесообразности применения тех
или иных методов решения задач. Существенным является и то, что в
библиотеке нет современных учебников в достаточном количестве. К
сожалению, работа с учебником по программированию в читальном зале мало
эффективна, учебник нужен постоянно при работе за компьютером.
В учебном пособии приведены и систематизированы те сведения, без
которых не обойтись при выполнении лабораторных работ. При этом
предполагается,
что
часть
вопросов
рассматривается
на
лекциях,
практические работы выполняются по изданным ранее указаниям [9].
3
а
1. ПРОЕКТ И УПРАВЛЕНИЕ ПРОЕКТОМ
1.1. Проект Delphi
В среде Delphi разрабатывается проект – набор файлов, из которых состоит
приложение. Рекомендуется файлы, относящиеся к проекту, хранить в
отдельной папке.
В любой проект входит по крайней мере шесть файлов:
• project1.dpr – главный файл проекта, формируется системой при
создании нового приложения;
• unit1.pas – первый модуль (unit) программы, который автоматически
появляется в начале работы;
• unit1.dfm – файл описания формы, используется для сохранения
информации о внешнем виде главной формы;
• project1.res – файл ресурсов, в нём хранятся иконки, растровые
изображения, курсоры. Как минимум, содержит иконку приложения;
• project1.dof – файл опций, является текстовым файлом для сохранения
установок,
связанных
с
данным
проектом
(например
директив
компилятора);
• project1.cfg – файл конфигурации, содержит информацию о состоянии
среды.
Кроме
того,
к
проекту
могут
относиться
файлы
с
картинками,
видеофрагментами, звуками, файлы справочной системы и т.п. Однако
перечисленными элементами управляет сам программист.
Если сохранить проект под другим именем, то кроме файла проекта
изменят название и файлы с расширением res, dof и cfg. Если изменить имя
файла модуля (.pas), то изменится и имя файла описания формы ( .dfm ).
Имена, данные системой по умолчанию, можно изменить. Хорошим стилем
программирования считается использование имён, несущих смысловую
нагрузку.
После компиляции программы получаются файлы с расширениями:
4
dcu – скомпилированные модули;
exe – исполняемый файл;
~pa, ~dp – backup файлы (предыдущие версии).
Помимо модулей, связанных с формой, можно создавать отдельные
модули, которые оформляются по обычным правилам языка Object Pascal
(Delphi), сохраняются в отдельных файлах и имена которых указываются в
разделе uses проекта или тех модулей, в которых они используются.
Главный файл проекта представляет собой текстоый файл, содержащий
программный код, записанный на языке Object Pascal. Этот файл подключает
все используемые программные модули и содержит операторы для запуска
приложения. При создании нового приложения Delphi автоматически создаёт
файл проекта. Код файла проекта, содержащего одну форму, приведён ниже.
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
В разделе uses подключается системый модуль Forms и модуль формы
Unit1.
Название
формы
приводится
в
фигурных
скобках.
Директива
компилятора {$R *.res} подключает к результирующему exe-файлу ресурсы.
Тело программы содержит операторы, которые готовят приложение к
работе (инициализируют), создают форму и начинают выполнение приложения.
По
мере
создания
новых
форм
содержимое
этого
файла
меняется
автоматически. Вручную этот файл корректируется только в особых случаях.
Чтобы увидеть код файла проекта, надо выполнить команду View|Unit
через меню или с помощью кнопки на панели инструментов, а затем в
диалоговом окне выбрать Project1. Окно ViewUnit используется для вывода на
экран кода файла проекта и входящих в него модулей.
5
При создании приложения Delphi генерирует пустую форму, текст модуля
которой приведён ниже.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, Dialogs;
type
TForm1 = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
end.
Модуль начинатся с зарезервированного слова unit, после которого
пишется имя модуля. Имя модуля совпадает с именем файла, в котором он
сохранён.
В интерфейсной секции описываются программные элементы (типы,
переменные,
константы,
процедуры,
функции),
которые
могут
быть
использованы другими модулями программы. Всё, что помещается в секцию
реализации implementation, доступно только в пределах модуля. Помимо
объявлений, в эту секцию включают реализацию всех упомянутых в
интерфейсной части процедур и функций, а также код любых дополнительных
процедур и функций. В общем случае структура модуля имеет вид:
заголовок;
секция интерфейсных объявлений interface;
секция реализации implementation;
секция инициализации initialization;
секция завершения finalization;
терминатор end.
В необязательную секцию инициализации помещают операторы, которые
осуществляют начальную настройку модуля и выполняются один раз при
6
первом обращении к модулю. Необязательная секция finalization содержит
операторы, выполняемые только один раз при любом завершении программы:
нормальном или аварийном. Раздел finalization вводится в программу только
при наличии секции initialization.
1.2. Управление проектом
При старте Delphi автоматически создаёт новый проект. При загрузке
другого проекта (нового или имеющегося на диске) открытый ранее проект
закрывается.
Для
создания
нового
проекта
надо
выполнить
команду
File|New|Application, а для загрузки существующего – File|Open Project.
Рекомендуется, создав новый прект, сразу сохранить его в отдельной папке и в
дальнейшем регулярно выполнять сохранение всех файлов проекта.
Менеджер проекта Project Manager предназначен для управления
проектами и составными частями разрабатываемого приложения. Его можно
вызвать командой View|Project Manager. Менеджер проектов позволяет
работать с группой проектов: можно просматривать, добавлять и удалять
проекты и их составные части. Если необходимо одновременно работать с
несколькими проектами, то их целесообразно объединить в группу.
Окно менеджера проектов разделено на две части. В верхней части
расположены управляющие элементы (раскрывающийся список и кнопки), а в
нижней – перечень проектов и модулей с указанием путей к ним. При
добавлении и удалении проектов и их составных частей автоматически
вносятся изменения в соответствующие файлы.
В группе только один проект является активным. Активизировать проект
можно выбрав его в раскрывающемся списке или с помощью кнопки Activate.
Некоторые из предусмотренных в менеджере проектов операции можно
выполнить другим способом. Так, команда Project|Add to Project добавляет к
проекту новую форму, а команда Project|Remove from Project позволяет
удалить существующую форму.
7
Обозреватель проекта Project Browser позволяет перемещаться по
иерархии
классов,
глобальных
элементов
и
модулей
проекта.
Окно
Обозревателя Exploring открывается командой View|Browser. Оно разделено
на две части: Inspector pane (Панель просмотра) и Details pane (Детальная
панель). Кнопками можно задать один из трёх доступных для просмотра
объектов: глобальные элементы Globals, классы Classes или модули Units.
Получить доступ к параметрам обозревателя проекта можно также через
окно Environment Options (Параметры среды), в котором параметры
обозревателя проекта находятся на вкладке Explorer.
1.3. Репозиторий
Delphi позволяет многократно использовать одни и те же объекты в
качестве шаблонов при дальнейшей разработке приложений. Для хранения
таких объектов используется специальное хранилище Repository. При
разработке приложения можно добавить в него объект из репозитория через
окно New Items, которое вызывается командой File|New|Other. Большое
количество объектов, находящихся в хранилище, распределены по нескольким
страницам: New (базовые элементы), Forms (формы), Projects (проекты),
Dialogs (диалоги), Data Modules (модули данных) и др. Кроме того,
пользователь может помещать в репозиторий свои заготовки.
Для добавления объекта к проекту необходимо выбрать страницу и указать
объект. Объекты можно добавлять к проекту различными способами, в
зависимости от состояния переключателя в нижней части окна:
• Copy – копирование объекта. Изменения, внесённые в проекте в копию
объекта, не влияют на оригинал;
• Inherit – от объекта в хранилище порождается новый объект, который
добавляется к проекту;
• Use – использование объекта из хранилища. Изменение этого объекта в
проекте приводит к изменению объекта в хранилище и во всех проектах,
использующих этот объект аналогичным образом (как Use).
8
Для помещения формы в репозиторий, следует сохранить её в папке
ObjRepos. Затем выполнить команду Add to Repository через контекстное
меню. Если использовать команду Project|Add to Repository, то в репозиторий
будет добавлен проект, а не форма. Проекты из репозитория копируются
целиком, с родительскими классами, что замедляет работу и увеличивает объём
памяти. В диалоговом окне Add to Repository надо записать сведения о
помещаемой в архив форме: название, пояснения, имя автора разработки,
название страницы хранилища.
1.4. Настройка параметров проекта
Установить параметры проекта можно двумя способами:
• в окне Project Options,
• программно.
Проще всего воспользоваться окном задания параметров объекта, которое
открывается командой Project|Options. На странице Forms можно назначить
главную форму приложения и в списке Auto-create forms выбрать формы,
которые
будут
создаваться
одновременно
с
главной.
Главная
форма
открывается первой, и её закрытие приводит к закрытию всего приложения.
На странице Application задают название и иконку, которые будут
отображаться в среде Windows на панели задач, а также файл справки,
подключаемый к проекту. На страницах Compiler и Linker устанавливают
директивы компилятора и компоновщика (редактора связей).
Заданные параметры Delphi автоматически заносит в соответствующие
файлы проекта.
Программное задание параметров (использованием свойств объекта
Application или включением в код директив компилятора и компоновщика)
обладает приоритетом.
9
1.5. Компиляция и выполнение проекта
Компиляция проекта выполняется командой Project|Compile ProjectName
или использованием комбинации клавиш Ctrl+F9. При этом компилируются
все исходные модули, содержимое которых изменялось после последней
компиляции: для каждого программного модуля создаётся файл с расширением
dcu. Затем компилируется файл проекта и компонуется (собирается) из dcuмодулей исполняемый файл, имя которого совпадает с именем файла проекта.
Готовый к использованию файл может быть приложением (*.exe) или
динамически загружаемой библиотекой (*.dll).
Выполнить компиляцию можно на любой стадии разработки проекта. Так
как
в
процессе
компиляции
проверяется
синтаксис
программы,
то
рекомендуется при формировании кода выполнять эту операцию регулярно.
Кроме обычной компиляции, можно командой Project|Build ProjectName
выполнить сборку (построение) проекта. В этом случае перекомпилируются все
модули проекта, для которых доступны исходные тексты.
Готовый проект можно запустить на выполнение в среде Delphi либо в
среде Windows. Выполнение приложения из среды Delphi задаётся командой
Run|Run (клавишей F9 или кнопкой с зелёным тругольником) и имеет
следующие особенности:
• нельзя запустить несколько копий приложения;
• при возникновении исключительных ситуаций сначала выводятся
сообщения Delphi, а затем – приложения;
• для аварийного завершения приложения (например при зацикливании)
необходимо выполнить команду Run|Program Reset;
• для продолжения разработки проекта приложение надо закрыть.
ВОПРОСЫ ДЛЯ САМОКОНТРОЛЯ
1. Почему Delphi называют интегрированной средой разработки?
10
2. Можно ли переименовывать файлы модулей, входящие в проект,
средствами операционной системы?
3. Что произойдёт, если сохранить главный файл проекта project1.dpr под
другим именем?
4. Что в Delphi используется для обработки программ: интерпретатор или
компилятор?
5. Какую структуру имеет модуль?
6. Можно ли в среде Delphi одновременно открыть два проекта?
7. Как удалить из проекта форму?
8. Как вывести на экран Project Manager?
9. Для чего предназначен Project Browser?
10. Что такое Repository?
11. Как добавить в хранилище созданную форму?
12. Назовите причину, по которой может измениться объект, помещённый в
репозиторий.
13. Какое расширение может иметь исполняемый файл, полученный после
обработки проекта?
14. В
чём
отличие
команд
Project|Compile
ProjectName
и
Project|Build ProjectName?
15. Какая форма по умолчанию становится главной формой проекта?
16. Как сделать главной нужную форму?
17. Как настроить панель инструментов главного окна Delphi?
18. Как подсоединить к проекту иконку?
19. В процессе тестирования проект был запущен на выполнение из среды
Delphi. Проверялось поведение проекта при некорректном вводе данных. В
программе была предусмотрена обработка такой ситуации: должно было
появиться окно с сообщением об ошибке и предложением повторить ввод.
Однако появилось окно с другим сообщением, причём на английском языке.
Почему?
11
2. СОЗДАНИЕ ПРИЛОЖЕНИЯ
2.1. Хорошее приложение
Понятие «хорошее приложение» зависит от многих факторов и постоянно
меняется. Можно считать хорошим приложение, которое:
• имеет простой, удобный, интуитивно понятный интерфейс, со всеми
присущими Windows атрибутами: окнами, кнопками, меню и т.д.;
• управляется как мышью, так и клавиатурой;
• отказоустойчиво, корректно обрабатывает любые ошибки пользователя;
• работает быстро;
• имеет хорошую справочную систему;
• обеспечивает обмен данными с другими приложениями;
• может (при необходимости) использовать средства мультимедиа;
• может работать с базами данных;
• разрабатывается быстро.
2.2. Этапы создания приложения
Разработка
приложения Delphi состоит из двух этапов: создания
интерфейса приложения и определения его функциональности.
Интерфейс определяет способ взаимодействия пользователя и приложения:
какие применяются окна, каким образом пользователь управляет приложением.
Интерфейс
создаётся
путём
размещения
на
форме
компонентов.
Функциональность определяется процедурами, которые выполняются при
возникновении
определённых
событий,
происходящих
при
действиях
пользователя. При создании приложения необходимо:
• уяснить задачу, которую надо решить;
• разработать эскизы того, что должно появляться на экране компьютера;
• написать сценарий работы будущей программы;
• разработать (при необходимости) алгоритмы процедур, реализующих
предусмотренные в сценарии действия;
12
• реализовать проект;
• выполнить тестирование и отладку;
• подготовить проект к распространению.
2.3. Создание интерфейса приложения
Интерфейс приложения определяется компонентами, которые разработчик
выбирает из палитры компонентов и помещает на форму. При проектировании
интерфейса приложения действует принцип WYSIWYG (What You See Is What
You Get) – что видите, то и получите. Так как компонент очень много, то они в
палитре распределены по страницам. Для того чтобы поместить компонент на
форму, необходимо перейти на нужную страницу, щёлкнуть мышью по
выбранному компоненту в палитре, а затем – в нужном месте формы. Другой
способ задания компонента предполагает использование общего перечня всех
компонент, который открывается командой View|Component List.
После добавления компонента на форму можно изменить его расположение
и размеры мышью. Для некоторых компонентов предусмотрено задание
положения на переднем или заднем плане. Для размещения на форме
нескольких одинаковых компонентов следует сначала нажать клавишу Shift,
затем выбрать в палитре компонент, а потом щёлкнуть мышью по форме
нужное число раз. Закончить действия с компонентом можно, щёлкнув по
кнопке со стрелочкой, либо выбрав другой компонент.
По умолчанию компоненты выравниваются на форме по линиям сетки, шаг
сетки равен 8 пикселям, и сетка видна на этапе проектирования. При желании
можно изменить шаг сетки или не использовать её вовсе (при необходимости
разместить элементы очень плотно). Для задания нужных параметров следует
выполнить команду Tools|Environment Options (Средства|Параметры среды) и
в открывшемся окне перейти на вкладку Designer.
Возможна подгонка расположения компонента с точностью до пикселя с
помощью клавиш со стрелками: при нажатой клавише Ctrl происходит
смещение компонента, а при нажатой клавише Shift – изменение размеров.
13
Выравнивать расположение компонентов можно вручную, либо выделив
группу компонентов и воспользовавшись командой Edit|Align или командой
View|Alignment Palette.
Работать с компонентами можно через буфер. Предварительно нужные
компоненты следует выделить, а затем применить команды меню Edit. Другой
способ работы с компонентами предлагает окно Object TreeView, которое
впервые появилось в Delphi 6. Дерево объектов отображает все компоненты и
связи между ними. Используя дерево объектов, очень удобно перемещать
компоненты из одного контейнера в другой, так как эта операция выполняется
простым перетаскиванием компонента мышью.
Компоненты
делятся
на
визуальные
и
невизуальные.
Визуальные
компоненты выглядят одинаково на этапах проектирования и выполнения
приложения. К визуальным компонентам относятся форма, кнопки, списки,
переключатели и т.п. Невизуальные компоненты либо не видны на этапе
выполнения (например таймер), либо их внешний вид отличается от того,
который был на этапе дизайна (например меню).
При размещении компонента на форме Delphi автоматически вносит
изменения в файл модуля и в файл описания формы. В файле модуля в
описании класса формы добавляется строчка с описанием типа компонента.
Описания всех типов начинаются с буквы Т. Если на форму помещены три
кнопки Button и компонент PaintBox, то в объявлении класса формы получим:
type
TForm1 = class(TForm)
PaintBox1: TPaintBox;
Button1: TButton;
Button2: TButton;
Button3: TButton;
private
{ Private declarations }
public
{ Public declarations }
end;
Для помещённых на форму компонентов непосредственно на форме или в
окне Инспектора объектов задают значения свойств. Сначала выбирают
14
нужный компонент из списка в верхней части Инспектора объектов или
щёлкнув по нему на форме, а затем задают значения свойств. Следует помнить,
что некоторые свойства нельзя изменить на этапе дизайна, они доступны
только во время выполнения программы. Такие свойства можно изменять
программным путём. Свойства же, перечисленные в инспекторе объектов,
разрешено изменять как на этапе проектирования, так и программно во время
работы приложения (run time).
Выбрать (сделать активным) можно один или несколько компонентов. Для
выбора компонента достаточно щёлкнуть по нему мышью, при этом
появляются точки растяжки. Свойства в Инспекторе объектов задаются только
для активных объектов. Если требуется выделить группу компонентов, то
можно воспользоваться одним из двух методов:
• нажать кнопку Shift и щёлкнуть мышью на нужных компонентах;
• нажать на левую кнопку мыши при расположении указателя вне
компонентов и протащить мышь по экрану, пересекая нужные
компоненты.
Для выделенных компонентов в окне инспектора объектов отображаются
одинаковые свойства. Задание свойства относится ко всем выделенным
компонентам.
Чтобы удалить компонент, его надо отметить, а затем нажать на клавишу
Delete. Перемещение и изменение размеров компонентов проще всего
выполнять перетаскиванием и растяжкой мышью. Если же требуется
установить точные значения свойств, определяющих размеры и положение
компонентов, то это удобнее делать в окне Инспектора объектов.
Многие свойства компонентов имеют значения по умолчанию, например,
Name, Caption, Visible, Color. Свойство Name определяет имя, под которым
компонент известен в программе. Свойство Caption – это заголовок.
Первоначально Caption получает значение от свойства Name. В дальнейшем
эти свойства можно изменить. Строка, определяющая свойство Caption, может
15
отсутствовать, а имя Name должно быть задано обязательно. Например, для
кнопки Button задано имя Button1, а свойство Caption, определяющее надпись
на кнопке, имеет значение Выполнить. При большом числе однотипных
компонент им следует присваивать информативные имена.
Свойство Visible имеет тип ТBoolean, определяет видимость компонента.
Если это свойство имеет значение true, то компонент видим.
Изменения свойств на этапе проектирования называют статическими.
Статические изменения выполняют в окне Инспектора объектов. Изменения в
ходе выполнения программы называют динамическими. Для реализации
динамического изменения свойства в каком-либо обработчике события задают
новое значение свойства с помощью оператора присваивания. Например, чтобы
компонент стал невидим во время выполнения программы, надо изменить
значение свойства Visible на false:
Label1.Visible:= false;
Или во время выполнения программы можно изменить надпись на кнопке:
Button1.Caption:='Выполнить';
Если на форме выделено несколько компонентов, то в Инспекторе
объектов доступны свойства, общие для всех этих компонентов. При этом
сделанные изменения относятся ко всем выделенным компонентам.
Для задания свойств в Инспекторе объектов действуют редакторы свойств,
которые могут быть нескольких типов:
• текстовый – свойство вводится и редактируется как строка символов.
Delphi интерпретирует строку (в зависимости от свойства) как данные
числового или строкового типа;
• перечисляемый – свойство выбирается из списка. Список раскрывается
при щелчке мышью по кнопке со стрелочкой, которая появляется при
преходе в область значений свойства (например свойство Visible);
• множественный – свойство представляет собой комбинацию значений из
предлагаемого списка. Слева от названия такого свойства расположен
16
значок +. Список, содержащий возможные значения, открывается
двойным щелчком по названию свойства (свойство BorderIcons);
• объект – свойство является объектом, то есть содержит другие свойства,
которые могут редактироваться самостоятельно. Например, свойство
Font включает Color, Name, и др. Такое свойство слева от названия
имеет символ + и задание значений может выполняться как для
множественного свойства. Кроме того, если поместить курсор в область
значения свойства, то появится кнопка с точками, щелчок по которой
откроет окно для задания свойств. Пользоваться диалоговым окном для
редактирования свойств удобнее, чем выбирать их из списка.
2.4. Определение функциональности проекта
Функциональность приложения определяется реакциями на возможные
события. Для этого разрабатывают процедуры, которые вызываются при
наступлении соответствующих событий.
Для создания процедуры обработки события (обработчика), необходимо
выделить компонент и перейти в Инспекторе объектов на страницу событий
(Events), на которой перечислены все возможные события компонента. Если
выполнить двойной щелчок в области значения нужного события, то Delphi
автоматически создаст в модуле формы заготовку процедуры-обработчика. На
передний план переместится окно Редактора кода и курсор будет помещён в то
место процедуры, где программист должен написать код. При этом в описание
класса формы будет добавлен заголовок процедуры-обработчика. Название
обработчика образуется добавлением к имени компонента названия события
без приставки on. Например, TForm1.Button1Click. Если в Инспекторе
объектов изменить имя компонента, то произойдёт автоматическое
переименование процедуры во всех файлах проекта.
Для
удаления
обработчика
достаточно
удалить
код,
написанный
программистом. Тогда при сохранении или компиляции модуля обработчик
будет удалён из всех файлов проекта. Не рекомендуется удалять обработчики
17
вручную. Следует помнить, что при удалении компонента все его обработчики
остаются в модуле формы.
Разрешено вместо создания нового обработчика использовать уже
существующий. В этом случае надо щёлкнуть в области значения события и
выбрать из списка подходящую процедуру. Таким образом, одну процедуру
можно связать с несколькими событиями, в том числе для разных компонент.
Такая процедура называется общим обработчиком и вызывается при
возникновении любого связанного с ней события (например одни и те же
действия выполняются через меню и кнопкой).
Среди множества событий, предусмотренных для компонента, выделяют
одно, наиболее часто используемое. Создать заготовку обработчика такого
события можно двойным щелчком по расположенному на форме компоненту.
2.5. События и их обработка
О всех происходящих в системе событиях Windows посылает сообщения
приложению в виде записи определённого типа. Источником этих сообщений
может быть драйвер устройства (например клавиатуры или мыши), ядро
системы, другие приложения. Delphi преобразует сообщения в свой формат и
предлагает специальные методы для обработки сообщений. Однако в
большинстве случаев можно обойтись без непосредственной обработки
сообщений Windows, так как Delphi предоставляет более простой способ работы
с сообщениями путём использования событий.
Событие
представляет
собой
свойство
процедурного
типа,
предназначенное для обеспечения реакции на те или иные действия. Задание
значения
этому
свойству
(событию)
означает
определение
метода,
вызываемого при наступлении события. События Delphi имеют различные
типы, самым простым из которых является TNotifyEvent, характерный для
уведомляющих событий:
type TNotifyEvent = procedure (Sender: TObject) of object;
18
Единственный параметр Sender указывает объект-источник события. Более
сложные события имеют кроме Sender и другие параметры, например событие,
связанное с перемещением мыши, передаёт координаты указателя.
Так как события являются свойствами, их значения можно изменять во
время выполнения приложения, то есть изменять реакцию объекта на одно и то
же событие. При этом разрешается назначать обработчик события одного
объекта, другому объекту или его событию. Обязательное условие – совпадение
типов событий. Такая возможность обеспечивается неявным параметром Self,
который всегда передаёт методу указатель на вызвавший его экземпляр
класса.
2.6. Формирование кода
Код пишется в окне Редактора кода, который имеет встроенные средства,
существенно
облегчаюшие
работу.
К
инструментальным
средствам,
используемым при записи кода, относятся: Code Insight, Code Explorer, Object
Browser, механизм навигации в коде.
Возможности Подсказчика Code Insight целесообразно использовать даже
в самых простых программах, так как это сокращает время записи и, главное,
гарантирует корректность введённых выражений.
Если записать имя компонента, поставить точку и немного подождать, то
появится длинный список всех свойств и методов класса, к которому
принадлежит компонент. Чтобы быстрее найти нужное название, желательно
записать первые символы. Затем надо выбрать строку щелчком мыши и нажать
на клавишу Enter (или дважды щёлкнуть левой кнопкой мыши по нужной
строке): соответствующее имя будет вставлено в код. Повторный вывод
Подсказчика
выполняется
комбинацией
клавиш
Ctrl+пробел.
Эта
же
клавиатурная комбинация позволяет вывести Code Insight на экран при
отключении автоматического режима работы.
По умолчанию строки списка упорядочены по категориям. При желании их
можно отсортировать по алфавиту, выбрав команду Sort by Name из
19
контекстного меню. Комбинацию клавиш Ctrl+пробел можно использовать
после записи переменной, оператора присваивания, в пустой строке. Во всех
случаях появится подсказка. Правда, иногда проще написать нужный текст, чем
искать его в очень длинном списке.
Если Code Insight работает в автоматическом режиме, то при записи
процедур и функций после того, как поставлена открывающаяся круглая
скобка, появится список параметров и их типов. Повторный вывод подсказки
выполняется комбинацией клавиш Shift+Ctrl+пробел.
Иногда полезно воспользоваться имеющимися в Code Insight шаблонами
стандартных структур языка Object Pascal. Перечень шаблонов выводится
клавишами Ctrl+J. Например, для оператора case один из шаблонов имеет вид:
case of
: ;
: ;
end;
Для быстрого перемещения по коду можно использовать закладки, которые
устанавливаются командой контекстного меню Toggle Bookmark. Переход на
нужную закладку выполняется командой контекстного меню Goto Bookmarks.
Очень удобно организован переход между объявлениями методов в
интерфейсной секции и их реализацией. Для этой цели используются клавиши
Ctrl+Shift и клавиша со стрелкой вверх или вниз (в зависимости от нужного
направления перемещения).
2.7. Организация взаимодействия форм
В операционной системе Windows можно выделить пять видов окон:
• окна папок;
• окна приложений;
• диалоговые окна;
• окна справочной системы;
• окна сообщений.
20
Все виды окон представляют собой контейнеры. При разработке
приложений,
функционирующих
под
Windows,
управлением
работа
организуется в принятых в этой операционной системе окнах.
Стандартное окно в Windows имеет заголовок, кнопки для вызова
системного (оконного) меню, кнопки сворачивания, разворачивания, закрытия
окна и рамки, позволяющие плавно изменять размеры окна.
Диалоговые окна предназначены для задания параметров, уточнения
характеристик или действий. Диалоговыми окнами пользуются, когда надо чтото настроить или изменить. Диалоговые окна стандартизованы (но не
стандартны!) за счёт применения в них типовых элементов управления.
Диалоговые окна, как правило, имеют другой состав команд системного меню,
не имеют средств для плавного изменения размеров, не содержат кнопок
сворачивания и разворачивания окна.
Среда Windows поддерживает два режима отображения окон – модальный и
немодальный. Диалоговые панели обычно работают в модальном режиме.
Модальное окно должно быть закрыто перед обращением к любому
другому
окну
данного
приложения.
Модальное
окно
перехватывает
управление, и пока оно не будет закрыто, попытка перейти в другое окно
приложения
блокируется
Windows,
операционная
система
выдаёт
предупреждающий сигнал. Запрет перехода в другое окно при незакрытом
модальном окне относится только к текущему приложению, пользователь
может активизировать любое другое приложение Windows. Программно
возможен доступ к любому элементу приложения, несмотря на наличие
открытого в текущий момент времени модального окна.
Если форм в приложении несколько, то одна из них является главной.
Главная форма отображается при запуске приложения, остальные создаются, но
отображаются по запросу. Закрытие главной формы приводит к завершению
работы приложения. По умолчанию главной назначается форма, созданная
первой, но при необходимости главной можно назначить другую форму.
Задание главной формы выполняется в окне Project Options на вкладке Forms.
21
Если одна форма выполняет действия с другой формой или с
расположенными
на
ней
элементами,
то
в
списке
uses
раздела
implementation модуля первой формы должна быть ссылка на модуль второй
формы.
Допустим, создана главная форма main и дополнительная форма second.
Чтобы из формы main можно было открыть форму second или получить
какие-либо сведения с формы second, надо дополнительную форму
подсоединить к главной. Для этого следует:
• активизировать главную форму;
• выполнить команду File|Use Unit. В окне Use Unit выбрать имя файла
модуля нужной формы (second).
После этого в секции implementation модуля основной формы появится
строка: uses second;
Если форма second должна получать сведения с главной формы main, то
форму main надо подсоединить к second. При наличии нескольких
дополнительных форм, их надо связать друг с другом в соответствии с
функциональностью проекта.
После того как дополнительные формы связаны с главной, необходимо
организовать их вызов. В простейшем случае можно на главной форме
установить кнопки, с помощью которых открывать нужные окна. Для
обработки события OnClick, наступающего при нажатии на кнопку вызова
дополнительного окна, используются методы Show и ShowModal. Например,
записанный в обработчике события OnClick метод Form2.Show откроет
обычное окно, заданное формой Form2, а метод Form3.ShowModal откроет
модальное окно.
22
ВОПРОСЫ ДЛЯ САМОКОНТРОЛЯ
1. Что понимают под разработкой интерфейса приложения?
2. Что понимают под функциональностью приложения?
3. Назовите этапы создания приложения.
4. Как найти нужную компоненту, если Вы не знаете, на какой странице она
расположена?
5. Как изменить шаг сетки, используемой для позиционирования компонентов
на форме?
6. Как можно задать точное расположение компонентов?
7. Какие используются команды для выравнивания группы компонент?
8. Почему некоторых свойств нет в Инспекторе объектов?
9. Можно
ли
переместить
компонент
с
одной
формы
на
другую
перетаскиванием мышью?
10. Можно ли переместить компонент из одного контейнера в другой
перетаскиванием мышью?
11. Для чего используется Object TreeView?
12. Почему свойство Name обязательно должно иметь какое-либо значение?
13. Для чего предназначен Инспектор объектов? Как пользоваться Инспектором
объектов ?
14. В каком случае можно задать значение свойства сразу нескольким
компонентам?
15. Как создать заготовку процедуры обработчика события?
16. Как формируется имя процедуры-обработчика?
17. Что произойдёт, если в инспекторе объектов изменить свойство Name
компонента, для которого созданы обработчики событий?
18. Какой параметр всегда присутствует в процедурах обработчиках событий?
19. Какие инструментальные средства используются при создании кода
программы?
20. Какие возможности предоставляет Code Insight для формирования кода?
23
3. ФОРМА
Форма является основным интерфейсным элементом в Delphi. С точки
зрения Windows форма представляет собой окно. С точки зрения Delphi форма –
это визуальный компонент, играющий роль контейнера, который содержит
другие компоненты, определяющие функциональность приложения.
3.1. Свойства формы
У формы достаточно много свойств. Первоначально Delphi устанавливает
свойства формы в значения по умолчанию. Изменить свойства формы можно в
процессе проектирования (в Инспекторе объектов) или во время выполнения
приложения. Динамическое изменение свойств осуществляется программно,
путём внесения в исходный текст программы соответствующих операторов.
При работе с формой на уровне исходного кода можно получить доступ к
свойствам, которые отсутствуют в Инспекторе объектов.
Свойство Caption определяет заголовок окна. Изменить цвет, шрифт,
размеры шрифта заголовка окна в Delphi нельзя. Это системные параметры
Windows, которые задаются в свойствах экрана.
Разновидности форм определяются значениями свойства FormStyle и
разнообразием заготовок, хранящихся в репозитории. Свойство FormStyle
определяет, какой пользовательский интерфейс будет использован: Multiple
Document Interface (MDI) – многодокументный или Single Document Interface
(SDI) – однодокументный. Это свойство может принимать значения:
fsMDIChild – дочернее окно MDI-приложения;
fsMDIForm – главное окно MDI-приложения;
fsNormal – обычное окно (значение по умолчанию):
fsStayOnTop – окно, расположенное поверх других окон на экране.
Если применяется SDI-интерфейс, то каждая форма (даже если их
несколько) существует в виде отдельного независимого окна. Одно из окон
является главным, но не содержит других окон. В SDI приложении все формы
имеют в свойстве FormStyle значение fsNormal. Иногда устанавливается
24
значение fsStayOnTop, чтобы окно всегда располагалось поверх других окон,
даже если приложение не активно.
MDI-интерфейс предполагает использование родительского окна, которое
включает одно или несколько дочерних окон. Дочерние окна ограничены
областью родительского окна и не могут выходить за его пределы. Дочерними
окнами можно управлять из главного окна.
Стиль рамки задаётся свойством BorderStyle, которое имеет значения:
bsDialog – неизменяемая в размерах рамка, свойственная окнам диалога;
bsSingle – неизменяемая в размерах рамка обычного окна;
bsNone – окно без рамки и заголовка;
bsSizeable – изменяемая в размерах рамка обычного окна;
bsToolWindow
–
рамка
аналогична
bsSingle,
но
окно
имеет
уменьшенный заголовок (целесообразно использовать для служебных окон);
bsSizeToolWin – рамка аналогична bsSizeable, но с уменьшенным
заголовком.
Обычно для окантовки формы используется значение bsSizeable. При
этом окно имеет стандартную изменяемую рамку, заголовок, системное меню,
кнопки сворачивания, разворачивания и закрытия окна. Если значение свойства
BorderStyle
предполагает
наличие
заголовка,
то
можно
свойством
булевского типа BorderIcons задать нужные системные элементы окна.
3.2. События формы
В этом разделе рассматриваются события, характерные только для формы.
Событие OnCreate происходит при создании формы. В обработчике этого
события обычно устанавливают начальные значения для свойств формы и
помещённых на неё компонентов, запрашивают у Windows необходимые
ресурсы и выполняют другие действия, которые следует совершить до вывода
формы на экран.
25
Событие OnShow происходит после того, как форма была создана, но перед
тем, как она становится видимой.
Событие OnActivate происходит, когда пользователь переключается на
форму, например при щелчке по форме мышью. Событие OnDeactivate
наступает, когда форма теряет активность.
Событие OnHide происходит перед тем, как форма становится невидимой.
Событие OnCloseQuery наступает при попытке закрыть форму. Действие
задаётся пользователем (кнопка Close) или программно (вызван метод Close).
В
обработчик
события
передаётся
булевский
параметр
CanClose,
разрешающий или запрещающий действительное закрытие формы.
Событие OnClose происходит после OnCloseQuery, непосредственно
перед закрытием формы.
Событие OnDestroy происходит при разрушении формы. Обработчик
этого события освобождает ресурсы и выполняет заданные действия до того,
как форма будет разрушена.
3.3. Создание форм разного вида
Существует возможность создавать непрямоугольные окна. За внешний
вид формы отвечает регион. Чтобы воспользоваться регионом, необходимо в
обработчике события OnFormCreate выполнить действия:
• объявить переменную типа HRgn;
• создать регион функцией CreateRectRgn (для прямоугольного региона)
или CreateEllipticRgn (для эллиптического региона);
• установить этот регион для окна функцией SetWindowRgn.
Например, создадим форму в виде окружности.
procedure TfmCircle.FormCreate(Sender: TObject);
Var Region:HRgn;
begin
Region:=CreateEllipticRgn(30,30,400,400);
SetWindowRgn(fmCircle.Handle,Region,true)
end;
26
Для создания более сложных форм используется объединение нескольких
регионов с помощью функции CombineRgn:
CombineRgn (Rez, A, B: HRgn, fmCombineMode: integer): integer;
где Rez – регион, получаемый после объединения,
A, B – исходные регионы,
fmCombineMode – режим объединения.
Режим объединения задаёт правила, по которым происходит получение
результата:
Rgn_AND– создаёт регион, являющийся пересечением исходных регионов;
Rgn_COPY – создаёт копию региона A;
Rgn_DIFF – вычитает из A B;
Rgn_OR – объединяет А и B;
Rgn_XOR – исключает из объединения А и B зону перекрытия.
При создании приложений с окнами произвольной формы необходимо
предусмотреть
возможность
закрытия
и
перемещения
окна,
так
как
традиционные элементы управления отсутствуют. Для закрытия окна можно
добавить кнопку Выход или создать соответствующий обработчик, например
для события OnDblClick. Для обеспечения возможности перемещения окна
мышью целесообразно создать процедуру, определяющую щелчок по любой
области окна как щелчок по строке заголовка.
В качестве примера приведён код создания прямоугольной формы с
круглым отверстием и кнопкой для закрытия.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls;
type
TfmComby = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
var
fmComby: TfmComby;
27
implementation
{$R *.dfm}
procedure TfmComby.FormCreate(Sender: TObject);
Var A,B:HRgn;
begin
A:=CreateRectRgn(20,20,400,400);
B:=CreateEllipticRgn(125,125,285,285);
CombineRgn(A,A,B,Rgn_DIFF);
SetWindowRgn(fmComby.Handle,A,true)
end;
procedure TfmComby.Button1Click(Sender: TObject);
begin
Close;
end;
end.
ВОПРОСЫ ДЛЯ САМОКОНТРОЛЯ
1. Почему средствами Delphi нельзя изменить шрифт заголовка окна?
2. Какое значение имеет по умолчанию свойство FormStyle?
3. Какой пользовательский интерфейс чаще используется: MDI или SDI ?
4. Поясните принцип организации многопользовательского интерфейса.
5. Какое окно появится на экране, если заданы приведённые ниже свойства?
form1.BorderStyle:=bsSingle;
form1.BorderIcons:=[biSystemMenu, biHelp];
6. В каком из приведённых вариантов будет присутствовать кнопка для
сворачивания окна:
1) form1.BorderStyle:=bsNone;
2) form1.BorderStyle:=bsNone;
form1.BorderIcons:=[biSystemMenu, biMinimize];
3) form1.BorderStyle:=bsSizeable;
form1.BorderIcons:=[biSystemMenu, biMinimize];
4) form1.BorderStyle:=bsSizeable;
form1.BorderIcons:=[biMinimize];
5) form1.BorderStyle:=bsDialog;
form1.BorderIcons:=[biSystemMenu, biMinimize];
6) form1.BorderStyle:=bsDialog;
7. В обработчике какого события задают программно размеры формы?
28
4. КОМПОНЕНТЫ
4.1. Общие свойства управляющих элементов
Состояние компонента описывается его свойствами, которые определяют,
как компонент отображается на экране и как функционирует. Свойства бывают
изменяемые (для чтения и записи) и неизменяемые (только для чтения). В
зависимости от времени установки разделяются на свойства времени
проектирования и времени выполнения. Первые устанавливаются в Инспекторе
объектов и определяют начальное состояние компонента. Вторая группа – это
свойства, которые не отображаются в инспекторе объектов, управлять ими
можно только программно. Во время выполнения приложения свойства могут
быть изменены операторами программы, соответственно изменится вид и
поведение компонента.
Управляющие элементы пользовательского интерфейса подразделяются на
управляющие элементы-окна и рисуемые управляющие элементы. Разница
принципиальная. Управляющие элементы-окна способны получать фокус ввода
(Button, BitBtn, Edit, CheckBox, GroupBox и др.). Некоторые из этих окон
могут содержать другие управляющие элементы (например, GroupBox,
PageControl)
и
называются
владельцами
(контейнерами).
Изображает
управляющие элементы-окна операционная система Windows.
Рисуемые управляющие элементы (Label, Image, Shape, Bevel и др.) не
являются окнами, не могут получать фокус ввода и содержать другие
компоненты. Их отрисовку выполняет Delphi.
Местоположение на форме или внутри контейнера задаётся координатами
левого верхнего угла Top и Left. Горизонтальные в вертикальные размеры
определяют свойства Width, Height.
Заголовок Caption представляет собой текстовую строку, которая может
содержать управляющий символ & (амперсанд). Следующий за амперсандом
символ отображается подчёркнутым, его используют для активизации
управляющего элемента с помощью клавиатуры.
29
Цвет Color может быть выбран произвольно или взят у своего владельца.
Это
определяется
свойством
ParentColor.
Если
значение
свойства
ParentColor равно true, то изменение цвета владельца приводит к
автоматическому изменению цвета Color.
Внешний вид курсора мыши Cursor можно выбрать из предлагаемого
набора. По умолчанию курсор имеет вид стрелки.
Свойство Enabled определяет доступность компонента для пользователя.
Если имеет значение true, то компонент доступен. Недоступные компоненты
отображаются блекло.
Font – сложное свойство, определяющее шрифт. Параметры шрифта
задаются вложенными свойствами Color, Name, Size, Style, Height. Шрифт
может быть независимым или определяться шрифтом владельца, в зависимости
от свойства ParentFont логического типа.
HelpContext содержит номер темы в файле справочной системы. Для
получения контекстной справки следует сфокусировать компонент и нажать на
клавишу F1. Если HelpContext имеет значение 0, то справка выводится по
номеру темы владельца.
Свойство Hint определяет строку подсказки. Если задержать на
компоненте
курсор
мыши,
может
появиться
всплывающая
подсказка.
Разрешение или запрет на вывод всплывающей подсказки задаётся свойством
логического типа ShowHint. В свою очередь, ShowHint может зависеть от
разрешения на вывод подсказки у владельца. Это определяется значением
свойства ParentShowHint. Если ParentShowHint равно true, то запрет
подсказки
для
владельца
автоматически
приводит
к
запрету
для
рассматриваемого компонента.
Свойство PopupMenu позволяет привязать к управляющему элементу
контекстное (всплывающее меню), которое выводится на экран щелчком по
компоненту правой кнопкой мыши.
30
TabOrder – порядковый номер компонента в пределах владельца. Задаёт
номер очереди для получения фокуса ввода.
TabStop – определяет возможность получения компонентом фокуса ввода.
Если значение TabStop равно true, то компонент находится в очереди.
Свойство Visible управляет видимостью компонента. Если значение
Visible равно true, то компонент виден, иначе – скрыт.
В разделе 4.3. приводятся те свойства компонентов, которые определяют
их функциональность. Для получения более полных сведений следует
обратиться к справочной системе или литературным источникам.
4.2. Общие события управляющих элементов
События обеспечивают интерактивность компонентов. Так как событий
много, то их принято подразделять на группы. Наиболее часто используются
события, относящиеся к группам, задающим действия:
• выбор элемента управления;
• перемещение указателя мыши;
• вращение колеса мыши;
• нажатие клавиш клавиатуры;
• получение или потеря элементом фокуса ввода;
• перемещение объектов методом перетаскивания.
Событие OnClick – выбор элемента управления; возникает при щелчке по
управляющему элементу левой кнопкой мыши. Для некоторых компонентов
это событие может возникнуть и при других способах нажатия элемента
управления. Например, для кнопки Button, находящейся в фокусе ввода,
событие OnClick можно задать с помощью клавиш «пробел» или Enter. При
разработке приложений это событие используется чаще других.
При щелчке любой кнопкой мыши генерируются еще два события:
OnMouseDown и OnMouseUp. Первое возникает при нажатии кнопки мыши,
когда курсор находится на компоненте, а второе – при отпускании кнопки.
31
Событие OnDbClick – двойной щелчок по компоненте левой кнопкой
мыши.
При перемещении указателя мыши над компонентом периодически
генерируется
событие
OnMouseMove,
что
позволяет
реагировать
на
перемещение указателя. Это событие имеет тип TMouseMoveEvent, который
описан следующим образом:
type TMouseMoveEvent=procedure(Sender:TObject;Shift:TShiftState;
x,y:Integer);
Параметр Sender указывает, над каким элементом управления находится
указатель мыши, а параметры х и y определяют координаты указателя
относительно этого элемента управления. Параметр Shift в зависимости от
использования клавиш Alt, Ctrl, Shift и кнопок мыши может принимать
значения:
ssShift – нажата клавиша Shift;
ssAlt – нажата клавиша Alt;
ssCtrl – нажата клавиша Ctrl;
ssLeft –- нажата левая кнопка мыши;
ssMiddle – нажата средняя кнопка мыши;
ssDouble – выполнен двойной щелчок мышью.
При нажатии любой из указанных клавиш к параметру Shift добавляется
соответствующее значение. Например, если нажата комбинация клавиш
Shift+Ctrl, то значением параметра Shift является [ssShift, ssCtrl].
Если не нажата ни одна клавиша, то Shift принимает пустое значение [].
Для примера поместим на форму компоненты Label и Shape. С помощью
компоненты Shape нарисуем окружность, задав свойству Shape значение
stCircl. Для компоненты Shape определим событие OnMouseMove и в
обработчике этого события сформируем надписи, соответствующие четверти,
над которой перемещается указатель мыши. Для вывода результата будем
использовать свойство Caption компонента Label. Если же действия
выполняются при нажатой клавише Ctrl, то выведем текст «Окружность».
32
procedure TForm1.Shape1MouseMove(Sender: TObject; Shift:
TShiftState; X, Y: Integer);
begin
if Shift= [ssCtrl] then Label1.Caption:='Окружность' else
begin
if (x<Shape1.Width div 2) and (y< Shape1.Height div 2)
then Label1.Caption:='Вторая четверть';
if (x>Shape1.Width div 2) and (y< Shape1.Height div 2)
then Label1.Caption:='Первая четверть';
if (x<Shape1.Width div 2) and (y> Shape1.Height div 2)
then Label1.Caption:='Третья четверть';
if (x>Shape1.Width div 2) and (y> Shape1.Height div 2)
then Label1.Caption:='Четвёртая четверть';
end;
end;
События OnMouseWheel, OnMouseWheelDown, OnMouseWheelUp связаны
с вращением колеса мыши. При вращении колеса мыши вперед и назад
генерируются
соответственно
события
OnMouseWheelDown
и
OnMouseWheelUp. В процессе вращения колёсика при расположении указателя
мыши над визуальным компонентом непрерывно вырабатывается событие
OnMouseWheel.
Событие OnEnter – получение компонентом фокуса ввода. При потере
фокуса ввода генерируется событие OnExit. Эти события не возникают при
переключении между формами и приложениями. Поместим на форму редактор
Edit и метку Label, для которой в свойстве Visible установим значение
false. При получении компонентой Edit фокуса ввода будем выводить метку
на экран, а при потере фокуса – делать её невидимой.
procedure TForm1.Edit1Enter(Sender: TObject);
begin
Label2.Visible:=true;
end;
procedure TForm1.Edit1Exit(Sender: TObject);
begin
Label2.Visible:=false;
end;
При использовании клавиатуры генерируются события OnKeyDown
OnKeyPress, OnKeyUp. Событие OnKeyDown происходит при нажатии любой
клавиши, когда элемент находится в фокусе ввода. При отпускании нажатой
33
клавиши возникает событие OnKeyUp. Если была нажата символьная клавиша,
то вслед за событием OnKeyDown до события OnKeyUp генерируется событие
OnKeyPress. При удерживании клавиши нажатой, непрерывно генерируется
событие
OnKeyDown,
событие
OnKeyUp
возникает
однократно
после
отпускания клавиши.
Обработка события OnKeyPress выполняется для формирования реакции
на нажатую клавишу. Это событие имеет тип TKeyPressEvent:
type TKeyPressEvent = procedure (Sender: TObject; var Key: Char);
Параметр Key содержит код ASCII нажатой клавиши, который может быть
проанализирован и при необходимости изменен. Если параметру Key задать
значение ноль (#0), то это будет соответствовать отмене нажатия клавиши.
Обработчик события OnKeyPress не реагирует на нажатие управляющих
клавиш, однако параметр Key содержит код символа с учетом регистра,
который определяется состоянием клавиш Caps Lock и Shift.
В качестве примера создадим обработчик события OnKeyPress редактора
Edit, запрещающий ввод знака минус:
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
if Key = '-' then Key:=#0;
end;
Для обработки управляющих клавиш, не имеющих ASCII-кодов (Shift,
Ctrl, Alt и др.), можно программно использовать события OnKeyDown и
OnKeyUp типа TKeyEvents [10].
События
OnStartDrag,
OnDragOver,
OnDragDrop,
OnEndDrag
используются для осуществления перетаскивания компонентов. Реализованная
в Delphi технология drag-and-drop позволяет перемещать различные объекты,
например, элементы одного списка в другой. При этом используются два
элемента
управления:
источник
и
приемник.
Источник
содержит
перемещаемый объект, а приемник – элемент управления, на который
помещается элемент-источник. Разные варианты выполнения перетаскивания
мышью хорошо изложены в книге [10].
34
4.3. Кнопки
Стандартная кнопка Button
Кнопки Button очень широко используются в качестве управляющих
элементов. Обычно на них наносится текст, описывающий выполняемые при
нажатии действия.
Кнопку можно нажать щелчком мыши, использованием клавиши быстрого
доступа (если она задана в свойстве Caption), клавишами Enter или пробел,
клавишей Esc. На нажатие клавиш Enter и пробел находящаяся в фокусе ввода
кнопка реагирует по умолчанию. Чтобы задействовать клавишу Esc, надо в
свойстве кнопки Cancel установить true. Это целесообразно делать только
для кнопок, используемых для отмены каких-либо действий.
Для кнопки определён метод Click, выполнение которого эквивалентно
щелчку по кнопке. Метод Click можно использовать, чтобы продублировать
какими-либо действиями щелчок по кнопке. Предположим, что обработчик
кнопки «Заменить» (Button1) должен вызываться клавишами R и r. Тогда
необходимо сформировать обработчик события формы OnKeyPress.
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
if (Key='R') or (Key='r') then Button1.Click;
end;
Дополнительно следует свойство формы KeyPreview установить в true.
Кнопка с рисунком BitBtn
Кнопка BitBtn является разновидностью обычной кнопки Button. Помимо
текста может содержать графическое изображение.
В Delphi имеется ряд предопределённых кнопок, задаваемых свойством
Kind
(рис.1.).
Для
каждой
такой
кнопки
подготовлена
картинка
и
предусмотрены сответствующие названию действия. При этом текст на кнопке
можно изменить. Например, присвоить свойству Caption эквивалентное
русское название. Расположение надписи и рисунка на кнопке определяется
свойствами Margin, Layout, Spacing. По умолчанию свойство Margin равно
35
-1 (картинка и надпись размещаются в центре кнопки). При этом расположение
картинки по отношению к тексту задаётся свойством Layout (слева, справа,
сверху, снизу).
Использование
предопределённых
кнопок
позволяет
очень
просто
реализовать нужные действия, но, к сожалению, их внешний вид часто не
соответствует общему стилю оформления приложения. Кроме того, некоторые
свойства могут быть настроены не лучшим образом. Часто оказывается
целесообразным задать свойства самостоятельно и использовать подходящую
картинку.
Рис.1. Кнопки BitBtn
По умолчанию свойство Kind имеет значение bkCustom, для которого
первоначально изображение отсутствует и его надо загрузить. Растровое
изображение на кнопке задаётся с помощью свойства Glyph. По умолчанию
свойство Glyph имеет значение None. Чтобы задать изображение, надо в
Инспекторе объектов щёлкнуть по кнопке в области значений свойства Glyph,
в открывшемся окне Picture Editor выбрать файл с растровым изображением.
Можно
использовать
поставляемые
с
Delphi
рисунки,
разработанные
специально для размещения на кнопках BitBtn (папка \Program Files\Common
Files\Borland Shared\Images\Buttons). При необходимости, можно создать файл с
36
изображением самостоятельно. Рисунок для кнопки может содержать до трёх
изображений (кнопка не нажата, кнопка не активна, кнопка нажата),
подготовленных по специальным правилам и сохранённых в одном файле
формата BMP.
Кнопка с независимой фиксацией CheckBox
Кнопка CheckBox (флажок) позволяет выбирать или отменять некоторые
действия или значения. При включении или выключении кнопки происходит
событие OnClick. Кнопка может находиться во включённом, выключенном и
неактивном состоянии. С помощью группы кнопок с независимой фиксацией
можно задать несколько опций. При этом состояние любого из компонентов
CheckBox не зависит от состояния остальных, поэтому такие переключатели
называют независимыми.
Свойство Alignment определяет положение сопровождающего текста
относительно кнопки (справа или слева).
Свойство Checked содержит выбор пользователя (да или нет). Состояние
флажка можно переключать щелчком мыши. Если флажок снят, то после
щелчка он будет установлен, и наоборот. При этом соответственно изменяется
состояние свойства Checked. Если переключатель находится в фокусе ввода, то
задать другое положение можно клавишей Пробел.
В приведённом ниже примере переключатель CheckBox1 управляет
выводом названия графика на экран, CheckBox2 отвечает за вывод легенды, а
CheckBox3 используется для изменения цвета фона.
if CheckBox1.Checked then Chart1.Title.Visible:=true
else Chart1.Title.Visible:=false;
if CheckBox2.Checked then Chart1.Legend.Visible:=true
else Chart1.Legend.Visible:=false;
if CheckBox3.Checked then Chart1.BackColor:=rgb(177,142,179)
else Chart1.BackColor:=rgb(255,255,255);
При использовании группы кнопок с независимой фиксацией их часто
размещают внутри контейнеров Panel, GroupBox или ScrollBox.
37
Кнопка с зависимой фиксацией RadioButton
Кнопка RadioButton отображается в виде кружка с расположенным рядом
поясняющим текстом. Выбранное состояние отмечается чёрной точкой. Кнопки
этого типа всегда объединяются в группу, которая образует зависимый
переключатель, предназначенный для выбора одной опции из нескольких
взаимоисключающих. Группа кнопок с зависимой фиксацией, как правило,
помещается в контейнер.
Состояние кнопки определяется свойством Checked. Если у одного из
компонентов группы это свойство равно true, то у всех других компонентов
группы свойство Checked принимает значение false. При включении или
отключении кнопки происходит событие OnClick, в обработчике которого
выполняются действия, зависящие от текущего состояния кнопки.
4.4. Контейнеры
Контейнер GroupBox
Служит для размещения
компонентов
и
представляет
собой
прямоугольную область с рамкой. Заголовок группы записывается в разрыве
верхней рамки слева.
Контейнер RadioGroup
RadioGroup – это специальный контейнер для размещения зависимых
переключателей. Каждый включённый в группу переключатель заносится в
список Items и доступен по индексу. Использование компонента RadioGroup
существенно упрощает обслуживание группы зависимых переключателей.
Свойство Columns определяет количество столбцов переключателей.
Свойство ItemIndex задаёт индекс выбранного переключателя. Свойство
Items – это список строк с заголовками переключателей. Добавление и
удаление элементов достигается добавлением и удалением строк списка Items.
Чтобы создать группу зависимых переключателей необходимо:
• присвоить группе название (свойство Caption);
38
• задать количество столбцов (cвойство Columns);
• сформировать список Items из названий переключателей. Список
создаётся в String list editor, окно которого открывается при нажатии на
кнопку, расположенную в строке свойства Items;
• выбрать один из переключателей, указав в свойстве ItemIndex нужный
индекс. Этот переключатель при запуске приложения будет включён.
Переключатели в группе нумеруются, начиная с нуля.
Для обслуживания зависимого переключателя в программе удобно
использовать оператор case:
case RadioGroup1.ItemIndex of
0:d:=3;
1:d:=5;
2:d:=7;
end;
Панель Panel
Панель Panel является контейнером общего назначения. В отличие от
GroupBox не имеет заголовка и менее удобна для объединения компонентов по
функциональному назначению. Часто используется для создания панелей
инструментов и статусных строк. Свойство Caption отображается в виде
текстовой строки и может использоваться для вывода сообщения. Если же
панель используется для размещения управляющих элементов, то свойство
Caption просто очищают.
Панель имеет развитые средства для создания эффектов трёхмерности за
счёт использующихся в ней двух рамок – внешней и внутренней. Любая из
рамок может отсутствовать (bvNone), быть выпуклой (bvRaised) или
вдавленной (bvLowered). Ширина рамок в пикселах задаётся свойством
BevelWidth.
Свойство Align удобно использовать, чтобы задать положение панели
относительно границ формы, не зависящее от изменения размеров последней: у
верхней границы alTop, у нижней – alBottom, у левой – alLeft, у правой –
alRight, на всем рабочем пространстве – alClient.
39
Панели с вкладками
Для создания элементов с вкладками рекомендуется использовать
компоненты PageControl и TabControl. Эти компоненты позволяют экономить
пространство окна, размещая на одном и том же месте страницы с разным
содержанием. Переход к нужной вкладке выполняется щелчком мыши по
ярлычку. Компоненты PageControl и TabControl имеют много общих свойств
(MultyLine,
TabHeight,
HotTrack,
ScrollOpposite
TabPosition,
TabWidth и др.), но отличаются по сути.
Рис. 2. Пример использования компонента PageControl
TabControl – это одна страница с множеством закладок. Применяется,
когда логические страницы имеют одинаковый вид, а их переключение влечёт
лишь изменение отображаемых данных. Можно применить, например, для
создания записной книжки с алфавитным указателем.
Компонент PageControl содержит перекрывающие друг друга панели
класса TTabSheet. Каждая панель может содержать свой набор компонентов.
Первоначально PageControl не содержит страниц. Для создания страницы надо
открыть контекстное меню и выбрать команду New Page. Появится страница,
40
для которой можно задать надпись на ярлычке (свойство Caption), индекс
изображения, которое может появиться на ярлычке (свойство ImageIndex) и
др. Количество страниц хранится в свойстве для чтения PageCount. Доступ к
странице осуществляется по её номеру PageIndex или программно через
свойство Pages[Index:Integer]. Нумерация страниц начинается с нуля.
На рис. 2 приведён пример использования компонента PageControl с тремя
страницами. Ярлычки оформлены в виде закладок (свойство Style равно
tsTabs) в верхней части компонента (свойство TabPosition равно tpTop).
4.5. Компоненты для работы со строками
Строка редактирования Edit
Компонент Edit используется для ввода, вывода и редактирования строк.
Отображается строка, записанная в свойстве Text. Строки могут быть
достаточно длинные. Однако этот компонент не распознаёт символов конца
строки и не может быть использован для работы с несколькими строками. С
помощью компонента Edit можно отобразить нередактируемый текст, если
свойству ReadOnly присвоить значение true.
Для изменения шрифта, используемого при записи текста, необходимо
изменить значение свойства Font. Свойство CharCase используется для
задания регистра символов, а свойство MaxLength позволяет ограничить длину
строки.
Метод
Clear
применяется
для
удаления
всего
текста,
а
метод
ClearSelection – для удаления выделенной части строки. По умолчанию
введённый текст выделяется при получении компонентом фокуса ввода – это
определяется значением свойства AutoSelect (если true – то выделяется).
Компонент Edit можно использовать для ввода пароля. Для этого свойству
PassWordChar необходимо присвоить значение символа, который будет
отображаться на экране при наборе пароля.
41
Компонент MaskEdit
Компонент MaskEdit – аналог Edit, но с возможностью ввода текста по
некоторому шаблону. Шаблон задаётся свойством EditMask, имеет вид
текстовой строки и управляет тем, что, сколько и в каком порядке вводит
пользователь. В редакторе свойств для EditMask есть заготовки форматов
даты, валюты и т.п. Шаблон можно выбрать из имеющихся, либо разработать
самому. Если это свойство не задано, то MaskEdit работает как обычный
редактор Edit.
Свойство EditText содержит текст до наложения на него шаблона, то есть
то, что ввёл пользователь. Свойство Text может содержать либо исходный
текст, либо результат наложения на него маски. Свойство IsMasked доступно
только для чтения и содержит true, если строка шаблона задана.
Шаблон состоит из трех частей, отделенных друг от друга символами «;».
Первая часть задает маску ввода, вторая – это символ 0 или 1, определяющий,
записывается ли в Text результат наложения маски или исходный текст (0 –
исходный текст). В третьей части указывается символ, который в окне
редактора будет стоять в полях, предназначенных для ввода данных.
Маска состоит из описателей полей ввода, специальных символов и
литералов. Описатель указывает, какой именно символ (один!) может ввести
пользователь в данное поле. Литерал вставляется в текст, показываемый в окне
редактора, но при вводе курсор перескакивает через литерал и не даёт
пользователю возможности изменить его. Литералами считаются любые
символы, кроме описателей полей и специальных символов, а также любой
символ, которому предшествует символ «\». Специальные символы формируют
дополнительные указания редактору. Если не все требуемые поля ввода
заполнены и компонент лишился фокуса ввода, то на экран выводится окно с
сообщением, после закрытия которого курсор устанавливается на позицию, где
закончился правильный ввод. Перечень описателей и специальных символов
можно найти в литературе [1-4,7,10].
42
Редактор Memo
Компонент Memo предназначен для ввода, редактирования и отображения
текста. В отличие от редактора Edit может содержать несколько строк, которые
задаются либо свойством Text, либо свойством Lines. Свойство Text
используется для доступа ко всему содержимому компонента, а свойство
Lines – для работы с отдельными строками. Редактор Memo может содержать
полосы прокрутки ScrollBars.
Многострочный редактор хранит информацию в массиве Lines типа
TStrings. Для загрузки текста из файла используется метод LoadFromFile.
Для сохранения информации в файле используется метод SaveToFile. При
необходимости добавить, удалить, вставить строку используются методы Add,
Delete, Insert. Для записи текста в процессе проектирования приложения
надо открыть окно редактора String list editor кнопкой, расположенной в
Инспекторе объектов у свойства Lines.
В примере редактор Memo1 очищается, и в него с помощью метода Add
выводятся значения из массива целых чисел x. Так как компонент Memo
работает со строками, то предварительно выполняется перевод целого числа в
строку функцией inttostr:
Memo1.Lines.Clear;
for i:=0 to n-1 do Memo1.Lines.Add(inttostr(x[i]));
Списки
Простой список ListBox позволяет выбирать один или несколько
элементов,
может
содержать
изображения.
Элементы
списка
всегда
присутствуют на экране, то есть список всегда раскрыт. Список ComboBox
представляет собой комбинацию компонент Edit и ListBox. Имеет несколько
модификаций. В отличие от ListBox можно выбирать только один элемент.
Модификации комбинированного списка ComboBox задаются свойством
Style: при значении csSimple список всегда раскрыт, значение csDropDown
задаёт раскрывающийся список с полем редактирования, csDropDownList
позволяет только выбрать строку. Количество строк, которые отображаются на
43
экране, задаётся свойством DropDownCount. По умолчанию видно 8 строк.
Если в списке больше элементов, то появляется полоса прокрутки. Свойство
DroppedDown логического типа определяет, раскрыт ли список (true –
раскрыт).
Свойство ItemIndex хранит индекс выбранной строки. Если ни одна
строка не выбрана, ItemIndex=-1. Это свойство задётся только во время
выполнения программы. У компонента ComboBox дополнительно выбранное
значение можно определить по свойству Text.
Работа со списками организуется через свойство Items, имеющее тип
TStrings и представляющее собой совокупность строк списка. Строки
нумеруются с нуля, доступ к строке осуществляется по номеру. Например,
Items[0],
Items[13]. Количество строк хранится в свойстве Count,
последняя строка имеет номер Count-1. При добавлении или удалении строк
значение свойства Count изменяется.
Метод Add(const S:string):integer добавляет строку S в конец
списка и возвращает номер нового элемента.
Процедура Insert(Index:integer;const S:string) вставляет строку
S в позицию Index. Строки, расположенные на этой позиции и за ней –
смещаются.
Процедура Delete(Index: integer) удаляет строку с номером Index.
Если такой строки нет, то действие не выполняется и никаких сообщений не
выводится. После удаления номера строк корректируются.
Процедура Clear очищает список, то есть удаляет все элементы.
Процедура Move(Index1, Index2: integer) перемещает строку с
позиции Index1 в позицию Index2. После перемещения номера строк
корректируются.
Метод IndexOf(const S:string):integer определяет, содержится ли
строка S в списке. Если строка присутствует в списке, то возвращается её
номер, иначе возвращается значение -1.
44
Методы LoadFromFile и SaveToFile позволяют загрузить строки в
список из файла и сохранить список строк в файле. При чтении строк из файла,
предыдущее содержимое списка удаляется. Если при сохранении списка будет
указано имя файла, которого нет, то такой файл будет создан.
Для выбора элементов из списка можно ещё использовать компоненты
CheckListBox, ComboBoxEx, ValueListEditor.
Список CheckListBox подобен ListBox, но у каждой строки есть
индикатор, состояние которого характеризуется свойством Checked. Это
свойство можно устанавливать программно, либо читать, отслеживая действия
пользователя во время работы приложения (аналогично CheckBox). Например:
if CheckListBox1.Checked[1] and CheckListBox1.Checked[2]
then Form2.Show;
С
помощью
задаваемого
программно
свойства
Header
список
CheckListBox можно разбить на разделы и дать этим разделам названия:
CheckListBox1.Header[3]:=true;
Расширенный комбинированный список ComboBoxEx подобен ComboBox,
но хорошо приспособлен для включения в элементы списка изображений.
Компонент
ValueListEditor
предназначен
для
ввода
строк
вида
«имя=значение». Окно имеет две колонки с заголовками Key для имён и Value
– для значений. ValueListEditor удобно использовать для работы с данными
сложной структуры. Например, вводить и редактировать списки студентов,
содержащие большое количество сведений (фамилию, имя, отчество, год
рождения, пол, адрес, телефон, шифр и т.д.).
Компоненты-таблицы DrawGrid и StringGrid
Компоненты DrawGrid и StringGrid имеют форму таблиц, предоставляют
программисту мощные возможности создания и обслуживания табличных
структур данных, позволяют отображать и редактировать данные в каждой
ячейке по отдельности.
В ячейках таблицы DrawGrid вместе с текстом можно поместить и
рисунки. Чтобы таблица была работоспособной, в ней как минимум следует
45
определить
обработчик
события
OnDrawCell,
которое
возникает
при
необходимости прорисовать ту или иную ячейку. Для прорисовки используется
свойство Canvas. При формировании процедур прорисовки используются
методы CellRect и MouseToSell. Компонент DrawGrid только отображает
информацию, но не хранит её.
Более простой и удобной в использовании является таблица StringGrid,
предназначеная для работы с текстовыми данными. Компонент StringGrid
является прямым потомком DrawGrid, от которого унаследовал большинство
свойств
и
методов.
Поэтому
StringGrid
тоже
позволяет
отображать
графические образы, но их прорисовка и хранение выполняются программно.
Таблица делится на две части – фиксированную и рабочую. Фиксированная
часть служит для отображения заголовков столбцов/рядов и для ручного
управления их размерами. Обычно фиксированная часть занимает крайний
левый столбец и самый верхний ряд таблицы. Остальная часть таблицы –
рабочая, она содержит произвольное число столбцов и рядов. Количество рядов
и столбцов можно изменять в Инспекторе объектов и программно. По
умолчанию свойства ColCount и RowCount, определяющие размеры таблицы,
имеют значение 5. Так как нумерация столбцов и строк начинается с нуля, то
первоначальный размер таблицы 6×6. Если рабочая часть не умещается в
пределах окна компонента, то используются полосы прокрутки. При прокрутке
рабочей области фиксированная область не исчезает, но меняется её
содержимое – заголовки строк и столбцов.
С помощью сложного свойства Options определяется внешний вид и
функциональные свойства таблицы. Так, параметр goEditing управляет
режимом редактирования. Чтобы можно было вводить в таблицу данные и
редактировать содержимое ячеек, параметр goEditing надо установить в
true. При работе приложения пользователь может вводить данные только в
ячейки рабочей области. Однако программно может быть реализован доступ к
любым ячейкам таблицы.
46
Свойство Cells[ACol,ARow:integer]:String обеспечивает доступ к
отдельным ячейкам и представляет собой двумерный массив, содержащий
строки текста ячеек таблицы. Размеры массива определяются значениями
свойств ColCount и RowCount. Параметр ACol указывает колонку ячейки, а
параметр ARow – её строку. Доступ к ячейкам таблицы осуществляется во
время выполнения приложения. Для примера зададим нужное число строк
таблицы и запишем заголовки первого и второго столбца:
StringGrid1.RowCount:=10;
StringGrid1.Cells[0,0]:='Аргумент';
StringGrid1.Cells[1,0]:='Функция';
Свойство Objects[ACol,ARow:integer]:TObject обеспечивает доступ
к объекту, связанному с ячейкой (ACol, Arow). Это свойство применяется, в
основном, для связывания изображения со строками и использования их для
специфического отображения данных в таблице. Следующая строка помещает
объект MyBitmap типа TBitmap в 10-ю колонку, 3-ю строку таблицы
StringGrid:
StringGrid1.Objects[10,3]:= MyBitmap;
Если объект был помещен в массив Objects, он продолжит своё
существование даже после того, как таблица StringGrid будет удалена.
Свойство Cols[index:integer]:TString – представляет собой список
строк, содержащий значения всех ячеек колонки с номером index. Это
свойство используется для получения доступа к любому столбцу.
Свойство Rows[index:integer]:TString обеспечивает доступ к ряду с
номером, заданным параметром index. Для примера выполним копирование
первой строки StringGrid2 в четвёртую строку StringGrid1:
StringGrid1.Rows[4].Assign(StringGrid2.Rows[1]);
Аналогично можно выполнять копирование в любые компоненты,
имеющие свойства класса TString, например, в ComboBox или ListBox.
Компонент StringGrid позволяет выбирать значения, отображённые в
ячейках, во время работы приложения. В момент выбора ячейки генерируется
47
событие OnSelectCell, в обработчик которого передаются номера столбца
ACol и строки ARow выделенной ячейки. Это событие позволяет использовать в
программе значение из выбранной ячейки:
procedure TForm1.StringGrid2SelectCell(Sender: TObject; ACol,
ARow: Integer; var CanSelect: Boolean);
begin
if (ACol in[1..3]) and (ARow in[1..3])
then case ARow of
1: xn:=strtofloat(StringGrid2.cells[ACol,ARow]);
2: xk:=strtofloat(StringGrid2.cells[ACol,ARow]);
3: hx:=strtofloat(StringGrid2.cells[ACol,ARow]);
end;
end;
4.6. Компоненты для отображения текста
Метка Label
Компоненты класса TLabel
(метки) предназначены для размещения
текстов: заголовков для других компонент, разделителей, поясняющих
надписей и т.д. Элементы этого типа применяют в тех случаях, когда надо
отобразить текст, который не должен изменяться пользователем.
Свойство AutoSize указывает, будет ли метка изменять свои размеры в
зависимости от помещённого в свойство Caption текста.
Свойство Alignment управляет выравниванием текста по горизонтали, а
свойство LayOut – по вертикали.
Свойство WordWrap разрешает/запрещает разрыв строки на границе слова.
Для вывода многострочных надписей необходимо AutoSize присвоить
значение false, WordWrap присвоить значение true и задать необходимые
размеры метки.
Статический текст StaticTerxt
Статический текст StaticTerxt очень похож на метку Label. Дополнительно
этот компонент может иметь рамку, задаваемую свойством Border. Для записи
длинного текста в несколько строчек достаточно установить в свойстве
AutoSize значение false и задать достаточный размер компонента.
48
Форматированный текст RichEdit
Для создания, просмотра и редактирования rtf-документов в приложениях
используется компонент RichEdit. Многострочный редактор RichEdit работает
с расширенным текстовым форматом, хранит дополнительную служебную
информацию, управляющую свойствами каждого абзаца и сменой шрифта по
ходу текста. Кроме средств форматирования абзацев и отдельных символов,
RichEdit обеспечивает печать активного документа и поиск текста.
Текст можно подготовить заранее, сохранить в файле, а затем при работе
приложения в нужный момент загрузить в RichEdit методом LoadFromFile.
Иногда удобно на этапе разработки приложения передать подготовленный
текст через буфер или ввести небольшой текст с клавиатуры, используя String
List Editor. В этом случае форматирование текста выполняется путём задания
нужных значений свойств в инспекторе объектов. Кроме того, компонент
RichEdit имеет сложные свойства SelAttributes и Paragraph, доступные из
программы и позволяющие динамически изменять параметры символов и
абзацев. Для программного добавления строк используется метод Add, а для
очистки редактора – метод Clear.
4.7. Компоненты для работы с графикой
Компонент Shape
Этот компонент рисует одну из простейших геометрических фигур:
прямоугольник, прямоугольник с закруглёнными краями, квадрат, квадрат с
закруглёнными краями, эллипс, окружность. Вид геометрической фигуры
задаётся свойством Shape, заполнение внутреннего пространства – свойством
Brush, а отрисовка внешних границ – свойством Pen. Фигура полностью
занимает всё пространство компонента. Если задан квадрат или круг, а размеры
по горизонтали и вертикали отличаются, то фигура рисуется с размером
меньшего измерения.
Свойства Brush и Pen сложные. Brush.Color, Pen.Color задают цвет
заполнения и цвет граничной линии. Метод заполнения определяется
49
значением свойства Brush.Style. Тип линии задаётся значением свойства
Pen.Style, а свойство Pen.Width задаёт толщину линии. Если толщина
линии равна 1, то, изменив свойство Pen.Style, можно выбрать другой тип
линии.
Свойство пера Mode определяет режим наложения графической фигуры на
экран или другую поверхность. Режим наложения действует не только на
контур фигуры, но также на её внутреннюю область, контролируемую кистью.
Компонент Image
Компонент Image служит для размещения на форме одного из
поддерживаемых
Delphi
изображений,
хранимых
во
внешних
файлах.
Используются растровые изображения .bmp, jpg, иконка .ico, метафайл .wmf.
Возможно задание файла, картинка из которого будет отображаться на форме,
как во время проектирования приложения, так и во время выполнения.
Центральным свойством класса является Picture, которое задаёт нужный
тип изображения и служит для него контейнером. Отображаемая картинка
хранится в свойстве Picture, доступном на этапе проектирования и на этапе
выполнения.
Свойство AutoSize позволяет управлять автоматическим изменением
размера изображения: если имеет значение true, то компонент изменяет свой
размер в зависимости от размера изображения (размер компонента Image
подгоняется под размер картинки). При AutoSize равном false, размер
компонента остаётся неизменным и, если изображение больше размера
компонента, то выводится только часть картинки. По умолчанию свойство
AutoSize имеет значение false.
Свойство Stretch разрешает/запрещает изменять размер изображения так,
чтобы оно занимало всю клиентскую область компонента (только для файлов
.bmp и .wmf), то есть позволяет подогнать размер картинки под размер
компонента. В этом случае надо в Stretch установить true, а в AutoSize –
false. Масштабирование целесообразно применять для метафайлов.
50
4.8. Формирование меню
Различают
два
типа
меню:
главное
и
контекстное
(локальное,
всплывающее). Главное меню обычно располагают под заголовком формы.
Выбор пункта главного меню вызывает появление на экране выпадающего
меню. Выпадающее меню содержит команды или вложенные выпадающие
меню. Уровень вложения не ограничен, но создавать очень сложные меню не
рекомендуется, так как это затрудняет работу с приложением.
Всплывающее меню не привязано к конкретному месту формы или к
главному меню. Оно появляется по специальному требованию, обычно по
щелчку правой кнопкой мыши. Всплывающим меню удобно пользоваться для
размещения команд, специфичных для отдельных элементов.
В
Delphi
главное
меню
реализовано
компонентом
MainMenu,
а
всплывающее – PopupMenu. Подключение меню к форме выполняется через
свойства формы MainMenu и PopupMenu. Компоненты, применяемые при
создании меню, являются невизуальными. На этапе выполнения их значки не
отображаются. Значки компонентов MainMenu и PopupMenu используется на
этапе разработки для того, чтобы можно было задать значения свойств.
Дизайнер меню
Формирование пунктов меню выполняется в Дизайнере меню. Дизайнер
меню вызывается из контекстного меню, связанного с компонентами
MainMenu или PopupMenu, командой Menu Designer. Как обычно, локальное
меню открывается щелчком правой кнопкой мыши на компоненте. Другой
способ вызова дизайнера меню заключается в выполнении двойного щелчка на
компонентах MainMenu или PopupMenu.
Помимо создания и модификации меню утилита Menu Designer позволяет
загружать меню из ресурсов и сохранять меню в качестве шаблонов. Меню,
сохранённые как шаблоны, могут использоваться несколькими приложениями.
Создание и удаление пунктов меню выполняется в окне Дизайнера меню, а
свойства задаются в Инспекторе объектов.
51
При первом вызове Дизайнера в окне появляется заготовка для
единственного пункта меню, которую надо заполнить в Инспекторе объектов,
то есть задать значения свойств. После этого можно перейти к формированию
следующего пункта главного меню (расположенного справа) или создать
вложенное меню. Щелчок по пункту главного меню приводит к началу
формирования вложенного меню: ниже заполненного пункта появляется пустая
ячейка. По мере заполнения строк ниже появляется
пустая
ячейка,
завершающая список команд. После того, как все нужные команды вложенного
меню записаны, можно приступать к созданию следующего пункта главного
меню. Пустую ячейку удалять не следует, она видна только на этапе
проектирования.
Спроектированный пункт главного меню со всеми подпунктами можно
переместить на другое место буксировкой.
На любом этапе создания приложения меню можно отредактировать. Для
этого следует войти в Дизайнер меню, установить курсор на нужном пункте и
вызвать контекстное меню щелчком правой кнопки мыши. Контекстное меню
позволяет вставить новый пункт (Insert), удалить существующий (Delete),
создать выпадающее меню (Create Submenu). Кроме того, имеется несколько
команд для работы с шаблонами меню. Все действия относятся к пункту меню,
находящемуся в позиции курсора.
Заполнение пунктов меню
Пункты меню являются компонентами, принадлежащими к классу
TMenuItem. Для пунктов меню определено свойство OnClick, которое
возникает при щелчке мышью или при нажатии на клавишу Enter, если перед
этим команда была выбрана.
Свойство Caption содержит текст пункта меню (заголовок). При записи
этого свойства можно использовать символ & (амперсант) для формирования
подчёркнутого
символа,
например
File,
Open.
Подчёркнутый
символ
применяется совместно с клавишей Alt для вызова пунктов меню с клавиатуры.
52
Если
свойству
Caption
присвоить
значение
"–"
(минус),
то
будет
сформирована горизонтальная линия, которая используется для разделения
групп команд.
Очень часто пункты меню являются переключателями. Если пункт меню
работает как обычный переключатель, то он отмечается символом ∨. Наличие
такого символа у независимого переключателя говорит о том, что команда
выполняется. Повторный выбор этого же пункта приводит к тому, что команда
выключается (символ ∨ исчезает). Включена команда или нет, определяется
свойством Checked: если значение равно true, то пункт меню выбран и
содержит метку.
Рядом с пунктами меню, которые относятся к зависимому переключателю,
может стоять жирная точка. В этом случае несколько пунктов работают
согласованно, как один переключатель с множеством состояний. Жирной
точкой отмечается только один пункт из группы команд, образующих
взаимоисключающие пункты-переключатели. Для всех пунктов группы
необходимо установить одинаковое ненулевое значение свойства GroupIndex
и присвоить свойству RadioItem значение true. Для приведения в действие
механизма переключения следует для всех пунктов группы определить
обработчики события OnClick. Выбор любого пункта приводит к тому, что его
свойство Checked становится равным true.
Некоторые
пользователю
режимы
в
работы
отдельные
приложения
моменты
времени.
могут
быть
Пункты
недоступны
меню
делают
запрещёнными с помощью свойства Enabled. Если значение Enabled равно
false, то текст пункта выглядит тусклым и его выбор игнорируется.
Как принято в Windows, для любого пункта меню можно задать
комбинацию клавиш, которая позволит выполнить команду, не открывая меню.
«Быстрые клавиши» выбираются в свойстве ShortCut. Следует помнить, что
Delphi не контролирует выбранные комбинации, разработчик должен сам
проследить за тем, чтобы использовались разные клавиши.
53
Локальное меню
Контекстное меню всплывает автоматически после щелчка правой кнопкой
мыши, если значение свойства Autopopup равно true. Место появления
зависит от позиции курсора в момент щелчка и определяется свойством
Alignment. С позицией курсора может совпадать левый (paLeft) или правый
(paRight) верхний угол меню, либо середина верхнего края (paCenter).
Всплывающее меню заполняется пунктами, так же как и главное меню, в
дизайнере меню. Часто в контекстное меню вводят пункты, которые дублируют
команды главного меню. Если для команд главного меню обработчики событий
уже написаны, то можно подключить их к соответствующим пунктам
локального меню. Затем надо синхронизировать работу локального и главного
меню.
Локальное меню может быть создано для любого оконного компонента.
Чтобы связать щелчок правой кнопкой мыши на компоненте с раскрытием
меню, в свойство PopupMenu этого компонента надо записать имя меню.
4.9. Другие компоненты
Компонент UpDown
Ввод целых чисел можно существенно упростить, если использовать
управляющий компонент UpDown. Этот компонент состоит из двух кнопок с
противоположно направленными стрелками, применяется совместно с какимлибо другим компонентом, обычно в сочетании с Edit.
Чтобы связать UpDown с конкретным компонентом, надо имя этого
компонента задать в свойстве Associate. Место появления кнопок со
стрелками определяется свойством AlignButton, они могут располагаться
слева (udLeft) или справа (udRight) от ассоциированного компонента.
Свойство Position содержит корректируемое числовое значение. Шаг
изменения определяется свойством Increment. Максимальное и минимальное
значения задаются свойствами Max и Min. Для того чтобы можно было
изменять значение мышью и на клавиатуре, свойство ArrowKeys задают true.
54
Компонент Timer
Таймер позволяет задавать в приложении интервалы времени. Управление
таймером осуществляется с помощью свойств Interval, Enabled и события
OnTimer.
Свойство Interval задаёт интервал времени в миллисекундах от момента
включения таймера до события OnTimer. Минимальный интервал равен 55
мсек (примерно 1 тик), интервалы кратны 55 мсек. Короткие интервалы
времени (единицы и десятки миллисекунд) точно задать с помощью таймера не
удаётся: реальные периоды срабатывания будут больше.
Свойство Enabled определяет, включён ли таймер (если true, то
включён). Причём, раз включённый таймер будет возбуждать событие
OnTimer до тех пор, пока его свойство Enabled не станет равным false.
Альтернативным
способом
отключения
таймера
является
задание
интервала срабатывания равным 0 при Enabled = true.
В приведённом примере в обработчике события OnFormCreate задаются
начальные размеры формы, которые затем меняются по таймеру.
procedure TForm1.FormCreate(Sender: TObject);
begin
Form1.Height:=28; Form1.Width:=124;
Timer1.Enabled:=true;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
with Form1 do
begin
if Width<574 then Width:=Width+50 else
if Height<308 then Height:=Height+40 else Timer1.Enabled:=false;
end;
end;
ВОПРОСЫ ДЛЯ САМОКОНТРОЛЯ
1. Какой тип имеет свойство Visible?
2. Будет ли видна на экране кнопка Button1, для которой задано
Button1.Enabled:=false;
3. Какие компоненты называют контейнерами?
4. Как создать всплывающую подсказку для компонента?
55
5. Что задаёт свойство TabOrder?
6. Как сделать компонент невидимым (недоступным)?
7. Способен ли получить фокус ввода компонент Memo (ListBox, ComboBox,
DrawGrid, StaticTerxt, UpDown, Timer)?
8. Проанализируйте приведённый ниже код. Выясните, что и как делает
программа. Подумайте, как можно избавиться от замеченных недостатков.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Label1: TLabel;
Image1: TImage;
Memo1: TMemo;
procedure Image1MouseDown(Sender:TObject; Button:TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure FormCreate(Sender: TObject);
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Image1MouseDown(Sender: TObject; Button:
TMouseButton; Shift: TShiftState; X, Y: Integer);
Var Lx,Ly:integer;
begin
Lx:=Image1.Width div 2; Ly:=Image1.Height div 2;
if (x<Lx) and (y<Ly) then
begin Label1.Caption:='Меланхолик';
Memo1.Lines.LoadFromFile('f2.txt')end;
if (x>Lx) and (y<Ly) then
begin Label1.Caption:='Холерик';
Memo1.Lines.LoadFromFile('f1.txt')end;
if (x<Lx) and (y>Ly) then
Begin Label1.Caption:='Флегматик';
Memo1.Lines.LoadFromFile('f3.txt')end;
if (x>Lx) and (y>Ly) then
Begin Label1.Caption:='Сангвиник';
Memo1.Lines.LoadFromFile('f4.txt')end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Image1.Picture.LoadFromFile('Pic.bmp');
Label1.Caption:='';
Memo1.Clear;
end;
end.
56
5. ОБРАБОТКА ИСКЛЮЧИТЕЛЬНЫХ СИТУАЦИЙ В DELPHI
Исключительная
ситуация – это некоторое ошибочное состояние,
возникающее во время выполнения программы. Исключительные ситуации
(исключения) могут возникать по самым разным причинам, например из-за
невозможности выполнить преобразование, при делении на ноль и др. В любом
случае приложение получает сообщение о возникновении исключения.
В Delphi предусмотрен глобальный обработчик исключительных ситуаций
и могут быть задействованы локальные обработчики. Глобальная обработка
исключений реализуется через объект Application. Глобальная обработка
обеспечивает пользователя информацией об ошибке, но не устраняет причины.
Локальная
возникновении
обработка
ошибки
исключительных
перейти
к
ситуаций
специально
позволяет
при
подготовленному
коду
программы. Такой подход реализуется с помощью языковых конструкций,
которые как бы «охраняют» фрагмент кода программы и определяют
обработчики ошибок, которые будут вызываться, если в защищённом участке
кода что-то пойдет не так, как предполагалось.
Для
обозначения
начала
защищенного
участка
кода
используется
служебное слово try, завершается конструкция словом end. Существует два
типа защищенных участков: try...except и try...finally, которые имеют
похожий синтаксис, но отличаются по назначению. Первый тип используется
для обработки исключительных ситуаций. Его синтаксис:
try
{Операторы, выполнение которых может вызвать ошибку}
except
{Операторы, которые должны быть выполнены в случае ошибки}
end;
Конструкция try...except применяется для перехвата исключительной
ситуации и позволяет восстановить работоспособность программы. Секция
except может быть разбита на несколько частей on...do для обработки
разных классов исключений. После конструкций on...do может быть
помещён раздел else, который относится ко всему блоку. По логике работы
57
группа конструкций on...do напоминает оператор case. К исключениям, не
имеющим своих локальных обработчиков, применяется механизм глобальной
обработки через объект Application.
try
{Операторы, выполнение которых может вызвать ошибку}
except
{Операторы, которые должны быть выполнены в случае ошибки}
on Exception1 do ...;
on Exception2 do ...;
...
else
...
end;
Рассмотрим следующий пример. В поля Edit1 и Edit2 записываются
целые числа. При щелчке по кнопке Button1 выполняется перевод введённых
строк в числовой формат, первое число делится на второе и результат
выводится в Edit3. Затем в Memo1 записываются исходные строки, сумма
чисел и частное от деления первого числа на второе.
Внимание! При тестировании приложений желательно пользоваться
созданным exe-файлом. Запускать приложения из Delphi можно, но при этом
надо учитывать, что при возникновании исключительной ситуации прежде
всего сработает система защиты Delphi. При появлении системного
сообщения его надо прочитать, окно сообщения закрыть и выполнить команду
Run для продолжения работы.
procedure TForm1.Button1Click(Sender: TObject);
Var a,b:integer;
rez:extended;
begin
a:=strtoint(Edit1.Text);
b:=strtoint(Edit2.Text);
rez:=a/b;
Edit3.Text:=floattostr(rez);
Memo1.Lines.Add(Edit1.Text);
Memo1.Lines.Add(Edit2.Text);
Memo1.Lines.Add(inttostr(a+b));
Memo1.Lines.Add(floattostr(rez));
end;
Во время работы приложения исключительные ситуации могут возникнуть
при выполнении преобразования строка-число и при вычислении частного от
58
деления, если делитель равен нулю или нулю равны оба введённых числа. Если
запустить программу на выполнение, то при возникновении любого из
исключений
сработает
глобальная
система
обработки
исключительных
ситуаций. При этом выполнение процедуры будет прервано и будут выводиться
сообщения о причине ошибки.
Введём локальную обработку исключительных ситуаций. Для этого
сформируем защищённый блок. Анализировать ошибки не будем.
procedure TForm1.Button1Click(Sender: TObject);
Var a,b:integer;
rez:extended;
begin
try
a:=strtoint(Edit1.Text);
b:=strtoint(Edit2.Text);
rez:=a/b;
Edit3.Text:=floattostr(rez);
except
ShowMessage('Ошибка!');
end;
Memo1.Lines.Add(Edit1.Text);
Memo1.Lines.Add(Edit2.Text);
Memo1.Lines.Add(inttostr(a+b));
Memo1.Lines.Add(floattostr(rez));
end;
В этом случае при возникновении любого исключения будет прерываться
выполнение операторов защищённого блока, в Edit3 результат не появится. На
экран
будет
выведено
окно
с
сообщением
«Ошибка!».
Операторы,
расположенные после защищённого блока, будут выполняться, то есть в Memo1
появятся записи.
Изменим секцию except. Проверим одну из возможных ошибок – деление
на ноль. Далее приводится фрагмент кода, в который внесены изменения.
except
on EZeroDivide do
begin
ShowMessage('Попытка деления на ноль!');
Edit2.SetFocus;
end;
В этом случае при возникновении других исключений сработает
глобальный обработчик, то есть выполнение процедуры будет прервано.
59
Добавим локальный обработчик для контроля за преобразованием
вводимых данных. При этом глобальная обработка исключений будет
задействована только для нулевых введённых значений (0/0).
except
on EZeroDivide do
begin
ShowMessage('Попытка деления на ноль!');
Edit2.SetFocus;
end;
on EConvertError do ShowMessage('Ошибка преобразования!');
Если ввести секцию else, то все исключения будут обработаны локально.
except
on EZeroDivide do
begin
ShowMessage('Попытка деления на ноль!');
Edit2.SetFocus;
end;
on EConvertError do ShowMessage('Ошибка преобразования!')
else ShowMessage('Ошибка в защищённом блоке!');
Конструкцию
try...finally
используют
в
тех
случаях,
когда
существуют действия, которые обязательно надо выполнить до завершения
программы. Код, расположенный в части finally, выполняется в любом
случае, даже если возникает исключительная ситуация. Если ошибки не
возникло, то последовательно выполняются все операторы секций.
try
...{Операторы, выполнение которых может вызвать ошибку}
finally
{Операторы, которые должны быть выполнены даже в случае ошибки}
end;
Конструкцию try...finally можно включить в блок try...except.
Это позволяет выполнить обязательные операторы секции finally и
обработать исключение операторами секции except. Оба типа конструкций
можно использовать в любом месте, допускается вложенность любой глубины.
Базовым классом для всех исключений является класс Exception.
Потомки этого класса охватывают большое количество исключений, которые
могут возникнуть в процессе работы приложений. Имена потомков класса
60
Exception начинаются с буквы E. Ниже приведены наиболее часто
используемые классы исключений.
EConvertError – ошибка преобразования типов, может возникнуть при
выполнении функций StrToInt и StrToFloat.
EInOutError – ошибка ввода/вывода при включенной директиве {$I+}.
EDivByZero – деление целого на ноль.
EIntOverflow – переполнение в операции с целыми переменными.
–
ERangeError
присвоение
значения,
выходящего
за
пределы
допустимого диапазона. Например, при попытке обращения к элементам
массива по индексу, выходящему за пределы массива.
EInvalidGraphic – попытка загрузки методом LoadFromFile файла,
несовместимого графического формата.
EInvalidPointer – некорректная операция с указателем.
EFCreateError – ошибка создания файла
EFOpenError – ошибка открытия файла
EListError, EStringListError – ошибка при работе со списками.
EMathError – предок исключений, возникающих при выполнении
операций с плавающей точкой.
EInvalidOp
–
попытка
передачи
математическому
сопроцессору
ошибочной инструкции.
EOverflow –переполнение при слишком больших величинах.
EUnderflow – потеря значимости при операции с плавающей точкой
(слишком малая величина). Результат получает нулевое значение.
EZeroDivide – попытка деления на ноль.
EMenuError –ошибка при работе с пунктами меню для компонент TMenu,
TMenuItem, TPopupMenu и их наследников.
EOutOfMemory – вызов методов New, GetMem или конструкторов классов
при невозможности распределения памяти.
61
EOutOfResources – ошибка при выполнении запроса на выделение или
заполнение Windows-ресурсов (например, обработчика handles).
Структурную обработку исключительных ситуаций, реализованную в
Delphi, можно дополнять традиционным подходом к обработке ошибок,
который заключается в анализе кодов ошибок, возвращаемых функциями.
ВОПРОСЫ ДЛЯ САМОКОНТРОЛЯ
1. В чём принципиальное отличие локальной и глобальной обработки
исключительных ситуаций?
2. Какие типы ошибок (синтаксические, логические или динамические)
позволяет обработать имеющийся в Delphi механизм?
3. Какая конструкция используется для восстановления работоспособности
программы?
4. В каких случаях в код включают блок try...finally?
5. Проанализируйте
приведённые
примеры
обработки
исключительных
ситуаций и определите, какие значения будут выводиться в редактор Memo
в каждом случае. При выполнении анализа следует рассматривать все
возможные комбинации некорректного задания данных.
6. Можно ли было в рассмотренных ранее примерах заменить конструкцию
try...except на try...finally?
7. Почему при анализе исключительных ситуаций целесообразно использовать
exe-файл?
8. Можно ли создать свой класс исключения?
9. Можно ли создать собственный глобальный обработчик исключений?
10. Как будет вести себя приложение, если на форму помещён компонент
ApplicationEvents1 и сформирована процедура:
procedure TForm1.ApplicationEvents1Exception(Sender: TObject;
E: Exception);
begin
ShowMessage ('Ошибка при исполнении приложения');
end;
62
6. СОЗДАНИЕ ОКОН ДИАЛОГА
6.1. Процедуры и функции, реализующие диалоги
В Delphi имеются процедуры и функции для отображения диалоговых окон
общего
назначения.
Для
вывода
сообщений
используются
процедура
ShowMessage и функции MessageDlg, MessageDlgPos. Для ввода данных
применяются
окна
диалога,
отображаемые
функциями
InputBox
и
InputQuery.
Процедура ShowMessage (const Msg:String) выводит окно сообщения
с кнопкой ОК. Заголовок содержит название исполняемого файла приложения,
а строка Msg содержит текст сообщения. Например:
ShowMessage('Повторите ввод целого числа');
Функция MessageDlg (const Msg: String; AType: TMsgDlgType;
AButtons: TMsgDlgButtons; HelpCtx: Longint):Word отображает окно
сообщений и позволяет получить ответ пользователя. Параметр Msg содержит
выводимое сообщение. Параметр AType задаёт тип окна (Warning, Error,
Information и др.). Параметр AButtons определяет набор кнопок окна (Yes, No,
OK, Cancel, Cancel, Help, Abort, Retry, Ignore). Для этого параметра имеются две
константы, задающие предопределенные наборы кнопок:
mbYesNoCancel = [mbYes, mbNo, mbCancel]
mbOKCancel = [mbOK, mbCancel]
Параметр HelpCtx определяет тему справки, появляющейся при нажатии
пользователем клавиши F1. Обычно значение этого параметра равно нулю.
Щелчок по любой кнопке, кроме Help, закрывает окно диалога. При этом
функция MessageDlg возвращает модальный результат, проанализировав
который, можно управлять выполнением приложения.
Функция MessageDlgPos отличается от функции MessageDlg наличием
параметров х и y, управляющих положением окна на экране.
Функция
InputBox(const
ACaption,
APrompt,
63
ADefault:
String):String
отображает в центре экрана диалоговое окно, служащее для ввода строки
текста. В окне имеется поле ввода, а также кнопки ОК и Cancel. Параметр
ACaption задает заголовок окна, параметр APrompt содержит поясняющий
текст к полю ввода. Параметр ADefault определяет строку, возвращаемую
функцией при отказе пользователя от ввода информации нажатием кнопки
Cancel или клавиши Esc. Пример использования функции InputBox:
st:=InputBox('Студент', 'Введите фамилию', 'Неизвестный');
Функция InputQuery(const
ACaption,
APrompt:String;
var
Value:String):Boolean отличается от функции InputBox тем, что вместо
строки
по
умолчанию
используется
параметр
Value,
который
при
подтверждении ввода содержит введенную пользователем строку. Например:
InputQuery('Студент', 'Введите фамилию', st);
Возвращаемое функцией InputQuery логическое значение позволяет
определить, каким образом завершен диалог (ОК соответствует true).
6.2. Стандартные диалоговые панели
На странице Dialogs Палитры компонентов расположены компоненты,
реализующие диалоговые окна общего назначения. Использование стандартных
окон диалога выполняется по единому сценарию, приведённому ниже.
Поместить на форму компонент и настроить его свойства в Инспекторе
объектов или программно.
Вызвать метод Execute, который создаёт и выводит окно на экран. Вызов
этого метода обычно располагается в обработчике какого-либо события. Так
как окно диалога модальное, то после применения метода Execute выполнение
программы приостанавливается до тех пор, пока пользователь не закроет окно.
Функция Execute возвращает true, если результат диалога успешный (OK).
Проанализировав результат диалога, можно выполнить третий этап:
использование введённых с помощью диалогового окна данных.
Рассмотрим более подробно диалоговые окна открытия и сохранения
файла. Так как окна похожи, то компоненты OpenDialog и SaveDialog,
64
предназначенные для их создания, имеют идентичный набор свойств и методов.
Свойство FileName строкового типа задаёт имя и полный путь файла,
выбранного
в
диалоге.
Для
удобства
дальнейшего
использования
рекомендуется задавать каталог, открываемый при первом появлении диалога
(свойство InitialDir), и формировать фильтр имени файла.
Свойство Filter можно задать в Инспекторе объектов или программно.
На этапе проектирования следует щёлкнуть по кнопке в строке Filter и в
открывшемся редакторе записать название типа файла (слева) и маску (справа).
Если
требуется
отображать
файлы
нескольких
типов,
то
придётся
сформировать соответствующее количество строк. При задании фильтра
программно все сведения записывают одной строкой, в которой в качестве
разделителя между фильтрами, описанием файла и маской используется
вертикальная черта. Если для одного описания приводится несколько масок, то
они разделяются символом «;».
У
компонента
SaveDialog
следует
задать
свойство
DefaultExt,
определяющее расширение, добавляемое по умолчанию к имени файла. Иногда
целесообразно в свойстве FileName записать имя файла. Например:
OpenDialog1.Filter:='Текстовые txt|*.txt|Файлы Pas|*.pas';
SaveDialog1.DefaultExt:='txt';
SaveDialog1.Filter:= OpenDialog1.Filter;
if SaveDialog1.Execute
then Memo1.Lines.SaveToFile(SaveDialog1.FileName);
if OpenDialog1.Execute
then begin
st:= OpenDialog1.FileName;
Memo2.Lines.LoadFromFile(st);
Memo3.Lines.SaveToFile(st);
end;
Для тонкой настройки параметров и внешнего вида окна используется
составное свойство Options. По умолчанию все параметры имеют значение
false. Для ввода имени с клавиатуры предусмотрен компонент Edit, который
можно заменить на ComboBox, присвоив свойству FileEditStyle значение
fsComboBox вместо fsEdit. Если используется комбинированный список, то с
65
ним можно связать протокол выбора имён (свойство HistoryList). Пополнять
этот список надо программно.
Специализированные диалоги открытия и сохранения графических файлов
OpenPictureDialog
и
SavePictureDialog
отличаются
от
OpenDialog
и
SaveDialog удобной возможностью просматривать изображения и заданным
значением свойства Filter. Причём в фильтре по умолчанию перечислены все
разрешённые форматы. При необходимости откорректировать фильтр на этапе
проектирования очень просто: достаточно удалить лишние строки.
OpenPictureDialog1.Filter:='Графические файлы bmp|*.bmp|'+
'Все файлы|*.bmp;*.jpg;*.jpeg;*.ico;*.emf;*.wmf';
OpenPictureDialog1.InitialDir:='F:\A_Slide';
if OpenPictureDialog1.Execute then
Image1.Picture.LoadFromFile(OpenPictureDialog1.fileName);
6.3. Использование модального окна
Поведение модальной формы определяется свойством ModalResult. Это
свойство доступно только во время выполнения приложения. При открытии
формы методом ShowModal свойство ModalResult приобретает значение,
равное нулю. Как только это свойство получит положительное значение –
модальное окно будет закрыто.
Требуемое
значение
ModalResult
можно
задать
программно
в
обработчиках событий для компонентов модальной формы. Однако проще
воспользоваться свойством ModalResult кнопок Button и BitBtn. В кнопках
BitBtn это свойство имеет значение, соответствующее назначению кнопки. Для
кнопки Button свойству ModalResult можно задать нужное значение. При
использовании кнопки для закрытия окна её свойство ModalResult
определяет, какое значение будет иметь одноимённое свойство формы.
Для облегчения трактовки результата в Delphi объявлены именованные
константы (смотри таблицу). Чаще требуемые значения свойства ModalResult
для кнопок задаются на этапе проектирования. Однако в некоторых случаях
целесообразно установить значения во время работы приложения. Например,
чтобы запретить закрытие модального окна.
66
Таблица
Значения свойства ModalResult
Число
Константа
Значение
Примечание
0
mrNone
1
mrOk
idOk
2
mrCancel
idCancel
3
mrAbort
idAbort
Закрытие кнопкой Cancel или методом Close
или кнопкой в строке заголовка окна
Закрытие кнопкой Abort
4
mrRetry
idRetry
Закрытие кнопкой Retry
5
mrIgnor
idIgnor
Закрытие кнопкой Ignor
6
mrYes
idYes
Закрытие кнопкой Yes
7
mrNo
idNo
Закрытие кнопкой No
8
mrAll
mrNo+1
Закрытие кнопкой All
9
mrNoToAll
mrAll+1
Закрытие кнопкой NoToAll
10
mrYesToAll
NoToAll+1
Закрытие кнопкой YesToAll
Закрытие кнопкой OK
При закрытии модального окна функция ShowModal возвращает значение
свойства ModalResult. Таким образом, для оценки действия пользователя
можно
прочитать
значение
свойства
формы
ModalResult
или
воспользоваться результатом, возвращаемым функцией ShowModal.
При разработке приложения следует учитывать, что закрытию формы
методом Close соответствует значение mrCancel свойства ModalResult.
Скрытие формы методом Hide не изменяет значения ModalResult.
Последовательность действий при создании окна диалога:
1) создать новую форму, присвоить ей имя (например, MyDlg), задать
значения свойств и сохранить в файле;
2) используя команду File|Use Unit, связать с нужной формой приложения;
3) в обработчик события для пункта меню или кнопки включить команду,
выводящую окно на экран: MyDlg.ShowModal;
4) проанализировать результат диалога. Например, применить конструкцию
if MyDlg.ModalResult=mrOk then <операторы> else <операторы>;
67
Альтернативный вариант предполагает совмещение пунктов 3 и 4 путём
использования конструкции:
if MyDlg.ShowModal then <операторы> else <операторы>;
Метод ShowModal выводит на экран модальное окно, а при его закрытии
возвращает результат диалога.
if MyDlg.ShowModal=mrOk
then begin
label1.Caption:=MyDlg.Edit1.Text;
label2.Caption:=MyDlg.Edit2.Text;
end
else begin
MyDlg.Edit1.Text:=st1;
MyDlg.Edit2.Text:=st2;
end;
Следующий пример иллюстрирует анализ свойства ModalResult при
использовании
функции
MessageDlg.
Для
задания
цвета
применяется
стандартное окно ColorDialog, а PrintDialog позволяет организовать печать.
procedure TForm1.MenuScrClick(Sender: TObject);
var res:TModalResult;
begin
if ColorDialog2.Color<> clWhite then
begin
res:=MessageDlg('Цвет фона - не белый'+
#10#13'Исправить автоматически - Yes'+
#10#13'Продолжить - OK'+
#10#13'Отменить печать - Cancel',
mtWarning,[mbYes,mbok,mbCancel],0);
if res=mrYes then ColorDialog2.Color:=clWhite;
if res=mrCancel then exit;
end;
if PrintDialog1.execute then
begin
< операторы вывода на печать >
end;
end;
6.4. Использование заготовок
Применение имеющихся в репозитории заготовок позволяет ускорить
разработку приложений. Чтобы воспользоваться заготовкой (шаблоном),
необходимо:
68
• выполнить команду File|New|Other, перейти на страницу Dialogs;
• выбрать подходящую заготовку, установить переключатель в положение
Copy и нажать кнопку OK. Появится соответствующая форма, и
сведения о ней система Delphi включит в файл проекта;
• при необходимости разместить на форме дополнительные компоненты и
изменить значения свойств имеющихся;
• сохранить форму;
• подсоединить диалоговую панель к нужной форме приложения;
• вывести окно диалога на экран командой ShowModal;
• обработать результат диалога.
Следует иметь в виду, что самостоятельно написать обработку кнопок,
имеющихся в заготовке, нельзя. Кнопки можно использовать только по
назначению, то есть в соответствии с расположенной на них надписью.
Например, добавим в проект окно диалога для ввода пароля PasswordDlg.
Пароль будем запрашивать при попытке выполнить одну из команд меню.
procedure TForm1.Dialog1Click(Sender: TObject);
begin
if PasswordDlg.ShowModal=mrok then
if PasswordDlg.Password.Text='Shaker' then Form3.Show;
end;
ВОПРОСЫ ДЛЯ САМОКОНТРОЛЯ
1. Перечислите компоненты, реализующие диалоговые окна.
2. Назовите характерные черты окна диалога.
3. Как вывести стандартную диалоговую панель на экран?
4. Как создать окно диалога на основе формы?
5. Какой
метод
надо
использовать
для
закрытия
окна
диалога,
сформированного на основе формы? Почему?
6. В каких случаях целесообразно самостоятельно разрабатывать окно диалога?
7. Окно диалога было закрыто методом Hide. Какое значение получит свойство
ModalResult?
69
7. ВВОД И ВЫВОД ДАННЫХ
7.1. Общие сведения
Для ввода данных можно использовать:
• реализующие диалоги функции InputBox и InputQuery;
• редакторы Edit, LabeledEdit, MaskEdit, Memo;
• компоненты для ввода целых чисел UpDown, SpinEdit;
• компоненты для работы со списками строк ListBox, ComboBox;
• компоненты-таблицы StringGrid;
• переключатели CheckBox, RadioGroup, RadioButton;
Данные можно вводить с клавиатуры, загружать из файла, формировать
программно (случайным образом или по определённым правилам).
При вводе с клавиатуры необходимо учитывать, что многие компоненты,
предназначенные для ввода данных, работают со строками. Поэтому при вводе
чисел необходимо использовать функции для перевода строки в число.
Обязательное требование: к обработке данных приступать только после
корректного ввода.
Основная проблема – контроль вводимых данных. Наиболее общее
решение – это использование имеющихся в Delphi средств обработки
исключительных ситуаций, то есть формирование защищённого блока и
обработка возникающих исключений. Но этот универсальный подход не всегда
удобен, так как предусматривает прерывание естественного хода обработки
данных. В ряде случаев желательно контролировать данные непосредственно
при вводе, то есть разрешать вводить только определённые символы.
При использовании нескольких полей ввода или больших объёмов данных
необходимо так организовать их контроль, чтобы пользователю не пришлось
полностью повторять ввод, если ошибка была сделана где-то в конце ввода.
Компоненты,
обеспечивающие
ввод
данных
(за
исключением
переключателей), прекрасно приспособлены для вывода информации. Кроме
70
того, специально для отображения данных предназначены компонентытаблицы StringGrid и компоненты для вывода строк Label и StaticText.
Для удаления текста в компонентах, предназначенных для ввода строк,
можно воспользоваться методом Clear либо присвоить нужной строке пустое
значение. Как правило, после очистки полей ввода следует передать фокус
ввода компоненту, с которого начнётся ввод данных.
Edit1.Clear;
//Очистка однострочного редактора
Memo1.Clear; //Очистка многострочного редактора
Memo2.Lines.Clear; //Очистка многострочного редактора
Edit2.Text:=''; //Очистка однострочного редактора
for i:=0 to n-1 do Memo3.Lines.Strings[i]:='';
//Очистка строк от 0 до n-1
for i:=0 to Memo4.Lines.Count-1 do Memo3.Lines[i]:='';
//Очистка строк от 0 до значения количества строк Memo4
Memo2.Lines[strtoint(Edit1.Text)]:='';
//Очистка строки, номер которой задан Edit1.Text
В следующих подразделах приводятся различные приёмы ввода и вывода
данных, а также способы контроля корректности ввода чисел. Использование
окон диалога рассмотрено в разделе 6. Логически законченные примеры
организации
ввода/вывода
приводятся
после
изложения
теоретических
сведений.
7.2. Формирование данных случайным образом
Формирование данных случайным образом часто оказывается полезным на
этапе отладки. Причём иногда требуется, чтобы при запуске программы
формировалась одна и та же последовательность случайных (точнее,
псевдослучайных) чисел, а иногда – нужны разные последовательности.
Для получения случайных чисел применяется функция random. Если
функция random используется без параметра, то генерируется случайное
вещественное число, которое больше либо равно 0 и меньше 1. Если же при
вызове функции random задать целочисленный параметр, например n, то она
вернёт целое число из диапазона [0, n-1]. Например,
x := random;
с := random(101);
71
Чтобы создать последовательность случайных чисел, функцию random
используют в цикле. Для получения при запуске программы новой
последовательности
следует
до
её
формирования
вызвать
процедуру
randomize, которая инициализирует функцию random (меняет базовое
значение в датчике псевдослучайных чисел).
7.3. Ввод данных с клавиатуры
Однострочные редакторы (окна редактирования) Edit, LabeledEdit,
MaskEdit представляют собой поля для ввода текста. Вводимая строка
сохраняется в свойстве Text. В компоненте MaskEdit дополнительно результат
ввода можно получить через свойство EditText (текст вместе с символами
маски). Значение свойства Text можно ввести с клавиатуры, установить
программно, задать начальное значение в Инспекторе объектов.
В компоненте Memo текст окна содержится в виде списка строк в свойстве
Lines, имеющем тип TStrings. Свойства и методы класса TStrings
упоминались в разделе 4.5 и подробно рассмотрены в разделе 12.2. Начальное
значение текста можно задать на этапе проектирования в окне редактирования
списка строк String list editor. Используя свойство Text, можно обратиться ко
всему тексту, представленному одной строкой с разделителями (символами
возврата каретки #13 и перевода строки #10).
В редакторе Memo доступ к отдельной строке осуществляется по её номеру
или с помощью свойства Strings [Index: Integer] типа String.
Обращаться по индексу можно только к существующим строкам. Для
добавления строк используется метод Add.
В отличие от однострочного редактора компонент Memo реагирует на
нажатие клавиши Enter. Чтобы при этом происходил ввод новой строки,
свойство WantReturns должно иметь значение true (значение по умолчанию).
При работе с редакторами разрешено использовать общепринятые способы
редактирования через буфер. Так, загрузить строку из буфера можно командой
контекстного меню Paste или комбинацией клавиш Ctrl+V.
72
Для ввода целых чисел предназначены компоненты UpDown и SpinEdit.
Счётчик UpDown применяется совместно с Edit, а компонент SpinEdit
представляет собой сочетание тех же элементов, но уже объединённых в единое
целое. При использовании UpDown и Edit обязательно надо у Edit в свойстве
ReadOnly устаноить true. В этом случае пользователь сможет ввести только
целые числа. Свойства компонента SpinEdit похожи на свойства UpDown, но
он удобнее в использовании, так как предназначен для ввода целых чисел.
Введённое число сохраняется в свойстве Text строкового типа.
7.4. Контроль вводимых данных
В реальных приложениях обеспечение корректности вводимых данных
является обязательным условием. Особой тщательности требует организация
ввода больших объёмов данных. В любом случае желательно использовать
такие компоненты, которые уменьшают количество ошибок. Если есть
возможность организовать выбор значений из списка, то предпочтение следует
отдать компонентам ListBox, ComboBox и их разновидностям.
К сожалению, полностью отказаться от набора данных на клавиатуре, как
правило, не удаётся. Тогда следует рассмотреть возможность использования
компонент, задающих маску ввода (например MaskEdit) или разрешающих
ввод
определённых
значений
(например
SpinEdit).
Иногда
известны
ограничения на вводимые значения. Например, для возраста и стажа работника,
скорости движения поезда, грузоподъёмности пассажирского лифта и др.
можно указать минимальное и максимальное значения, для шифра – количество
символов. Часто в формулировке задачи допустимые значения указываются
явно и, используя свойства MaxValue, MinValue, MaxLength, можно задать
ограничения на значения. Хорошими возможностями для организации
корректного ввода обладает компонент ValueListEditor.
При вводе данных с клавиатуры в обычные поля надо учесть возможность
случайных ошибок: нажатие «неверной» клавиши (например буквы вместо
73
цифры) ни в коем случае не должно приводить к нарушению работы
приложения.
Контролировать данные можно на разных уровнях. Прежде всего,
выполняется контроль по формальным признакам (синтаксический). Например,
если вводится число, то во вводимой последовательности не должно быть букв,
если число целое положительное, то должны вводиться только цифры и т.п.
Для анализа введённых символов целесообразно создавать обработчики
события нажатия клавиш OnKeyPress и события OnChange, возникающего при
любых изменениях в содержимом редактора. Иногда полезно контролировать
свойство Modified, которое при изменении содержимого редактора принимает
значение true. Это свойство можно использовать, например, для принятия
решения о сохранении изменённых данных. До использования функций
преобразования строки в число желательно проверить, задана ли строка, так как
эти функции с пустой строкой не работают.
Фрагменты кода, при выполнении которых возможно возникновение
исключительных ситуаций, необходимо заключать в защищённые блоки (см.
раздел 5). Причём, защищённые блоки надо формировать так, чтобы было
понятно, где возникла ошибка. Нельзя все поля ввода заключать в один блок.
Иногда хорошие результаты даёт использование традиционного подхода к
обработке ошибок. Так, для ввода целых и особенно вещественных чисел
целесообразно использовать процедуру Val. Формируемый в этой процедуре
код ошибки позволяет оперативно реагировать на некорректный ввод (не
прерывая работы программы). При вводе вещественных чисел и особенно при
использовании процедуры Val необходимо проверить, какой используется
разделитель между целой и дробной частью.
Если при вводе данных с клавиатуры была допущена ошибка, то
необходимо:
1) сообщить пользователю об ошибке, по возможности с указанием
причины, и предложить повторить ввод;
74
2) прервать естественное выполнение операторов;
3) очистить поле ввода;
4) передать фокус ввода компоненту, обеспечивающему ввод данных;
5) обеспечить повторный ввод данных.
Неформальный анализ данных определяется спецификой задачи, и в этом
разделе не рассматривается.
7.5. Загрузка данных из файлов
При загрузке данных из файла имя файла может задаваться программно
или выбираться пользователем в процессе работы приложения. Очень просто
организовать доступ к файловой системе с помощью компоненты OpenDialog.
Задание имени файла в программе не означает, что имя всегда одно и то
же. В ряде случаев имя может формироваться программно с учётом текущей
ситуации. При загрузке данных из файла обязательно надо обработать
ситуации, возникающие как при отсутствии заданного файла, так и проблемы с
его открытием. Причём, желательно сообщать пользователю причины, по
которым файл не может быть открыт.
После успешного открытия файла проблемы могут возникнуть при
считывании числовых данных на этапе выполнения преобразований строкачисло. Сказать однозначно, как надо поступить при возникновении ошибки в
данных, полученных из файла, не представляется возможным. Иногда можно
продолжить обработку, просто пропустив данные с ошибками, иногда
приходится корректировать выполняемые действия, а в ряде случаев
приходится прерывать обработку. В хорошо спроектированной программе
предусматривается обработка всех возможных ситуаций.
У всех компонент, работающих со строками класса TStrings, имеются
методы LoadFromFile и SaveToFile, которые значительно облегчают чтение
данных из текстового файла и запись данных в файл. Однако эти методы могут
быть применены только в тех случаях, когда считываются и записываются все
75
данные подряд. Если же требуется выполнить выборочное чтение (запись)
данных, то следует действовать по стандартной схеме работы с файлом [9].
7.6. Примеры
Пример 1. Использование функции random без параметров
Однострочный редактор Edit применяется для задания количества чисел.
Формируемая последовательность выводится в Memo. Вспомогательная
переменная х облегчает запись и восприятие программы. Её использование не
является обязательным.
procedure TForm2.Button1Click(Sender: TObject);
var i:word;
x:extended;
begin
for i:=0 to strtoint(Edit1.Text)-1 do
begin
x:=random;
Memo1.Lines.Add(floattostr(x));
end;
end;
Пример 2. Использование randomize, random и SpinEdit
Целочисленный параметр функции random задаётся в компоненте
SpinEdit. Случайные числа выводятся в Memo.
procedure TForm2.Button4Click(Sender: TObject);
var i:word;
begin
Randomize;
for i:=0 to 9 do
Memo2.Lines.Add(inttostr(random(strtoint(SpinEdit1.Text))));
end;
Пример 3. Ввод целых положительных чисел
Данные вводятся в Edit1. Для этой компоненты в обработчике события
нажатия клавиши разрешается ввод только десятичных цифр. До вызова
функции перевода строки в число проверяется, не является ли строка пустой.
Введённое число с комментарием отображается в метке Label3. При
отсутствии значения в поле ввода на экран выводится окно с сообщением (в две
строчки) и компоненте Edit1 передаётся фокус ввода.
76
procedure TForm1.Button3Click(Sender: TObject);
var a:integer;
begin
if Edit1.Text<>''
then begin
a:=strtoint(Edit1.Text);
Label3.Caption:='Введено число '+inttostr(a);
Label3.Visible:=true;
end
else begin
ShowMessage('В поле ввода пусто.'#13#10'Введите число');
Edit1.SetFocus;
exit;
end;
end;
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
if (key<'0')or (key>'9')then key:=#0;
end;
Пример 4. Ввод вещественного числа процедурой Val
Данные вводятся в Edit2. Преобразование строки в число выполняется
процедурой Val. Анализируется код ошибки. Если в записи числа нет ошибки
(значение кода 0), то полученное число b используется в программе. При
наличии ошибки выводится номер «неверного» символа, компоненту Edit2
передаётся фокус ввода и прерывается выполнение процедуры.
procedure TForm1.Button5Click(Sender: TObject);
var b:extended;
Code:integer;
begin
Val(Edit2.Text,b,Code);
if Code=0
then begin
Label4.Caption:='Введено число '+floattostr(b);
Label4.Visible:=true;
end
else begin
ShowMessage('Ошибка в записи числа в позиции '
+inttostr(Code)+#13#10'Повторите ввод');
Edit2.SetFocus;
exit;
end;
end;
77
Пример 5. Использование события OnChange и свойства Modified
Обработчик события OnChange компонента Edit3 анализирует вводимую
строку. Если оказывается, что количество введённых символов «a» больше
двух, то выводится сообщение. Программно строка не корректируется.
procedure TForm1.Edit3Change(Sender: TObject);
var i,k:byte;
st:string;
begin
k:=0;
st:=Edit3.text;
for i:=1 to length(st) do if st[i]='a' then inc(k);
if k>2 then ShowMessage('Ошибка в записи строки');
end;
В
обработчик
непосредственно
события
перед
формы
закрытием
OnClose,
формы,
которое
введена
происходит
проверка
свойства
Modified компонента Edit3. Если текст в этом компоненте был изменён, то
выполняется запись в файл.
procedure TForm1.FormClose(Sender: TObject; var Action:
TCloseAction);
var f:textfile;
begin
if Edit3.Modified=true
then begin
assignfile(f,'data.txt');
rewrite(f);
write(f,Edit3.Text);
end;
end;
Пример 6. Использование компонент Memo и StaticText
При вводе данных в каждой строке записывается по одному числу, для
перехода к следующей строке нажимается клавиша Enter. Для контроля ввода
данных в редакторы Memo1 и Memo2 сформированы защищённые блоки try…
except. Анализ причин исключительных ситуаций не выполняется, просто
выдаётся сообщение и осуществляется выход их процедуры. При вводе данных
в Memo2 и Memo3 используется
процедура Val. Введённые
данные
записываются в массивы. С целью уменьшения ошибок для Memo2 и Memo3
определены обработчики события OnKeyPress, в которых разрешается
78
использование клавиши Enter, ввод десятичных цифр, знака «минус» и
разделителя.
var y:array[0..100] of integer;
r,rval:array[0..100] of extended;
const n=5;
procedure TForm1.Button6Click(Sender: TObject);
var Code,i:integer;
b:extended;
st:string;
begin //Ввод из Memo
try // Ввод целых чисел
for i:=0 to n-1 do y[i]:=strToInt(Memo1.Lines[i]);
except
ShowMessage('Ошибка при вводе данных');
Memo1.SetFocus;
exit;
end;
//Ввод вещественных чисел
try
for i:=0 to Memo2.Lines.Count-1 do
r[i]:=strTofloat(Memo2.Lines.Strings[i]);
except
ShowMessage('Ошибка при вводе данных');
Memo2.SetFocus;
exit;
end;
//Ввод вещественных чисел процедурой Val
for i:=0 to Memo3.Lines.Count-1 do
begin
Val(Memo3.Lines.Strings[i],b,Code);
if Code=0 then rval[i]:=b else
begin
ShowMessage('Ошибка в записи числа в позиции '
+inttostr(Code)+#13#10'В строке '+inttostr(i));
Memo3.SetFocus;
end ;
end;
end;
procedure TForm1.Memo2KeyPress(Sender: TObject; var Key: Char);
begin
if not(key in ['0'..'9',#13,#10,'-',','])then key:=#0;
end;
procedure TForm1.Memo3KeyPress(Sender: TObject; var Key: Char);
begin
if not(key in ['0'..'9',#13,#10,'-','.'])then key:=#0;
end;
procedure TForm1.Button4Click(Sender: TObject);
79
var st:string;
m,i:integer;
begin
//Вывод данных в StaticText
st:='123';
StaticText1.Caption:='stroka';
m:=strtoint(st);
StaticText1.Caption:=StaticText1.Caption+inttostr(m);
//Вывод данных в Memo
for i:=0 to n-1 do Memo4.Lines.Add(inttostr(y[i]));
for i:=0 to Memo2.Lines.Count-1 do
Memo4.Lines.Add(floattostr(r[i]));
for i:=0 to Memo3.Lines.Count-1 do
Memo4.Lines.Add(floattostr(rval[i]));
if OpenDialog1.Execute then
Memo4.Lines.LoadFromFile(OpenDialog1.FileName);
end;
Пример 7. Использование компонент ListBox, ComboBox и StringGrid
В обработчике OnCreate формы задаётся начальный выбор для списка
ListBox1 и заносятся сведения в StringGrid2. Комбинированный список
ComboBox1 используется для задания варианта исходных данных. В процессе
работы приложения функция выбирается в списке ListBox1. Вычисленные
значения аргумента и функции отображаются в StringGrid1, причём для
преобразования
числа
в
строку
используется
функция
FloatToStrF,
позволяющая задать нужный формат выводимого числа. Сформирован
защищённый блок try… except и предусмотрена обработка исключительной
ситуации, связанной с невозможностью преобразовать строку в число.
procedure TForm1.FormCreate(Sender: TObject);
begin
ListBox1.ItemIndex:=0;
With StringGrid2 do
begin Cells[1,0]:='Вариант 1';
Cells[2,0]:='Вариант 2';
Cells[3,0]:='Вариант 3';
Cells[0,1]:='Начальное значение';
Cells[0,2]:='Конечное значение';
Cells[0,3]:='Шаг';
Cells[1,1]:='2'; Cells[1,2]:='3'; Cells[1,3]:='0,2';
Cells[2,1]:='1'; Cells[2,2]:='1,8'; Cells[2,3]:='0,1';
Cells[3,1]:='10'; Cells[3,2]:='14'; Cells[3,3] :='1';
end;
end;
80
procedure TForm1.Button7Click(Sender: TObject);
var xn,xk,hx,x,f:extended;
i,m:integer;
begin
try
case ComboBox1.ItemIndex of
0: begin
xn:=strtofloat(StringGrid2.Cells[1,1]);
xk:=strtofloat(StringGrid2.Cells[1,2]);
hx:=strtofloat(StringGrid2.Cells[1,3]);
end;
1: begin
xn:=strtofloat(StringGrid2.Cells[2,1]);
xk:=strtofloat(StringGrid2.Cells[2,2]);
hx:=strtofloat(StringGrid2.Cells[2,3]);
end;
2: begin
xn:=strtofloat(StringGrid2.Cells[3,1]);
xk:=strtofloat(StringGrid2.Cells[3,2]);
hx:=strtofloat(StringGrid2.Cells[3,3]) ;
end
else begin
xn:=0.1; xk:=1.2; hx:=0.1;
end;
end;
except
on EConvertError do
begin
ShowMessage('Ошибка преобразования числа');
exit;
end;
end;
m:=round((xk-xn)/hx)+1;
StringGrid1.RowCount:=m+1;
StringGrid1.Cells[1,0]:='x';
StringGrid1.Cells[2,0]:='f';
x:=xn;
for i:=1 to m do
begin
case ListBox1.ItemIndex of
0: f:=sin(x);
1: f:=cos(x);
2: f:=arctan(x-1)+2*x;
3: f:=exp(x*ln(1.5));
end;
StringGrid1.Cells[1,i]:=FloatToStrF(x,ffFixed,8,3);
StringGrid1.Cells[2,i]:=FloatToStrF(f,ffFixed,8,3);
x:=x+hx;
end;
end;
81
ВОПРОСЫ ДЛЯ САМОКОНТРОЛЯ
1. Назовите способы ввода данных в Delphi.
2. В
каких
случаях
для
ввода
данных
целесообразно
использовать
переключатели (функции, реализующие диалоги)?
3. Перечислите способы, используемые для контроля вводимых данных.
4. Почему при использовании нескольких полей ввода их не заключают в один
защищённый блок?
5. Поясните использование функций FloatToStrF и FloatToStr.
6. Назовите константы, задающие формат вещественного числа TFloatFormat.
7. Можно ли в примере 1 оператор
`
Memo1.Lines.Add(floattostr(x));
заменить на оператор
Memo1.Lines[i]:= floattostr(x);
8. Как с помощью функции random можно задать вещественные числа в
диапазоне от 1 до 100?
9. Запишите оператор для занесения данных в ячейку компонента StringGrid,
расположенную во второй строке и третьем столбце.
10. С какой целью в примере 7 используется оператор
a. StringGrid1.RowCount:=m+1;
11. Перечислите компоненты, в которые можно загрузить данные с помощью
процедуры LoadFromFile?
12. Приведите пример ситуации, в которой целесообразно использовать
компонент SpinEdit (UpDown).
13. Запишите оператор, очищающий свойство Caption компонента Label.
14. Как узнать, не является ли строка, записанная в компоненте Edit (Memo,
Label) пустой?
82
8. ОРГАНИЗАЦИЯ ПРИЛОЖЕНИЙ
8.1. Консольные приложения
Консольным называется приложение, имитирующее работу в текстовом
режиме. Пользователь работает с программой практически так же, как в среде
DOS. При запуске консольного приложения Windows выделяет окно как для
DOS-программы, в заголовке окна отображается название исполняемого файла.
Ввод/вывод данных осуществляется с помощью процедур read, readln,
write и writeln. К консольному приложению автоматически подключаются
файлы input и output. Несмотря на то, что пользователь работает с консольным
приложением так же, как с DOS-программой, оно является приложением
Windows и не работает под DOS.
Достоинство
консольных
приложений
–
относительная
простота
использования и лёгкость переноса программ, написанных на языке Pascal, в
систему программирования Delphi. Кроме того, исполняемый ехе-файл
консольной программы намного меньше по размеру (десятки килобайт) по
сравнению с исполняемым файлом Delphi-варианта такой же программы (сотни
килобайт).
Проще всего создать консольное приложение через репозиторий. В
репозитории (команда File|New|Other) на странице New имеется объект
Console
Аpplication,
представляющий
собой
Console
Wizard – Мастер
консольного приложения. Если выбрать этот объект, то будет создан новый
проект, состоящий из одного файла с расширением dpr. Этот файл и является
консольной программой. Созданный Мастером код похож на заготовку
обычной программы на языке Pascal, написанной под DOS. Единственным
отличием является директива $APPTYPE, которая значением CONSOLE
сообщает компилятору, что Delphi-программа работает в консольном режиме.
Консольное приложение можно создать также на основе проекта обычного
приложения
следующим
образом.
Первоначально
по
команде
File|New|Aplication создаётся новое приложение. Консольное приложение не
83
включает формы, поэтому из проекта нужно удалить форму Form1. С этой
целью по команде Project|Remove from Project (Проект|Удалить из проекта)
вызывается диалоговое окно Remove from Project удаления форм из проекта, в
котором для данного проекта содержится один модуль unit1 формы. Нужно
выбрать этот модуль и удалить его.
Затем вызывается окно редактора кода, в нем открывается файл проекта
(dpr), в который вносятся соответствующие изменения.
Далее к заготовке консольного приложения добавляется необходимый код.
Как и любая программа на языке Pascal, консольное приложение может
включать отдельные модули.
program demo;
{$APPTYPE CONSOLE}
uses SysUtils;
begin
writeln('Проверка');
end.
Завершив работу с консольным приложением, нужно нажать клавишу
Enter. После этого окно, в котором функционировало консольное приложение,
автоматически будет закрыто.
Консольное приложение Delphi представляет собой не просто программу,
написанную на языке Object Pascal и выполняемую в среде Windows. Система
Delphi
поддерживает
создание
32-разрядных
консольных
приложений,
имеющих доступ к ресурсам операционной системы и использующих
различные функции API Windows. При этом в разделе uses нужно подключать
модули, средства которых применяются в программе.
Для организации ввода-вывода информации используются стандартные
процедуры:
Read(<файловая_переменная>,<список_ввода>);
Readln(<файловая_переменная>,<список_ввода>);
Write(<файловая_переменная>,<список_вывода>);
Writeln(<файловая_переменная>,<список_вывода>);
Первым параметром в любой из перечисленных процедур может стоять
файловая переменная. В этом случае выполняется обращение к дисковому
84
файлу или логическому устройству, связанному с файловой переменной. Если
файловая переменная не указана, то подразумевается использование текстовых
файлов input или output. Input используется при чтении данных с клавиатуры, а
output – при выводе данных на экран:
Read (a,b,x2);
Readln (p,q5);
Write (n:5,x:4:1;y:7:2);
Writeln (name, ' ':3, 2*x+3:6:0);
Специфика обработки текстовых файлов заключается в том, что процедуры
ввода-вывода позволяют работать со значениями не только символьного типа:
фактическими
параметрами
могут
быть
символы,
строки
и
числа.
Последовательность символов автоматически преобразуется к значению
переменной того типа, который задан в списке ввода-вывода.
При вводе числовых значений процедура Read выделяет подстроку по
следующему правилу:
• все ведущие пробелы, символы табуляции и маркеры конца строк
пропускаются;
• после появления первого значащего символа любой из перечисленных
символов или код конца файла служат признаком конца подстроки.
Выделенная таким образом подстрока рассматривается как символьная
запись числа соответствующего типа и преобразуется во внутреннее
представление; полученное значение присваивается переменной.
Если при вводе чисел нарушен формат (например описана переменная типа
integer, а задано число real), то во время работы программы возникнет
ошибка ввода-вывода. Если при пропуске ведущих пробелов встретится символ
конца файла, то переменная получит значение ноль.
При вводе с клавиатуры символьные строки запоминаются в буфере.
Содержимое буфера передаётся процедуре только после нажатия клавиши
Enter. Это позволяет редактировать данные при вводе. Ввод информации
сопровождается эхо-повтором на экране.
85
Отличие процедуры Readln от Read заключается в том, что после
считывания последней переменной, фигурирующей в списке ввода, оставшаяся
часть строки до маркера конца строки пропускается. Следующее обращение к
Readln или Read выполняет чтение с первого символа новой строки. Readln
можно использовать без списка ввода, это обеспечивает пропуск строки.
Процедуры Write, Writeln выводят информацию в файл или на
логическое устройство. Если файловая переменная описана как текстовая, то
список вывода может содержать символы, строки, вещественные и целые
числа, а также выражения типа boolean. В последнем случае записывается true
или false, в зависимости от текущего значения логической переменной.
Элемент списка вывода, например х, может быть записан в виде x:k:m.
Значение
k
задаёт
ширину
поля
вывода
символьного
представления
переменной x. Если символьное представление имеет меньшую длину, то оно
будет дополнено пробелами слева; если длиннее – то параметр k игнорируется
и переменная выводится целиком. Параметр m определяет выводимое
количество десятичных знаков в дробной части числа. Этот параметр
используется только для вещественных чисел и только совместно с
параметром k. Если ширина поля вывода не указана, то переменные выводятся
подряд,
без
разделения,
вещественные
числа
записываются
в
экспоненциальном формате.
При использовании Writeln выводимая строка завершается символами
конца строки. Последующее применение процедур Write и Writeln
обеспечивает запись информации с новой строки.
8.2. Фокус ввода
Во время работы приложения только один из управляющих элементов
принимает клавиатурный ввод в текущий момент. Такой управляющий элемент
обладает фокусом ввода (сфокусирован).
Передача
фокуса
ввода
выполняется
щелчком
мыши
на
другом
управляющем элементе или нажатием клавиш Tab либо Shift+Tab. При
86
использовании клавиатуры фокус ввода передаётся последовательно от одного
управляющего элемента к другому, причём Tab обеспечивает перебор в
прямом порядке, а Shift+Tab – в обратном. Порядковый номер в очереди,
определяющей получение фокуса ввода, задаётся целочисленным свойством
TabOrder (начиная с нуля). Этот номер действует относительно владельца:
формы или компонента. Первоначально порядок перебора соответствует
очерёдности добавления компонентов на форму, но его можно изменить,
устанавливая требуемые значения свойства TabOrder. Если элементов на
форме много, то удобнее воспользоваться окном EditTabOrder, которое
открывается командой Edit|TabOrder и позволяет быстро и просто задать
нужную очерёдность.
Включением и исключением из очереди управляет свойство TabStop
булевского типа. Обычно значение этого свойства равно true. Если же
установить в этом свойстве false, то управляющий элемент не сможет
получить фокус ввода.
Для управления фокусом ввода программно используется метод SetFocus
и свойство формы ActiveControl. Чтобы передать фокус ввода требуемому
управляющему элементу, надо у него вызвать метод SetFocus, например,
Edit1.SetFocus.
Свойство формы ActiveControl указывает сфокусированный в текущий
момент элемент. Это свойство доступно из Инспектора объектов и может быть
использовано для задания элемента, который первым получит фокус ввода (в
обход очереди). Если значение свойства не задано, то первым фокус ввода
получает управляющий элемент, у которого значение TabOrder равно нулю.
8.3. Запуск других приложений
Приложение, выполняемое в текущий момент времени в операционной
системе, называется процессом (process). Процессу выделяется отдельное
адресное пространство, он характеризуется исполняемым кодом и данными, а
также потреблением ресурсов операционной системы.
87
Процессы порождаются запуском новых приложений. В некоторых случаях
требуется из работающего приложения запустить на выполнение другое
приложение. Например, открыть калькулятор, вызвать программу-архиватор и
др. Запуск одной программы из другой называют «порождением дочернего
процесса».
Запуск внешней программы из приложения Delphi можно выполнить
несколькими способами, предусматривающими использование функций API
Windows: WinExec, ShellExecute и CreateProcess.
Проще всего воспользоваться функцией WinExec, которая работает в
разных версиях Windows и может выполнять как приложения Windows, так и
программы MS DOS:
function WinExec (CmdLine: PChar; CmdShow: integer): integer;
Параметр CmdLine является указателем на строку, содержащую имя
исполняемого файла и при необходимости – дополнительные сведения
(параметры командной строки). Если имя файла указано без пути, то Windows
будет искать его, последовательно просматривая каталоги:
1) тот, из которого было запущено приложение;
2) текущий каталог;
3) системный каталог Windows;
4) главный каталог Windows;
5) каталоги, заданные командой PATH (переменной окружения).
Параметр CmdShow определяет способ отображения окна запускаемого
приложения. Для приложений Windows этот параметр может принимать
большое количество значений [1]. Наиболее часто используются значения
SW_RESTORE и SW_SHOWNORMAL, которые активизируют и отображают
окно в обычном виде. После запуска новое приложение выполняется вне
зависимости от работы вызвавшего его приложения. Функция WinExec
возвращает целое число, которое при удачном запуске больше 32. При
несостоявшемся запуске сообщений на экран не выводится, функция WinExec
возвращается код ошибки (от 0 до 32), который можно обработать программно.
88
Например, для запуска Калькулятора можно записать:
WinExec(PChar('calc.exe'), SW_ShowNormal);
В следующем примере запускается на выполнение приложение Balls.exe.
Так как не указан путь, то это приложение должно быть расположено в одном
из просматриваемых Windows каталогов. Учитывая, что при отсутствии
возможности запустить приложение Windows не выдаёт сообщений, в примере
используется целочисленная переменная cod для обработки ошибки.
procedure TForm1.Button2Click(Sender: TObject);
var cod:byte;
begin
cod:=WinExec('Balls.exe', SW_Restore);
case cod of
0: ShowMessage('Не хватает ресурсов');
2: ShowMessage('Файл не найден');
3: ShowMessage('Путь не найден');
end;
end;
При необходимо можно обеспечить выбор запускаемого приложения
пользователем во время работы. В приведённой ниже процедуре обработки
щелчка
по
кнопке
Button3
используется
стандартное
окно
диалога
OpenDialog1 для задания нужного файла.
procedure TForm1.Button3Click(Sender: TObject);
var cod:byte;
begin
if OpenDialog1.Execute then
begin
cod:= WinExec(PChar(OpenDialog1.FileName), SW_Restore);
if cod=0 then ShowMessage('Не хватает ресурсов');
end;
end;
Функция
ShellExecute
обладает
большими
возможностями,
она
позволяет не только запускать на выполнение заданное приложение, но и
открывать документы и печатать их. Например, обычно с документами,
имеющими расширение .doc, связан редактор Word, а с документами,
имеющими расширение .xls – табличный процессор Excel. Чтобы начать работу
с документом, надо запустить соответствующую программу (в данном случае
Word или Excel) и открыть нужный файл. Кроме того, функция ShellExecute
89
позволяет открыть указанную папку, то есть запустить программу Проводник с
открытой требуемой папкой. Чтобы воспользоваться функцией ShellExecute,
необходимо в раздел uses добавить модуль ShellAPI. При вызове функции
ShellExecute необходимо указать достаточно много сведений:
function ShellExecute (Wnd:HWnd; Operation, FileName,
Parameters, Directory: PChar; CmdShow: integer): THandle;
Параметр Wnd содержит ссылку на окно, из которого запускается новое
приложение. Обычно для задания «родительского» окна используют Handle.
Параметр FileName является указателем на строку, содержащую имя
файла или каталога. Параметр Operation указывает на строку, задающую
выполняемую операцию. Определено три значения: open (открыть файл или
каталог), print (напечатать документ), explore (открыть папку). Если этот
параметр равен nil, то выполняется команда open.
Параметр Parameters указывает на строку, содержащую передаваемые
запускаемому приложению опции. Если же FileName задаёт неисполняемый
файл, то значением этого параметра должно быть nil. Параметр Directory
указывает на строку с именем каталога по умолчанию. Если имя каталога не
задано, то значением этого параметра должно быть nil.
Параметр CmdShow определяет способ отображения окна запускаемого
приложения, может принимать те же значения, что и параметр CmdShow
функции WinExec.
В качестве результата функция ShellExecute возвращает ссылку на
запущенное приложение, значение которой при успешном выполнении больше
32. При неудачном выполнении возвращается код ошибки. Значения кодов
ошибки те же, что и для функции WinExec.
Примеры использования функции ShellExecute:
ShellExecute(Handle,'open','calc.exe',nil,nil,SW_ShowNormal);
ShellExecute(Handle,nil,'текст.doc',nil,nil,SW_ShowNormal);
if OpenDialog1.Execute then
ShellExecute(Handle,'open',PChar(OpenDialog1.FileName),
nil,nil,SW_Restore);
90
ВОПРОСЫ ДЛЯ САМОКОНТРОЛЯ
1. Какие приложения называют консольными?
2. В каких случаях целесообразно использовать консольные приложения?
3. Можно ли в консольном приложении подсоединить имеющийся в Delphi
модуль Math?
4. Как организован ввод и вывод данных в консольных приложениях?
5. Как программно передать фокус ввода нужному компоненту?
6. Как запретить получение фокуса ввода компонентом?
7. Как задать нужную очерёдность получения компонентами фокуса ввода?
8. Какие используются клавиши для перемещения фокуса ввода?
9. Перечислите способы, позволяющие запустить из приложения Delphi
другую программу.
10. Можно ли из приложения Delphi запустить документ Word (Excel)?
11. Проанализируйте примеры, приведённые в конце раздела. Поясните, какие
действия будут выполнены.
12. В программу включён один из операторов, приведённых в конце раздела.
При компиляции проекта выдаётся сообщение о том, что идентификатор
ShellExecute неизвестен. Почему?
13. Запишите оператор, позволяющий вывести на экран html-документ.
14. Запишите оператор, позволяющий вывести на печать html-документ
(текстовый документ).
15. Запишите фрагмент кода, предназначенный для запуска файла .xls и
обеспечивающий обработку исключительных ситуаций.
91
9. ДИАГРАММЫ
9.1. Компоненты для построения диаграмм
В первых версиях системы Delphi для построения графиков и диаграмм
использовались
компоненты,
созданные
другими
инструментальными
средствами. Затем появились компоненты Chart и DBСhart. Эти компоненты
идентичны по назначению, структуре и правилам применения, для них в Delphi
имеется подробный Help. Компонент DBСhart предназначен для построения
диаграмм в приложениях, использующих базы данных, по сравнению с Chart
дополнен свойствами, позволяющими загружать данные из таблиц.
Однако, в VCL на странице ActiveX сохранены компоненты Chartfx и
VtChart. Эти компоненты не документированы и в справочной системе Delphi
сведения о них отсутствуют, хотя файлы справки имеются. Если установить
компонент на форму и через контекстное меню открыть какое-нибудь окно для
задания свойств, то в нём будет кнопка для вызова справки. К сожалению, в
большинстве случаев система не найдёт нужные файлы, так как они
расположены по другому адресу. Уточнить путь к файлам проще всего через
систему поиска Windows.
VtChart – это мастер диаграмм, обеспечивает мощные средства построения
двух- и трёхмерных диаграмм по результатам табличных вычислений. Chartfx
– это редактор диаграмм со встроенной панелью инструментов, даёт
программисту удобное средство для включения в приложения интерактивных
графиков и диаграмм. Параметры диаграммы и исходные данные можно
задавать как на этапе проектирования, так и в процессе выполнения
приложения. Компонент Chartfx рассмотрен в книгах [1] и [4].
При использовании компонент Chartfx и VtChart в некоторых версиях
Delphi возникают сложности, особенно проблематично применение VtChart.
Построение диаграмм с помощью любой из компонент требует задания
большого числа параметров, некоторые из которых являются объектами и
имеют свои свойства. Для удобства задания свойств, кроме Инспектора
92
объектов можно воспользоваться специальными средствами редактирования,
доступ к которым осуществляется через контекстное меню.
9.2. Использование компоненты Сhart
Компонент Сhart позволяет строить диаграммы различных типов, в том
числе
и
объёмные.
Важнейшим
свойством
Сhart
является
свойство
Series[Index:Longint]:TChartSeries, представляющее собой массив
диаграмм, выводимых в области компонента. Каждая серия содержит
последовательность значений, которые задают отдельную диаграмму. При
построении диаграмм часть свойств задаётся в целом для компонента Сhart, а
некоторые свойства уточняются для отдельных серий. При использовании
Сhart можно рекомендовать приводимую ниже последовательность действий.
Поместите на форму компонент Сhart. Появится панель с подготовленным
полем для диаграммы.
Дважды щёлкните левой кнопкой мыши по компоненту или выберите из
контекстного меню команду Edit Chart. Редактор Edit Chart позволяет
задавать
большое
число
параметров.
Причём
изменение
некоторых
характеристик сразу же отображается на диаграмме (например заголовок Title).
Некоторые параметры становятся доступными только после ввода данных. В
редакторе две страницы: Chart и Series, каждая из которых имеет несколько
вкладок. Так, страница Chart содержит вкладки Series, General, Axis, Titles,
Legend, Panel, Paging, Walls, 3D, назначение которых интуитивно понятно. На
вкладках страницы Series (Format, General, Marks, Data Source) задаются
параметры, относящиеся к конкретной серии данных.
В редакторе Edit Chart на странице Chart, вкладке Series щёлкните по
кнопке Add. Появится галерея доступных типов графиков. Страница
TeeChartGallery имеет две вкладки: Standard и Functions. На вкладке Standard
приведены имеющиеся типы диаграмм Line, Bar, Horiz Bar, Area, Point, Pie, Fast
Line, Shape, Gantt, Arrow, Bubble и переключатель для выбора объёмного (3D)
93
или плоского изображения. На вкладке Functions можно выбрать одну из
имеющихся функций: Add, Subtract, Multiply, Divide, High, Low, Average.
Щелчком выберите нужный тип графика. После этого появится значок,
соответствующий выбранному типу графика и надпись Series1. Станут
доступными кнопки Delete, Clone, позволяющие удалить и продублировать
диаграмму, а также кнопка Title, открывающая диалоговое окно для задания
имени серии (по умолчанию имя состоит из слова Series и номера). В
программном коде в разделе описания класса формы появится тип,
соответствующий выбранному графику, например: Series1:TlineSeries. В
дальнейшем тип графика можно будет изменить. Для этого используется
кнопка Change. После выбора типа графика система генерирует случайным
образом данные, чтобы визуально отображать изменения, вносимые в
диаграмму на этапе проектирования. Если запустить проект на выполнение, то
на форме будут видны панель для графика и надпись, сама диаграмма
отображаться не будет до тех пор, пока не будут введены данные.
Задайте программно данные. Важнейшим свойством диаграммы является
сложное свойство Series, которое используется при задании значений. Для
управления значениями, по которым строится диаграмма, используются методы
Add, Delete и Clear. Метод Add применяется для добавления значения в
серию, а метод Delete – для удаления. Метод Clear позволяет очистить всю
серию. Его надо использовать каждый раз перед построением графика по
новым данным. Например:
Series1.Clear;
With Series1 do
begin
Add(10,'Отлично',clTeeColor);
Add(50,'Хорошо',clTeeColor);
Add(40,'Удовлетворительно',clTeeColor);
end;
В методе Add первый параметр задаёт численное значение, второй –
подпись, а третий – цвет. Причём обязательным является только первый
параметр. Цвет можно указать явно, либо записать clTeeColor. Задание
94
clTeeColor означает, что будут использованы цвета по умолчанию. Исходные
данные можно задавать константами, загружать из массивов или из компонент.
for i:=0 to 10 do
begin
Series4.Add(f[i]);
Chart1.Series[4].Add(strtofloat(Memo1.Lines[i]));
end;
Так как серия является свойством Сhart, то обратиться к нужной серии
можно указав её номер. Нумерация начинается с нуля и для задания, например,
серии пять можно записать Chart1.Series[4] или Series5.
При
формировании
различных
типов
диаграмм
используются
модификации метода Add. Для более подробного знакомства следует
обратиться к разделу справочной системы, посвящённому TChartSeries.
Если при построении диаграммы требуется задавать две величины
(аргумент XVal и значение функции YVal), то используется метод AddXY:
AddXY(Const XVal,YVal:Double;Const ALabel:String;Coler:TColor).
Аналогично методу Add, параметр ALabel содержит текст, который будет
отображён на диаграмме и в легенде, а параметр Coler определяет цвет.
for i:=0 to 35 do
begin
x:=Pi/18*i;
Series2.AddXY(x,sin(x),'',clBlue);
Chart1.Series[2].AddXY(x,cos(x),'',clYellow);
end;
В приведённом примере строятся графики функций sin(x) и cos(x). Так
как надписи у значений не нужны, то параметр ALabel задан пустой строкой.
Цвета кривых указаны явно (синий и жёлтый).
ВОПРОСЫ ДЛЯ САМОКОНТРОЛЯ
1. Перечислите параметры, влияющие на оформление диаграммы.
2. Запишите фрагмент кода для построения в одних координатах двух
графиков Fast Line по данным, расположенным в первых двух столбцах
компоненты StringGrid.
3. Как программно изменить параметр? Запишите оператор, запрещающий
вывод легенды. Задайте градиентную заливку фона диаграммы.
95
10. ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ
10.1. Объектная модель
Объектно-ориентированным языкам программирования присущи три
основные черты – инкапсуляция, наследование и полиморфизм.
Инкапсуляция – это объединение данных с процедурами и функциями для
получения нового типа данных – класса.
Класс в Delphi представляет собой единство трех сущностей – полей,
методов и свойств. Инкапсуляция позволяет во многом изолировать класс от
остальных частей программы, сделать его «самодостаточным» для решения
конкретной задачи. В результате класс всегда несет в себе некоторую
функциональность. Например, класс TForm содержит (инкапсулирует в себе)
всё необходимое для создания Windows-окна, класс TTimer обеспечивает
работу программы с таймером и т.д.
Наследование – это определение класса и его дальнейшее использование
для построения иерархии порождённых классов с возможностью доступа для
каждого порождённого класса к коду и данным предка. Порожденный класс
автоматически наследует поля, методы и свойства родителя и может дополнять
их новыми. Таким образом, принцип наследования обеспечивает поэтапное
создание сложных классов и разработку собственных библиотек классов.
В Delphi существует предопределённый класс TObject, который служит
неявным предком тех классов, для которых предок не указан. Класс TObject
выступает корнем иерархии классов. Он содержит ряд методов, которые по
наследству передаются всем остальным классам (Create, Destroy и др.).
Механизмы наследования полей, свойств и методов различаются.
Порождённый класс наследует от родителя все поля данных. Доступ к
полям предка осуществляется по именам (так, как если бы они были
определены в потомке). В наследниках можно определять новые поля, но их
имена должны отличаться от имён предка.
96
Свойство базового класса можно перекрыть (override) в производном
классе, например, чтобы добавить ему новый атрибут доступа или связать с
другим полем или методом.
Метод базового класса тоже можно перекрыть в потомке. При этом в
наследнике можно вызвать перекрытый метод предка, указав перед именем
метода зарезервированное слово inherited.
Полиморфизм – это использование одинаковых имён методов на разных
уровнях иерархии. При этом каждый класс реализует метод удобным для него
образом. Полиморфизм обеспечивает классам возможность решать схожие по
смыслу проблемы разными способами. В Delphi поведенческие свойства класса
определяются набором входящих в него методов. Изменяя алгоритм того или
иного метода в потомках класса, программист может придавать этим потомкам
отсутствующие у родителя специфические черты. Для изменения метода
необходимо перекрыть его в потомке, то есть объявить в потомке одноименный
метод и реализовать в нем нужные действия. В результате в объекте-родителе и
объекте-потомке будут действовать два одноименных метода, имеющие разную
алгоритмическую основу и, следовательно, придающие объектам разные
свойства.
10.2. Объекты и классы
Концепция объектно-ориентированного программирования основана на
понятиях объекта и класса.
Классом в Delphi называется тип данных, содержащий поля, методы и
свойства. Как и любой другой тип, класс даёт обобщённое описание, служащее
образцом для создания конкретных экземпляров реализации.
В языках С++ и Delphi (Object Pascal) объекты – это программные
конструкции,
формируемые
классами.
Объект
является
конкретным
экземпляром класса. Класс определяет категорию объектов, содержит как
объявление данных, так и функции их обработки. Пользователю, как правило,
предоставляется описание класса, а не его реализация. Главная забота класса –
97
скрыть как можно больше информации. Объекты же – это конкретные
представители класса, экземпляры класса.
Важным отличием классов от других типов является то, что экземпляры
класса всегда распределяются в куче. Объекты фактически представляют собой
лишь указатели на динамическую область памяти.
Классы определяются в секции type глобального блока. По форме
объявления классы похожи на записи. Описание класса начинается служебным
словом class и завершается словом end. Объекты описываются в разделе var.
Поля класса аналогичны полям записи и служат для хранения данных.
Методами называют процедуры и функции, предназначенные для обработки
полей. Свойства реализуют механизм доступа к полям.
В описание класса включаются заголовки методов, которые играют роль
предварительных объявлений. Программный код методов помещается ниже
определения класса. В программе может быть объявлено несколько объектов,
принадлежащих к одному классу.
Type
TMyClass = class(TParentClass)
<поля>;
<свойства>;
<методы>;
. . .
end;
Var
MyClass1, MyClass2: TMyClass;
MyClass1, MyClass2 – это ссылки на объекты, которых ещё физически
не существует. Объекты появятся в процессе работы программы. После
создания объект можно использовать в программе. Доступ к полям и методам
объекта выполняется с помощью составных имён:
<имя объекта>.<имя поля>
<имя объекта>.<имя процедуры>
Для сокращения текста кода можно использовать оператор with.
Когда объект станет не нужен, он должен быть уничтожен вызовом
специального метода. Объекты могут выступать в программе не только в
качестве простых переменных, но и в качестве элементов массивов, полей
98
записей, параметров процедур и функций. Объекты могут служить полями
других объектов.
10.3. Поля
Полями называются инкапсулированные в классе данные. Поля могут быть
любого типа, в том числе – классами. Имена полей должны начинаться с буквы
f, например:
Type
TNewClass = class
FCod: Integer;
FCh: Char;
FObjField: TList;
...
end;
Каждый объект получает уникальный набор полей, но общий для всех
объектов данного класса набор методов и свойств. Фундаментальный принцип
инкапсуляции требует обращаться к полям только с помощью методов и
свойств класса. Однако в Delphi разрешается обращаться к полям и напрямую:
Var
NewClass: TNewClass;
Begin
...
FCod:=0;
FCh:=‘с’;
...
End;
Класс-потомок получает все поля всех своих предков и может дополнять
их своими, но он не может переопределять или удалять поля предка. Таким
образом, чем ниже в дереве иерархии располагается класс, тем больше данных
получают в свое распоряжение их объекты.
10.4. Свойства
Свойства объектов аналогичны свойствам, которые мы наблюдаем у
обычных предметов. Значения свойств можно читать и устанавливать.
Например, панель имеет свойство «цвет». Значение этого свойства хранится в
одном из полей. Чтобы узнать цвет, надо прочитать значение соответствующего
99
поля; чтобы изменить цвет, надо вызвать метод, который перерисует панель в
соответствии с новым значением поля, содержащего цвет панели.
Таким
образом,
свойства
–
это
специальный
механизм
классов,
реализующий доступ к полям. Обычно свойство связано с некоторым полем и
указывает те методы класса, которые должны использоваться при записи
данных в это поле и при чтении значений из него. Описание свойства
начинается со слова property, при этом тип свойства и соответствующего
поля должны быть одинаковыми.
property Cod: integer read FCod write FCod;
property Ch: сhar read FCh write FCh;
property PercentCritical: integer read FPercentCritical write
SetPercentCritical;
После слова read указывается поле или метод, к которому происходит
обращение при чтении значения свойства, а после слова write – поле или
метод, к которому происходит обращение при записи свойства. Атрибуты read
и write называют спецификаторами доступа. Если один из них опущен, то
свойство можно только читать (задан read) или только записывать (задан
write). Метод чтения поля – это всегда функция, возвращающая значение того
же типа, что и свойство. Метод записи свойства – это всегда процедура,
принимающая параметр того же типа, что и тип свойства. Один и тот же метод
может использоваться для получения (установки) значений нескольких свойств
одного типа. В этом случае каждому свойству назначается целочисленный
индекс, который передаётся в метод первым параметром.
При работе с объектом свойства выглядят как поля: они принимают
значения и участвуют в выражениях. Но в отличие от полей, свойства не
занимают места в памяти, а операции их чтения и записи ассоциируются с
обычными полями и методами. Так как свойства не имеют адреса в памяти, к
ним нельзя применить операцию @ и их нельзя передавать в качестве
параметров-переменных (Var) процедур и функций.
Технология ООП в Delphi предписывает избегать прямого обращения к
полям, создавая вместо этого свойства. Это упорядочивает работу с объектами,
100
изолируя их данные от непосредственной модификации. Для программиста
свойства имеют первостепенное значение. Чтобы понять суть и назначение
объекта, надо знать его свойства, реже методы и очень редко – поля (объект сам
знает, что с ними делать).
Обычно свойство связано с некоторым полем, но это не обязательно.
Фактически свойство описывает один или два метода, которые осуществляют
некоторые действия над данными того же типа, что и поле. Кроме обычных
свойств у объектов существуют свойства-массивы (array properties). Свойствомассив – это индексированное множество свойств.
10.5. Методы
Метод
(правило)
представляет
собой
процедуру
или
функцию,
определенную в рамках класса, и используемую для выполнения действий над
полями. В разделе interface содержится объявление методов (при описании
класса), а в разделе implementation записывается программный код. В
отличие от обычных процедур и функций заголовки методов должны иметь
составные имена, содержащие наименование классов. Внутри методов
обращения к полям и другим методам выполняется как к обычным переменным
и подпрограммам, без уточнения объекта.
Следуя
логике
объектно-ориентированного
программирования,
все
мыслимые действия над полями объекта необходимо определять в виде правил
– процедур и функций. Именно это в конечном итоге обеспечивает простоту и
универсальность
ООП,
так
как
описание
каждого
класса
становится
функционально завершённым на соответствующем уровне иерархии. Описание
класса
получается
громоздким,
но
очень
удобным
для
дальнейшего
использования.
Наиболее полно стараются описать классы, расположенные на верхних
уровнях иерархии. При этом можно не заботиться о том, что какой-либо метод
не будет использован, так как код методов, к которым нет обращения в
программе, компилятор не включает в exe-файл.
101
Type
TMyClass = class
Function MyFunc (aPar: Integer): Integer;
Procedure MyProc;
End;
Var
aObject: TMyClass;
...
Begin
...
aObject.MyProc;
...
end;
Методы класса могут перекрываться в потомках. Например:
Type
TParentClass = class
Procedure DoWork;
End;
TChildClass = Class (TParentClass)
Procedure DoWork;
End;
Потомки обоих классов могут выполнять сходную по названию процедуру
DoWork, но, в общем случае, будут это делать по-разному. Такое замещение
методов называется статическим, так как реализуется компилятором.
В состав любого класса входят два специальных метода – конструктор и
деструктор. У класса TObject эти методы называются Create и Destroy, так
же они называются в подавляющем большинстве его потомков. Обращение к
конструктору должно предварять любое обращение к полям и некоторым
методам объекта.
DiskGauge:=TDiskGauge.Create;
Конструктор создаёт объект. Создание объекта включает выделение памяти
и инициализацию полей. Распределив объект в динамической памяти,
конструктор помещает адрес этой области памяти в переменную Self, которая
автоматически объявляется в классе. Деструктор разрушает объект: очищает
поля и удаляет объект из кучи (освобождает память):
DiskGauge.Destroy;
После вызова деструктора обращаться к полям и методам объекта нельзя.
Так как действия, выполняемые при создании и разрушении разных
объектов, могут быть специфичными, то Delphi позволяет переопределить
102
стандартные конструктор Create и деструктор Destroy. Можно даже
определить несколько конструкторов и деструкторов, выполняющих свою
работу разными способами. Объявление конструкторов и деструкторов
аналогично объявлению обычных процедур, только вместо слова procedure
используются constructor и destructor.
Конструктор может иметь параметры, через которые передаются исходные
значения полей. Конструктор может применяться к классу или объекту. При
применении конструктора к классу выполняются действия:
• выделяется в памяти место под объект;
• выделенная память заполняется. Поля, содержащие указатели и
объекты, получают значение nil. Числовые поля заполняются нулями.
Строки задаются пустыми;
• выполняются действия, определяемые конструктором;
• ссылка на созданный объект возвращается в качестве значения
конструктора. Тип возвращаемого значения совпадает с типом класса,
использованного при вызове.
При применении конструктора к объекту новый объект не создаётся,
происходит переинициализация полей существующего. В этом случае
конструктор не возвращает никакого значения.
Деструктор уничтожает объект, к которому применяется: выполняется
заданный программный код деинициализации, освобождается занимаемая
объектом динамическая память. В теле деструктора должны уничтожаться
встроенные объекты и динамические данные, созданные конструктором.
Вызов деструктора для несуществующего объекта недопустим, если это
сделать,
то
произойдёт
ошибка.
Чтобы
освободить
программиста
от
необходимости контролировать наличие объекта и его состояние (равен или нет
nil), ввели предопределённый метод Free, который следует вызывать вместо
деструктора. Метод Free сам вызывает Destroy, но только если значение
объекта не равно nil.
103
DiskGauge.free;
Большинство конструкторов реализуют некоторые действия, необходимые
для правильной работы объекта. Поэтому в конструкторе класса-потомка надо
сначала вызвать конструктор родителя, а потом задать дополнительные
действия.
Вызов
любого
перекрытого
метода
родительского
класса
выполняется с помощью зарезервированного слова inherited.
Constructor TMyClass.create(mmm:byte);
begin
inherited Create;
intfield:=mmm;
end;
Метод, объявленный в классе, в зависимости от вида может вызываться
разными способами. Вид метода задаётся служебным словом (модификатором),
которое указывается в описании класса после заголовка метода и отделяется от
него точкой с запятой. Основные типы методов:
• abstract – абстрактный;
• virtual – виртуальный;
• dynamic – динамический;
• override – перекрывающий;
• message – обработки сообщения.
Методы принято разделять на обычные (статические) и динамические. При
обращении к обычному методу компилятор точно знает класс, которому
данный метод принадлежит.
В Delphi чаще используется динамическое замещение методов на этапе
выполнения программы. Для этого метод, замещаемый в родительском классе,
должен
объявляться
как динамический (с директивой dynamic) или
виртуальный (virtual). В производных классах (потомках) виртуальный и
динамический методы перекрываются с использованием слова override.
Перекрывающий метод должен иметь точно такой же список параметров, что и
перекрываемый. Суть динамического замещения методов в том, что они
вызываются по фактическому типу экземпляра. Работа виртуальных методов
104
основана на механизме позднего связывания, в отличие от раннего связывания,
характерного для обычных методов. Позднее связывание основано на
вычислении адреса вызываемого метода при выполнении программы. Адрес
вычисляется по хранящемуся в каждом объекте описателю типа. Виртуальные
методы позволяют в полной мере реализовать идею полиморфизма.
Разница между виртуальным и динамическим методами заключается в
особенностях создаваемых таблиц и, как следствие, в разной скорости работы.
Встретив метод, объявленный как виртуальный или динамический, компилятор
создаёт таблицу DMT (Dinamic Method Table) или VMT (Virtual Method Table) и
помещает в неё адреса точек входа соответственно динамического или
виртуального методов. При каждом обращении к замещаемому методу
компилятор вставляет код, позволяющий извлечь адрес точки входа в
подпрограмму из той или иной таблицы. Когда в классе-потомке встречается
метод, объявленный с директивой override, компилятор создаст код, который
на этапе прогона программы поместит в родительскую таблицу точку входа
метода класса-потомка, что позволит родителю выполнить нужное действие с
помощью нового метода. Таблица динамических методов содержит адреса
только тех методов, которые объявлены как dynamic в данном классе, в то
время как таблица VMT содержит адреса виртуальных методов не только
данного метода, но и всех его родителей. Значительно большая по размеру
таблица VMT обеспечивает более быстрый поиск. При использовании
динамического метода программа сначала просматривает таблицу DMT у
объекта, а затем у его родительского класса и так далее, пока не будет найдена
нужная точка входа.
При построении иерархии классов часто возникает ситуация, когда работа
виртуального метода в базовом классе неизвестна и наполняется содержанием
только в потомках. В этом случае метод объявляется абстрактным. После слова
virtual записывается директива abstract, что исключает необходимость
написания кода для виртуального метода.
105
Абстрактный метод подразумевает конкретное действие, а не способ его
реализации. Реализацию такие методы получают в наследниках.
Классы, содержащие абстрактные методы, называются абстрактными.
Объекты абстрактных классов никогда не создаются. Для использования
абстрактных классов в библиотеку классов включаются потомки.
Например, для разных геометрических фигур можно определить единые
методы show, hide, moveto и абстрактный метод draw. Метод draw для
каждой фигуры реализуется по-разному.
10.6. Управление доступом к классу
Существует три типа пользователей класса:
• сам класс (методы класса могут обращаться к другим методам и данным
класса);
• обычные пользователи, то есть программы пользователя;
• производные классы (методы производного класса могут обращаться к
методам или данным базового класса).
Каждый пользователь обладает разными привилегиями доступа. Уровни
доступа задаются ключевыми словами private, public, protected. Приватные
члены класса, объявленные в секции private, имеют самую ограниченную
область действия. Они доступны только внутри методов данного класса и
подпрограмм, находящихся в том же модуле. Элемент, объявленный как private,
недоступен даже ближайшим потомкам класса, если они размещены в других
модулях. Обратите внимание, что приватные данные видимы, но недоступны.
Такой контроль введен для предотвращения случайного доступа к данным или
внутренним функциям, то есть в целях уменьшения ошибок при разработке
программ, но не для предотвращения «взлома»
Ко всему, что объявлено в секции public, разрешен неограниченный
доступ. В частности, можно все содержимое класса объявить общедоступным и
манипулировать им, как заблагорассудится. При определении класса часть
методов, свойств и полей можно скрыть от пользователя, но сделать
106
доступными для производных классов, поместив их в секцию с ключевым
словом protected. Элементы описания, размещённые в защищённой секции
доступны только методам самого класса и любым его потомкам, независимо от
того, находятся они в том же модуле, или нет.
Кроме перечисленных выше секций есть ещё одна – published. Правила
видимости у этой секции такие же, как у public. Особенность в том, что для
элементов, помещённых в эту секцию, генерируется информация, позволяющая
превращать их в компоненты. Те свойства, которые должны быть доступны в
Инспекторе объектов, обязательно надо поместить в эту секцию. Секция
published используется при разработке компонентов.
По умолчанию (без указания типа секции) секция считается объявленной
как published. Такая секция помещается в самом начале объявления класса
любой формы и продолжается до первой объявленной секции, в неё Delphi
помещает описания расположенных на форме компонентов.
ВОПРОСЫ ДЛЯ САМОКОНТРОЛЯ
1. Поясните,
в
чём
суть
принципов
инкапсуляции,
наследования
и
полиморфизма.
2. Дайте определение класса.
3. У каких классов больше полей: расположенных выше или ниже по
иерархии?
4. Что такое объект?
5. Что такое поле (свойство, метод)?
6. Что общего и в чём различие в наследовании полей, свойств и методов?
7. Какой класс называется абстрактным?
8. Какие существуют методы?
9. Что общего и в чём различие виртуальных и динамических методов?
10. Перечислите секции в объявлении класса, определяющие видимость
(доступность) сделанных объявлений.
11. Для чего предназначены методы Create, Destroy, Free?
107
11. КЛАСС TAPPLICATION
Класс TApplication описывает приложение в целом. При каждом запуске
приложения система Delphi автоматически создает экземпляр Application
класса TApplication (если приложение Delphi не является приложением Web
сервера, панели управления или службой Windows NT). По сути, объект
Application
является
окном
Windows.
Методы
и
свойства
класса
предназначены для создания, исполнения, поддержки и закрытия приложения.
TApplication позволяет:
• обработать сообщения Windows;
• организовать работу справочной системы;
• обработать клавиши и пункты меню;
• обработать ошибки;
• управлять основными классами, объявленными в ОС Windows.
TApplication не отображается на панели компонентов и не доступен в
режиме дизайна визуально. Однако некоторые его public свойства могут быть
заданы или изменены на закладках Forms и Application в диалоговом окне
Project Options. Кроме того, можно поместить на форму компонент
TApplicationEvents, чтобы задать обработчики событий в приложении.
Свойства и методы объекта Application доступны только программно.
Этот объект фигурирует в файле проекта .dpr. При создании нового
приложения в файл проекта автоматически добавляются вызовы методов
Initialize, CreateForm, Run. Код файла проекта был приведён в разделе 1.
Процедура
Initialize
инициализирует
приложение.
При
этом
выполняются операторы раздела инициализации всех модулей. Процедура
CreateForm создаёт форму. Владельцем созданной формы является объект
Application. Обычно этот метод вызывается автоматически для всех форм
приложения. Процедура Run запускает приложение на выполнение. При
желании вместо автоматического создания формы можно предусмотреть вызов
108
метода CreateForm в процессе работы приложения. Предварительно надо
командой Project Options открыть окно параметров проекта, перейти на
вкладку Forms и перенести формы, которые должны создаваться по мере
необходимости, из панели Auto-create forms в Available forms.
TApplication предоставляет свойства, с помощью которых можно
отслеживать состояние приложения и контролировать некоторые аспекты его
поведения. Свойство Active определяет активность приложения, возвращает
значение true, если приложение в текущий момент имеет фокус ввода. В этом
случае свойство Active одной из форм тоже будет равно true. Обычно это
свойство используется для выяснения, имеет ли приложение фокус ввода,
например перед выводом строки состояния или перед прорисовкой. Свойство
доступно только для чтения. Следует помнить, что даже неактивное
приложение продолжает получать сообщения о перемещении мыши.
Свойство EXEName представляет собой строку, содержащую полный путь
выполняемого файла. Чаще всего оно используется для определения рабочего
каталога приложения, в котором могут находиться файлы данных или
инициализации программы. Это свойство доступно только для чтения и только
во время работы приложения. Для получения из EXEName рабочего каталога и
имени файла используются функции ExtractFilePath и ExtractFileName.
В свойстве Hint содержится текст, который будет выведен при
наступлении события OnHint. Свойство ShowHint определяет, выводить ли
подсказку. Задание значения false в свойстве ShowHint отключает систему
подсказок для всех элементов приложения, независимо от их индивидуальных
установок. Обычно оно используется совместно с пунктом меню, включающим
или отключающим подсказки.
Свойства HintColor, HintPause, HintHidePause и HintShortPause
задают параметры всплывающей подсказки: цвет фона, временные задержки.
По умолчанию цвет фона жёлтый, текст подсказки появляется через 0,5 с после
наведения указателя мыши на визуальный компонент и отображается в течение
109
2,5 с. Свойства HintPause и HintHidePause позволяют изменить задержку (в
миллисекундах) перед выводом окна подсказки и интервал, в течение которого
подсказка видна. Свойство HintShortPause определяет задержку перед
отображением подсказки, если активна подсказка другого компонента.
Свойство Icon позволяет изменить пиктограмму во время работы. Это
очень полезно, если требуется отслеживать состояние приложения. Если иконка
не задана, то используется иконка Delphi. Если для главной формы в свойстве
Icon задан файл с пиктограммой, то эта пиктограмма отображается на кнопке
приложения в панели задач. Иначе используется иконка, установленная в
свойстве Icon объекта Application.
Свойство Title определяет заголовок приложения. По умолчанию
название приложения совпадает с именем исполняемого файла. При желании
приложению можно дать имя, совпадающее с заголовком главной формы.
Строка, записанная в свойстве Title, отображается в панели задач при
сворачивании приложения.
Свойство HelpFile определяет имя справочного файла. По умолчанию
значением свойства HelpFile является пустая строка. Используя это свойство,
можно в процессе работы подсоединять разные справочные файлы.
Свойство Terminated имеет тип Boolean. Если значение свойства равно
true, то приложение получило сообщение о закрытии.
Первоначально некоторые параметры проекта (Title, Icon, HelpFile)
разработчик задаёт в диалоговом окне Project Options. Установки, сделанные в
окне опций проекта, автоматически вносятся в соответствующие файлы.
Методы
Minimize
и
Maximize
заставляют
приложение
принять
свернутый и развернутый вид. Подобный результат обеспечивает свойство
WindowState объекта TForm. Однако использование методов Minimize и
Maximize объекта Application позволяет выполнять операции более
корректно.
Вызов
метода
ProcessMessages
вынуждает
приложение
обработать имеющиеся сообщения. Это полезно делать, например, в длинном
110
цикле. Иначе при выполнении длительных операций приложение не реагирует
на поступающие сообщения: бесполезно пытаться переместить окно, щёлкать
по кнопкам, пунктам меню и т.п. Поэтому рекомендуется включать метод
ProcessMessages
в
циклы
длительной
обработки
данных,
чтобы
принудительно обработать все находящиеся в очереди сообщения. В частности,
сообщения могут содержать сведения, влияющие на работу цикла. Для анализа
таких сообщений надо после команды Application.ProcessMessages
разместить операторы проверки условия прерывания цикла и операторы,
осуществляющие выход из цикла.
Метод Terminate позволяет корректно прекратить работу приложение.
Метод Terminate вызывает функцию Windows API – PostQuitMessage, чтобы
совершить запланированное закрытие приложения. Вызов этого метода
приводит к освобождению памяти, занятой объектами, и завершению
приложения. Причём, процедура Terminate не закрывает приложение
немедленно, а дожидается обработчика события и завершения всех других
процессов. Terminate вызывается автоматически на закрытие формы и на
сообщение WM_QUIT. Вместо метода Terminate часто используется
процедура Close главной формы.
Доступ
к
командам
Windows
Help
API
обеспечивает
HelpCommand (Command : Word; Data : Longint) : Boolean.
функция
Метод
HelpCommand запускает файл winhelp.exe, передаёт ему команду, заданную
параметром Command, и данные, определяемые параметром Data. В результате
появляется соответствующее окно справочной системы Windows. Эта функция
вызывается после задания в программе файла справки через свойство
HelpFile.
Функция
HelpContext(Context:THelpContext):Boolean
выводит окно справочной системы Windows и отображает экран, указанный
параметром Context. Предварительно через свойство HelpFile необходимо
задать имя файла справки.
111
События OnActivate и OnDeactivate оповещают программу об
изменении свойства Active. Приложение становится активным сразу после
запуска или когда на одно из его окон перевели фокус ввода. Приложение
становится неактивным, когда из его окон фокус ввода перемещается на другое
приложение.
Событие OnException вызывается при необработанной исключительной
ситуации. Событие OnHint генерируется при перемещении указателя мыши
над объектом – потомком TControl, если его свойство Hint не является
пустой строкой.
Событие OnIdle генерируется при простое приложения. Обработчик
события OnIdle используется для выполнения фоновых задач. Операции,
включённые в этот обработчик, выполняются каждый раз, когда приложение
заканчивает текущую работу и переходит в режим ожидания (например
ожидает ввода и не занято обработкой события). Код обработчика события
OnIdle должен занимать мало памяти и выполняться быстро, чтобы не
тормозить работу приложения. Событие OnIdle имеет тип TIdleEvent,
описанный следующим образом:
type TIdleEvent=procedure(Sender:TObject;var Done:Boolean)of
object;
Обработчик получает логический параметр Done, который определяет
правила поведения приложения в режиме ожидания. Если Done равно true, то
обработчик не запустится до тех пор, пока не будет получено и обработано
очередное сообщение. Если параметру Done установить значение false, то
обработчик запустится, как только приложение перейдёт в режим ожидания. По
умолчанию Done имеет значение true. Так как в процессе функционирования
обработчика приложение не реагирует на сообщения, то рекомендуется
использовать короткий обработчик, либо включать в него процедуру
ProcessMessages. Процедура обработки события OnIdle обычно (но не
всегда!) описывается и используется в модуле главной формы приложения.
112
Событие OnTerminate генерируется после выполнения метода Execute
потока, но перед тем как поток уничтожается. Это событие можно использовать
для исполнения кода после того, как поток закончит выполняться.
ВОПРОСЫ ДЛЯ САМОКОНТРОЛЯ
1. В чём заключается особенность в задании свойств объекта Application?
2. Как на этапе проектирования можно задать некоторые параметры проекта?
3. Как создаются обработчики событий объекта Application?
4. В каких случаях целесообразно отказаться от автоматического создания
форм в файле проекта?
5. Какое
название
отображается
на
панели
задач
при
сворачивании
приложения?
6. Можно ли сразу для всех элементов приложения отключить вывод
всплывающих подсказок?
7. Если на главной форме и в свойстве Icon объекта Application указаны
разные иконки, то какая из них будет отображена на панели задач?
8. В какой ситуации изменяется значение свойства Terminated?
9. Какие действия реализованы в методе ProcessMessages?
10. Проанализируйте приведённый ниже код.
Application.ProcessMessages;
if form1.Modalresult=mrOk then exit;
11. Какой метод можно применить вместо метода Terminate?
12. Когда генерируется событие OnIdle?
13. Когда и как используется обработчик события OnIdle?
14. Какие действия выполняются в приведённой ниже процедуре?
procedure TForm1.Button1Click(Sender: TObject);
begin
if not Assigned(Form2)then Form2:=TForm2.Create(self);
if Form2.ShowModal=mrOk then
begin
if not Assigned(Form3)then Form3:=TForm3.Create(self);
Form3.Show;
end;
end;
113
12. КЛАССЫ ОБЩЕГО НАЗНАЧЕНИЯ
Для управления основными структурами данных в Delphi разработан ряд
классов. Классы для работы со списками, коллекциями, словарями, потоками
сосредоточены в модуле Classes. Наиболее нужными являются списки TList,
TStrings, TStringList и потоки TStream, THandleStream, TFileStream,
TMemoryStream, TBlobStream.
Разработанные классы являются универсальными. Они очень широко
используются не только при создании программ пользователями, но и в
библиотеке компонентов (VCL).
12.1. Класс TList – списки
Класс TList позволяет создать набор из произвольного числа элементов и
организовать индексный доступ к ним, как это делается при работе с
массивами. Размер списка динамически изменяется в процессе работы
программы, ограничивается лишь доступной памятью. Список может состоять
из элементов разных типов. Свойства и методы класса TList позволяют
находить в списке заданные элементы, добавлять новые, удалять, менять
местами, сортировать элементы.
Технически списки представляют собой массивы нетипизированных
указателей
на
размещённые
в
динамической
памяти
элементы.
Нетипизированные указатели позволяют ссылаться на произвольные элементы.
Свойства класса Tlist
Count: integer – количество помещённых в список элементов. Это
свойство изменяется при добавлении и удалении элемента.
Capacity: integer – мощность (ёмкость) списка – содержит количество
элементов массива указателей коллекции; всегда больше Count. Если при
добавлении очередного элемента Count стало равно Capacity, происходит
автоматическое расширение списка: наращивание ёмкости на фиксированную
величину (для Count меньше 5 – на 4 элемента, для Count 5..7 – на 8, для
114
Count больше 7 – на 16 элементов). Сначала резервируется память для
расположения расширенного массива указателей, затем в неё копируется
содержимое
уничтожается.
старого
Если
массива,
заранее
после
известно,
чего
старый
сколько
массив
элементов
указателей
необходимо
поместить в список, то в начале работы нужно установить значение свойства
Capacity – это снизит непроизводительные затраты на расширение списка.
Items(Index: integer): pointer – возвращает указатель на элемент
списка по его индексу. Самый первый элемент списка имеет индекс 0.
Используется для обращения к элементу по номеру.
List: pPointerList – возвращает массив указателей на элементоы
списка.
Методы класса TList
Add (Item: Pointer): integer – функция, добавляет элемент Item в
конец списка и возвращает его индекс. Предварительно необходимо
сформировать в динамической памяти элемент и получить ссылку Item.
Insert (Index: integer; Item: Pointer) – процедура, вставляет
элемент Item в позицию Index списка; новый элемент получает индекс Index,
все элементы с номерами Index и больше увеличивают свой индекс на 1. При
необходимости расширяет список. Так же как и функция Add, работает с
указателем Item на элемент, предварительно размещённый в динамической
памяти.
Exchange(Index1, Index2: integer) – процедура, меняет местами
элементы с номерами Index1 и Index2.
Move
(CurIndex,
NewIndex:
integer) – процедура, перемещает
элемент в списке с позиции CurIndex в позицию NewIndex.
First: Pointer – функция, возвращает указатель на первый элемент.
Last: Pointer – функция, возвращает указатель на последний элемент.
IndexOf (Item: Pointer): integer – функция, отыскивает в списке
элемент Item и возвращает его индекс.
115
Clear – процедура, очищает список, удаляя из него все элементы.
Устанавливает в свойствах Count и Capacity значение 0.
Delete (Index: integer) – процедура, удаляет из списка элемент с
номером Index. Все элементы, расположенные за удаляемым, смещаются на
одну позицию вперёд.
Remove (Item: Pointer): integer – функция, отыскивает в списке
элемент Item и удаляет его. Возвращает индекс удалённого элемента.
Expand: TList – функция, расширяет массив элементов, увеличивая
Capacity.
Pack – процедура, упаковывает список, удаляет пустые элементы в конце
массива индексов.
Sort (Compare: TListSortCompare) – процедура, сортирует список по
критерию, устанавливаемому функцией Compare: в качестве единственного
параметра она получает ссылку на функцию, которая сравнивает два элемента.
Тип TListSortCompare определён следующим образом:
TListSortCompare = function (Item1, Item2: Pointer): integer;
Функция Compare получает указатели на два элемента списка и выполняет
сравнение.
Результат
сравнения
любое
отрицательное
число,
если
Item1^<Item2^; 0, если Item1^=Item2^ и любое положительное число, если
Item1^>Item2^.
Так как заранее неизвестно, к какому типу данных принадлежат элементы
списка, то критерий сравнения устанавливается программистом и реализуется в
функции
Compare.
Например,
элементы
списка
являются
записями,
содержащими три поля: номер зачетной книжки, ФИО, год рождения.
Type TstudentList=record
Number:LongInt;
FIO:String[30];
Year:byte
end;
Var PstudentList:^TstudentList;
Если необходимо выполнить сортировку по номеру зачётной книжки, то в
функции Compare необходимо сравнивать поля Number.
116
function Compare(Item1,Item2:Pointer):Integer;
begin
if PstudentList(Item1)^.Number<PstudentList(Item2)^.Number
then Result:= -1
else if PstudentList(Item1)^.Number>PstudentList(Item2)^.Number
then Result:= +1 else Result:= 0;
end;
Следует учитывать, что методы Clear, Delete, Remove не освобождают
память, связанную с каждым удалённым элементом. Данные, распределённые в
памяти, программист должен уничтожить сам (если это необходимо).
12.2. Классы TStrings и TStringList
Классы TStrings и TStringList служат для представления списка
элементов, каждый из которых представляет собой пару строка-объект, где
строка – собственно строка символов, а объект – объект любого класса Delhpi.
Такая
двойственность
позволяет
сохранять
объекты
с
текстовыми
примечаниями, сортировать объекты, отыскивать нужный объект по его
описанию и т.д. Если со строками не ассоциированы объекты, получается
обычный список строк.
Класс TStrings является абстрактным, не имеет собственных средств для
хранения строк и определяет лишь интерфейс для работы с элементами. От
него порождены многочисленные потомки, обслуживающие наборы строк в
различных компонентах, таких как TComboBox, TListBox и др. Эти классы
объявляются в разделах Implementation соответствующих модулей, скрыты
от пользователя и не включены в справочную службу. Единственным
доступным
наследником
класса
TStrings
является
TStringList
–
полнофункциональный класс общего назначения.
Свойства абстрактного класса TStrings
Основные свойства свойства класса TStrings перечислены ниже.
Strings[Index:integer]:string – обеспечивает доступ к массиву
строк по индексу. Первая строка имеет индекс, равный 0. Свойство Strings
является основным свойством класса.
117
Objects[Index:integer]:TObject – обеспечивает доступ к массиву
объектов. Свойства Strings и Objects позволяют использовать класс
TStrings как хранилище строк и ассоциированных с ними объектов
произвольных классов.
Count:integer – число элементов в списке.
Text:string – позволяет интерпретировать список строк как одну
большую строку, в которой элементы разделены символами #13#10 (возврат
каретки и перевод строки).
Методы абстрактного класса TStrings
Add(const S:string):integer – функция, добавляет новую строку S в
список и возвращает её позицию. Новая строка добавляется в конец списка.
AddObject(const S:string;AObject:TObject):integer – функция,
добавляет в список строку S и ассоциированный с ней объект. Возвращает
индекс пары строка-объект. AddStrings(Strings: TStrings) – процедура,
добавляет группу строк в существующий список.
Append(const S:string) – процедура, делает то же, что и Add, но не
возвращает позицию.
Clear – процедура, удаляет из списка все элементы.
Delete(Index:integer) – процедура, удаляет строку и связанный с ней
объект. Методы Delete и Clear не разрушает объектов, т.е. не вызывают
деструктор. Об освобождении памяти должен позаботиться программист.
Equals(Strings:TStrings):Boolean – функция, возвращает true,
если список строк в точности равен тому, что передан в параметре Strings.
Exchange(Index1,Index2:integer) – процедура, меняет два элемента
списка местами.
GetText:PChar – функция, возвращает все строки списка в виде одной
нуль-терминированной
строки.
SetText(Text:PChar)
–
процедура,
загружает строки списка из одной большой нуль-терминированной строки.
118
IndexOf(const S:string):integer – функция, возвращает позицию
строки S в списке. IndexOfObject(AObject:TObject):integer – функция,
возвращает позицию объекта. Если строка или объект в списке отсутствует, то
результат равен -1.
Insert(Index:integer;const S:string) – процедура, вставляет в
список строку S в позицию Index.
InsertObject(Index:integer;const S:string;AObject:TObject)
– процедура, вставляет в список строку S и ассоциированный с ней объект
AObject в позицию Index.
LoadFromFile(const FileName:string) – процедура, загружает в
список строки из текстового файла. LoadFromStream(Stream:TStream) –
процедура, загружает строки списка из потока данных.
Move(CurIndex,NewIndex:integer) – процедура, изменяет позицию
элемента (пары строка-объект) в списке.
SaveToFile(const FileName:string) – процедура, сохраняет строки
списка в текстовом файле. SaveToStream(Stream: TStream) – процедура,
сохраняет строки списка в потоке данных.
Дополнительные свойства и методы класса TStringList
Класс TStringList добавляет к TStrings несколько свойств, методов и
событий для уведомления об изменениях в списке.
Свойство
Duplicates:
TDuplicates
определяет,
разрешено
ли
использовать дублированные строки в списке. Свойство может принимать
значения: dupIgnor, dupAccept, dupError.
Свойство Sorted:Boolean. Если значение свойства равно true, то строки
автоматически сортируются в алфавитном порядке.
Метод Sort сортирует строки в алфавитном порядке.
Метод
Find(const S:string;var Index:integer):boolean
ищет
строку S в списке строк. Если строка найдена, то её позиция помещается в
параметр Index и функция возвращает значение true.
119
ВОПРОСЫ ДЛЯ САМОКОНТРОЛЯ
1. Какие действия принято выполнять со списками TList?
2. Как создать список TList? Как добавить в список новый элемент?
3. Что делает приведённая ниже процедура? Прокомментируйте каждую
строчку.
procedure newL(m:integer;Var L:Tlist);
var
i:integer;
pn: ^integer;
begin
L:=TList.create;
for i:=1 to m do
begin
new(pn);
pn^:=random(30);
L.add(pn);
end;
end;
4. Запишите процедуру для формирования списка TList по данным из файла.
5. Запишите процедуру для вывода данных из списка TList в редактор Memo.
6. Как отсортировать список TList?
7. Как освободить память, занятую списком, после завершения работы с ним?
8. Для
чего
используется
TStringList
в
приведённом
ниже
коде?
Прокомментируйте использованные конструкции.
H:=TStringList.Create;
H.Clear;
H.Add('<html>');
H.Add('<head>');
H.Add('<title> Результаты тестирования </title>');
H.Add('</head>');
H.Add('<body>');
. . .
H.Add('</body>');
H.Add('</html>');
H.SaveToFile('HtmlRes.htm');
9. Как узнать, сколько элементов в списке?
10. как обратиться к элементу списка TstringList?
11. Как можно отсортировать список TstringList?
12. Перечислите компоненты, которые используют потомков класса Tstring?
120
13. ГРАФИКА И МУЛЬТИМЕДИА
13.1. Поддержка графики в Windows
Вывод графики в Windows осуществляется с помощью функций Graphics
Device Interface (GDI). Функции GDI используют как сама операционная
система, так и программы, функционирующие под управлением Windows.
Функции, реализованные в GDI, являются аппаратно-независимыми. Они
взаимодействуют с устройством через специальную программу, называемую
драйвером устройства. Такой подход позволяет приложению и операционной
системе работать на компьютерах с различным периферийным оборудованием.
При появлении новых моделей видеокарт, принтеров, плоттеров необходимо
подключить новый драйвер. Функции GDI взаимодействуют с драйвером
устройства через специальную структуру данных, называемую контекстом
устройства. Эта структура содержит основные характеристики устройства и
ссылки на различные средства отображения (кисти, карандаши, цвета и т.п.).
Драйвер устройства преобразует аппаратно-независимые функции GDI в
команды конкретного устройства. Прежде чем вызвать какую-либо функцию
для отображения информации, приложение должно получить ссылку на
контекст устройства вывода, а после завершения действия – освободить
полученный контекст.
Таким
образом,
графическая
система
Windows
является
мощной,
аппаратно-независимой, процедурно-ориентированной и сложной.
Восстановление изображений
Windows-приложение делит экран компьютера с другими приложениями.
Совместное использование экрана обеспечивают прямоугольные окна. Во
время выполнения приложения видимая часть окна может изменяться:
перекрываться другими окнами, разворачиваться на весь экран и т.п. Это
требует
постоянного
контроля
за
состоянием
экрана
и
правильного
восстановления утрачиваемых частей изображения. Операционная система не
хранит копий выводимых на экран окон, но запоминает координаты
121
разрушаемых частей окна в системной области, называемой областью
обновления. Периодически у каждого окна проверяется область обновления, и
если она оказывается не пустой, то приложению-владельцу посылается
сообщение
с
требованием
перерисовать
окно.
Приложение
передаёт
соответствующее сообщение форме. Форма восстанавливает утраченные части
окна собственными средствами. С точки зрения формы сообщение о
перерисовке – это системное событие, а формирование изображения – реакция
на него. Для ускорения графического вывода Windows реализует отсечение. В
результате при перерисовке отображаются только те части формы, которые
были не видны. Рисование за границами области отсечения не выполняется.
Принятый подход приводит к нарушению изображений, размеры которых
зависят от размеров формы. Для таких изображений необходимо в форме
определить обработчик события OnResize, поместив в него вызов метода
Invalidate.
Метод Invalidate определяет всю рабочую область формы как
подлежащую обновлению. После вызова метода Invalidate форма не будет
перерисована сразу. Перерисовка произойдёт при очередном событии OnPaint.
Если надо перерисовать форму немедленно, то следует вызвать метод Refresh.
13.2. Вывод графической информации в Delphi
Для построения изображений в Delphi была введена иерархия графических
классов и разработаны компоненты. Средства Delphi избавляют программиста
от непродуктивных потерь времени на управление ресурсами графической
системы и облегчают вывод графической информации. Однако сохранена
возможность работы непосредственно с функциями GDI и разрешено
комбинировать использование компонентов с процедурами и функциями
графической системы Windows. Для обращения к функциям GDI все
графические объекты имеют целочисленное свойство Handle.
Средства Delphi позволяют выводить заранее подготовленные изображения
и рисовать из программы. Первый способ не требует программирования и
122
прекрасно подходит для вывода статических изображений. Он основан на
использовании
компонентов
определённых
навыков
Image
и
Shape.
программирования,
Второй
но
способ
требует
предоставляет
больше
возможностей для динамического создания изображений. Он основан на
использовании
доступного
программно
свойства
Canvas.
Построение
изображения выполняется в обработчике события OnPaint.
13.3. Классы и компоненты для работы с графикой
Для работы с графикой определены классы TGraphic, TPicture,
TGraphicObject, TCanvas.
TGraphic – это абстрактный класс для инкапсуляции различных
графических форматов, поддерживаемых Windows. Наследниками этого класса
являются TBitmap, TIcon, TMetafile.
Класс TPicture представляет
собой
полнофункциональный
класс,
содержащий всё необходимое для работы с готовыми изображениями, является
контейнером
для
класса
TGraphic,
позволяет
загружать
различные
графические изображения, не заботясь о формате. Методы класса определяют
тип изображения по расширению имени файла. Свойство Graphic класса
TPicture указывает на тип используемого графического изображения.
Классы TGraphic и TPicture содержат ограниченное количество
поддерживаемых ими форматов, однако на базе TGraphic можно создавать
новые классы, которые будут поддерживать другие графические форматы.
Абстрактный
класс
TGraphicObject
является
родительским
по
отношению к классам TFont, TBrush, TPen. Классы TFont, TBrush, TPen
используются только в качестве свойств других классов.
Компонент TPaintBox используется в тех случаях, когда необходимо
иметь прямоугольную область для выполнения графических операций.
Использование этого компонента может быть альтернативой рисованию по
канве формы, но TPaintBox не позволяет загружать готовые изображения.
123
13.4. Программное рисование
Класс TCanvas инкапсулирует основные операции модуля GDI. Canvas –
это поверхность рисования (холст, канва). Форма и все визуальные
управляющие компоненты Delphi обладают свойством Canvas. Конструктор
Create создаёт экземпляр класса TCanvas со свойствами: Brush, Pen, Font,
CopyMode, ClipRect, PenPos, Pixels.
Brush, Pen и Font называютcя инструментами для рисования.
Свойство ClipRect (только для чтения) задаёт координаты отсекающего
прямоугольника. За пределами этой прямоугольной области изображение не
строится. Свойство CopyMode устанавливает режим копирования. Значение
свойства cmSrcCopy определяет обычное копирование, то есть замену
текущего изображения.
Свойство PenPos – это текущая позиция карандаша – невидимый маркер,
который задаётся горизонтальной PenPos.x и вертикальной PenPos.y
координатами. Pixels[X,Y: integer]:color представляет собой массив,
содержащий цвета пикселей. Для доступа к отдельному пикселю достаточно
указать его координаты.
При построении графических изображений часто используются классы
TPoint и TRect, задающие координаты точки и прямоугольную область:
TPoint=record
x:Longint;
y: Longint;
end;
TRect=record
Case integer of
0:(Left,Top,Right,Bottom:integer);
1:(TopLeft, BottomRight: TPoint);
end;
Одним из приёмов построения изображения является использование
рекурсии. На рисунке 3 приведены деревья, полученные многократным
построением двух отрезков, выходящих из одной точки.
Рисуются два отрезка, имеющие общую вершину. Затем из каждой
свободной вершины рисуются два отрезка и т.д. Возможная длина отрезка на
124
каждом шаге уменьшается. Процесс продолжается до тех пор, пока длина
отрезка не станет меньше заданного значения.
Рис.3. Построение изображения с использованием рекурсии
У «регулярного» дерева на каждом шаге длины отрезков и углы одинаковы.
Во втором случае углы и длины отрезков на каждом шаге задаются случайным
образом, в том числе они могут быть равными нулю.
Фрагмент кода, реализующего «регулярное» дерево, приведён ниже.
Процедура Branch1 строит отрезки. В теле процедуры на каждом шаге
вычисляются координаты концов отрезков, и для каждого из них выполняется
вызов процедуры Branch1.
procedure Branch1(x,y,l,f,df,l_min:integer; r:real);
const u=0.01745;
var
x1,x2,y1,y2,f1,f2:integer;
t1,t2:real;
begin
t1:=f-df;
x1:=x+round(l*cos(t1*u));
y1:=y+round(l*sin(t1*u));
125
t2:=f+df;
x2:=x+round(l*cos(t2*u));
y2:=y+round(l*sin(t2*u));
with Form1.PaintBox1 do
begin
canvas.moveTo(x1,y1);
canvas.lineTo(x,y);
canvas.lineTo(x2,y2);
l:=round(l*r);
if l>l_min then
begin
f1:=f-df;
branch1(x1,y1,l,f1,df,l_min,r); //Рекурсивный вызов процедуры
f2:=f+df;
branch1(x2,y2,l,f2,df,l_min,r);//Рекурсивный вызов процедуры
end;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
branch1(150,250,50,-90,10,5,0.8);
end;
13.5. Использование средств мультимедиа
Для работы со звуком и видео в Delphi предусмотрены методы и
компоненты.
Звук
Процедура Beep воспроизводит стандартный звуковой сигнал Windows.
Это очень простая процедура без параметров. Функция MessageBeep
предназначена для вывода звуковых сигналов Windows:
function MessageBeep(uType:word):boolean;
Параметр uType определяет тип звука, его
можно
задавать
шестнадцатеричным числом или с помощью именованной константы.
Функция PlaySound позволяет проигрывать звуковые файлы, форматы
которых
поддерживаются
установленным
драйвером
устройства
воспроизведения.
function PlaySound(pszSound:PChar; hmod:HINST; fdwSound:
Cardinal): Boolean;
Параметр pszSound содержит указатель на звуковой файл, параметр hmod
используется, если звук берётся из ресурса. Параметр pszSound – это опции
126
(флаги), которые определяют режим воспроизведения и тип источника звука.
Если заданный звуковой файл не найден, то PlaySound воспроизводит
системный звук по умолчанию. При использовании функции PlaySound в
разделе uses необходимо указать модуль mmSystem.
Звук можно воспроизводить синхронно, асинхронно, непрерывно. При
синхронном воспроизведении звука работа приложения приостанавливается до
завершения звучания, однако система запоминает действия пользователя.
Асинхронное (параллельное) воспроизведение не блокирует работу приложения.
Если задано непрерывное повторение звукового файла, то обязательно надо
предусмотреть управляющий элемент для завершения воспроизведения.
Функция
MessageBeep
воспроизводит
звук
асинхронно,
а
при
использовании PlaySound можно управлять режимом воспроизведения.
В приведённом ниже примере демонстрируется использование функций
воспроизведения звука. Переменная file_name содержит имя звукового
файла. Параметр hmod задан равным 0, так как звук берётся не из ресурса.
Значение параметра snd_async обеспечивает параллельное воспроизведение
звука функцией PlaySound.
RadioGroup1.ItemIndex of
Beep;
MessageBeep(mb_iconhand);
if file_name<>''
then PlaySound(pChar(file_name), 0, snd_async)
else ShowMessage('Файл не задан');
end;
case
0:
1:
2:
Анимация
Для создания анимации на профессиональном уровне в настоящее время
имеются специальные пакеты. Однако средствами Delphi вполне можно
«оживить» простые изображения. Для этой цели используется программное
рисование и таймер, который задаёт темп смены кадров. Примеры создания
простой мультипликации можно найти в книгах [1], [3] и [10].
127
Видео
Для воспроизведения видеоклипов можно использовать компоненты
Animate и MediaPlayer.
Компонент
Animate
позволяет
воспроизводить
стандартные
мультипликации Windows (например летящие листочки при копировании
файлов) и небольшие (до 64 Кбайт) avi-файлы без звукового сопровождения и
без сжатия. Воспроизводимое изображение задаётся свойством FileName или
CommonAvi. Свойство CommonAvi используется для задания предопределённых
в Windows видео клипов.
Свойство Repetitions задаёт число повторений клипа. Если значение
Repetitions равно 0, то клип будет повторяться до тех пор, пока не сработает
метод Stop.
Начальный кадр указывается в свойстве StartFrame, а конечный – в
StopFrame. По умолчанию свойство StartFrame указывает на первый кадр
(равно 1), а StopFrame – на последний (равно значению свойства
FrameCount). Компонент Animate позволяет воспроизводить фрагмент клипа,
задав начальный и конечный кадры. Чтобы определиться с кадрами, их надо
просмотреть и выбрать нужные на этапе проектирования. Для этого следует
открыть контекстное меню компонента Animate и воспользоваться командами
Next Frame и Previous Frame.
Обычно размеры компонента Animate подстраиваются под размеры кадров
видеоклипа. Этому соответствует значение свойства AutoSize, равное true.
Свойство Active используется для запуска клипа (true) и его
принудительной остановки (false).
Для воспроизведения клипа использование компонента Animate не
является обязательным. Можно воспользоваться методом Play:
procedure Play (FromFrame, ToFrame:word; Count:integer);
Метод Play воспроизводит кадры от FromFrame до ToFrame
включительно Count раз. Если Count равно 0, то клип повторяется до вызова
метода Stop.
128
Управление мультимедийными устройствами
Универсальный
проигрыватель
MediaPlayer
предназначен
для
воспроизведения аудио и видео файлов, а также для управления устройствами,
которые имеют MCI-совместимый драйвер (Media Control Interface).
MCI-интерфейс поддерживают многие модели таких мультимедийных
устройств, как звуковые карты, видеокарты, видеомагнитофоны, лазерные
проигрыватели. В компоненте MediaPlayer используются имеющиеся в
Windows средства для работы с такими устройствами.
Визуально MediaPlayer представляет собой набор кнопок, из которых
формируется
панель
для
управления
различными
аппаратными
и
программными средствами мультимедиа.
Управлять воспроизведением можно с помощью кнопок или программно,
путём вызова соответствующих методов компонента. Назначение кнопок
интуитивно понятно, так как обозначения на кнопках идентичны используемым
в бытовых проигрывающих устройствах. Всего кнопок 9 (Play, Pause, Stop,
Next, Prev, Step, Back, Record, Eject), однако в каждом конкретном случае
можно оставить только те кнопки, которые требуются для работы. Видимостью
и
доступностью
кнопок
управляют
свойства
VisibleButtons
и
EnableButtons.
При выполнении программы пользователь нажимает кнопки с помощью
мыши или клавиатуры (клавишей «пробел»). С нажатием кнопок связано
несколько событий, чаще других используются события OnClick и OnNotify.
Событие OnClick возникает при щелчке по одной из кнопок. Событие
OnNotify возникает после завершения работы метода. Свойства Notify,
Wait и событие OnNotify используются для определения правил передачи
управления приложению.
В каждый момент времени MediaPlayer может управлять только одним
устройством,
тип
которого
определяется
свойством
DeviceType.
По
умолчанию свойство DeviceType имеет значение dtAutoSelect. В этом
129
случае медиаплеер пытается определить тип устройства по расширению имени
файла, заданного в свойстве FileName.
Перед
использованием
устройства
его
надо
открыть.
Для
этого
используется свойство Open. Если же требуется автоматическое открытие
устройства при создании формы, то следует в свойстве AutoOpen установить
true.
По умолчанию видео фрагменты выводятся в окно, формируемое
устройством воспроизведения. При необходимости можно организовать вывод
информации в какой-либо другой оконный элемент, задав его в свойстве
Display.
Компонент MediaPlayer является многофункциональным устройством,
позволяющим управлять режимом воспроизведения/записи, идентифицировать
открытое устройство и определять его возможности. За эти действия отвечает
большое количество свойств и методов, рассмотрение которых выходит за
рамки пособия.
Ниже приводится фрагмент кода, иллюстрирующий различные способы
воспроизведения звука и видео. В приложении для задания метода
воспроизведения звука используется переключатель RadioGroup1, а для
выбора одного из предопределённых видеоклипов Windows – переключатель
RadioGroup2. Для выбора воспроизводимого файла применяется стандартное
окно диалога OpenDialog1, доступ к которому осуществляется через меню.
Просмотр выбранного файла можно выполнить компонентой MediaPlayer1
или Animate1 (с учётом ограничениий). В приложении использован компонент
PageControl с тремя страницами (рис.2).
Пример
const
aviType:array[0..7] of TCommonAvi=
(aviCopyFile, aviCopyFiles, aviDeleteFile, aviEmptyRecycle,
aviFindComputer, aviFindFile, aviFindFolder, aviRecycleFile);
//массив констант, задающих стандартные клипы Windows
var
Form1: TForm1;
130
implementation
{$R *.dfm}
var
file_name:string;//строковая переменная для хранения имени файла
procedure TForm1.Button1Click(Sender: TObject);
begin
//Воспроизведение звука
case RadioGroup1.ItemIndex of
0: Beep;
1: MessageBeep(mb_iconhand);
2: if file_name<>''
then PlaySound(pChar(file_name), 0, snd_async)
else ShowMessage('Файл не задан');
end
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
RadioGroup2.ItemIndex:=0; //Начальное положение переключателя
RadioGroup2Click(Sender);
//Вызов процедуры обработки положения переключателя
end;
procedure TForm1.N1Click(Sender: TObject);
begin
//Обработка пункта меню «Выбрать файл»
if OpenDialog1.Execute then
begin
file_name:= OpenDialog1.FileName; //запоминание имени файла
MediaPlayer1.FileName:= file_name;
//Подготовка медиаплеера к работе
MediaPlayer1.DeviceType:=dtAutoSelect;
MediaPlayer1.open;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
//воспроизведение файла компонентом Animate
try
if file_name<>''
then
begin
Animate1.FileName:= file_name;
//Задание имени
Animate1.Active:=true;
//Запуск воспроизведения
end
else ShowMessage('Файл не задан');
except
ShowMessage('Воспроизведение невозможно');
end;
131
end;
procedure TForm1.RadioGroup2Click(Sender: TObject);
begin
//Процедура обработки положения переключателя
Animate1.CommonAVI:=aviType[RadioGroup2.ItemIndex];
//Задание видео клипа
Label1.Caption:=RadioGroup2.Items[RadioGroup2.ItemIndex];
//Вывод выполняемых действий в метку
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
//Запуск воспроизведения стандартного клипа
Animate1.Active:=true;
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
//Остановка воспроизведения компонентой Animate
Animate1.Active:=false;
end;
ВОПРОСЫ ДЛЯ САМОКОНТРОЛЯ
1. Как осуществляется вывод графики в Windows? Что такое драйвер?
2. Как выполняется восстановление изображений в Windows?
3. Перечислите классы, предназначенные для работы с графикой, и поясните,
для чего предназначен каждый из них.
4. Какие из классов для работы с графикой являются абстрактными?
5. Почему в некоторых случаях нельзя применить компонент PaintBox?
6. Как определить, можно ли рисовать по поверхности компонента?
7. Какие функции используются для воспроизведения звука?
8. При каком режиме воспроизведения звука работа приложения не
приостанавливается? Как задать этот режим?
9. Каким образом можно воспроизвести видео клип? Назовите разные
способы.
10. Как
программно
задать
нужные
кнопки
компонента
Приведите фрагмент кода.
11. Что определяет свойство Display компонента MediaPlayer?
132
MediaPlayer?
14. СОЗДАНИЕ ПРИЛОЖЕНИЯ С ЗАСТАВКОЙ
Заставка присутствует на экране при загрузке приложения, затем исчезает
автоматически или по команде пользователя. Способы отображения заставки
могут быть разными. Так как форма, являющаяся заставкой, появляется первой,
но при её закрытии приложение не должно закрываться, то в проект
необходимо внести изменения. Далее рассматриваются два способа вывода
заставок.
14.1. Особенности формы-заставки
Обычно форма-заставка не имеет заголовка, располагается по центру
экрана, поверх всех окон. Соответствующие свойства формы можно задать на
этапе дизайна в инспекторе объектов или программно. Проще воспользоваться
инспектором объектов, но для контроля и изменения параметров заставки
удобнее задавать свойства программно, в обработчике события OnCreate
формы.
Чтобы у заставки не было заголовка с присущими ему элементами
управления, надо:
ƒ очистить свойство Caption;
ƒ в свойстве BorderStyle задать bsNone;
ƒ в сложном свойстве BorderIcons установить все значения в false.
Чтобы заставка располагалась по центру экрана поверх других окон,
следует в свойстве Position задать poScreenCenter и в FormStyle выбрать
fsStayOnTop. В некоторых случаях разработчики выводят заставку на весь
экран, задав свойство Align равным alClient и выбрав wsMaximized в
свойстве WindowState.
На время отображения заставки целесообразно убрать с экрана курсор. Для
этого следует при создании формы-заставки отключить курсор командой
ShowCursor(false), а в процедуру FormCreate главной формы добавить
команду ShowCursor(true).
133
14.2. Управление выводом форм
Форма-заставка создаётся при запуске приложения и отображается первой.
Затем создаётся главная форма, но она не выводится, пока на экране
располагается заставка. После того как заставка удаляется с экрана и из памяти,
приложение выполняется как обычно. Для реализации предложенного сценария
необходимо внести изменения в файлы проекта и главной формы. Далее
приводится рекомендуемая последовательность действий.
1. Начать новое приложение.
2. В модуле главной формы в процедуре FormCreate задать время
демонстрации заставки. Для этого объявить целочисленную переменную t,
зафиксировать текущее время и задать цикл, который будет повторяться в
течение заданного интервала времени (например 5с). Так как функция
getTickCount возвращает результат в мс, то его надо разделить на 1000:
t:=getTickCount div 1000;
while ( getTickCount div 1000 ) < t+5 do;
Задержка может не потребоваться, если при создании главной формы в
обработчике OnCreate надо выполнить большое количество действий или если
приложение содержит много форм, создание которых выполняется в файле
проекта. В последнем случае операторы создания форм располагаются между
командами, которые создают и удаляют форму-заставку. В результате заставка
отображается на экране сразу после запуска приложения и видна до тех пор,
пока идёт подготовка других форм. К сожалению, время такой задержки
зависит от производительности компьютера. В итоге время искусственной
задержки приходится подбирать экспериментальным путём.
3. Сохранить главную форму в файле.
4. Добавить к проекту новую форму. Так как эта форма будет использована
для создания заставки, то следует ей присвоить имя и задать в Инспекторе
объектов или программно свойства, определяющие внешний вид, размеры и
расположение на экране.
134
5. Расположить на форме нужные компоненты, задать их свойства и
записать требуемый код. Для компонента Image обычно задаются свойства
Align
и
Stretch.
При
использовании
рисунка
большого
объёма
рекомендуется загружать его при выполнении приложения. Иначе .exe-файл
будет содержать рисунок и значительно увеличится в размере. При этом файл с
рисунком должен находиться в папке с запускаемым файлом приложения.
6. Сохранить форму-заставку в файле.
7. Подсоединить модуль с заставкой к приложению.
8. Откорректировать файл проекта:
• создать экземпляр формы-заставки;
• вывести заставку на экран командами Show и Update. Обычно для
отображения формы достаточно метода Show. Однако в данной
ситуации надо дополнительно вызвать метод Update, так как
приложение ещё не запущено и не обрабатываются сообщения
системы Windows. В частности, автоматически не обрабатываются
сообщения, связанные с прорисовкой формы, и в код следует
включить метод Update для отображения формы;
• обычным образом создать главную форму;
• используя метод Hide сделать форму невидимой;
• удалить заставку из памяти методом Free;
• оставить без изменения команду запуска приложения.
Ниже приведён код приложения Demozast, в составе которого две формы:
главная fmMain и заставка fmZast. Ориентировочное время задержки 5с,
картинка загружается в компонент Image1 во время работы приложения.
program Demozast;
uses
Forms,
Main in 'Main.pas' {fmMain},
zast in 'zast.pas' {fmZast};
{$R *.RES}
begin
Application.Initialize;
fmZast:=TfmZast.Create(Application);
135
fmZast.Show;
fmZast.Update;
Application.CreateForm(TfmMain, fmMain);
fmZast.Hide;
fmZast.Free;
Application.Run;
end.
unit zast;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls;
type
TfmZast = class(TForm)
Image1: TImage;
procedure FormCreate(Sender: TObject);
end;
var
fmZast: TfmZast;
implementation
{$R *.DFM}
procedure TfmZast.FormCreate(Sender: TObject);
begin
try
Image1.Picture.LoadFromFile('ZastPicture.bmp');
except;
end; end; end.
unit Main;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs;
type
TfmMain = class(TForm)
procedure FormCreate(Sender: TObject);
end;
var
fmMain: TfmMain;
implementation
uses zast;
{$R *.DFM}
procedure TfmMain.FormCreate(Sender: TObject);
var t:longint;
begin
t:=getTickCount div 1000;
while ( getTickCount div 1000 ) < t+5 do;
end;
end.
136
14.3. Использование для заставки модального окна
В этом случае форма-заставка создаётся обычным способом, но выводится
на экран в модальном режиме. Команда вывода заставки zast.ShowModal
включается в файл проекта. После закрытия заставки экземпляр её формы
следует удалить командой zast.Free. Откорректированный файл проекта
приложения, содержащего две формы (главную и заставку), приведён ниже.
program Zast_move;
uses
Forms,
fmmain in 'fmmain.pas' {main},
fmzast in 'fmzast.pas' {zast};
{$R *.RES}
begin
Application.Initialize;
Application.CreateForm(Tmain, main);
Application.CreateForm(Tzast, zast);
zast.ShowModal;
zast.free;
Application.Run;
end.
Самый
простой
способ
удаления
заставки
с
экрана
сводится
к
использованию элемента управления (например кнопки) с соответствующим
обработчиком. Так, если на форме-заставке дополнительно разместить две
кнопки Далее и Выход, то щелчком по кнопке Далее можно будет убрать с
экрана заставку и продолжить работу, либо с помощью кнопки Выход закрыть
приложение.
При включении в проект заставки с большим временем отображения
необходимо предоставить пользователю возможность прервать вывод заставки
и перейти к работе в любой момент времени. Контролировать действия
пользователя можно с помощью свойства Modalresult формы-заставки. Для
этого
придётся
определить
обработчик
события
OnMessage
объекта
Application. В процедуре обработки поступивших сообщений следует
выяснить, использовалась ли клавиатура или мышь, и присвоить свойству
Modalresult соответствующее значение.
procedure Tzast.AppMessage(var Msg: tagMSG; var Handled: Boolean);
begin
137
if (msg.message=wm_Keydown)or (msg.message=wm_LButtondown)or
(msg.message=wm_RButtondown) then zast.Modalresult:=mrOk;
end;
Если при выводе заставки используются циклы и процедуры, то для
мгновенного
закрытия
окна
надо
добавить
в
код
вызов
метода
ProcessMessages и предусмотреть выход из цикла или из процедуры. Иначе
полученное сообщение о закрытии окна будет отработано только после
естественного завершения цикла (процедуры). Например,
Application.ProcessMessages;
if zast.Modalresult=mrOk then exit;
{if zast.Modalresult=mrOk then break;}
При использовании нескольких длительных циклов или процедур придётся
добавлять предложенные фрагменты кода многократно.
ВОПРОСЫ ДЛЯ САМОКОНТРОЛЯ
1. В чём заключаются особенности формы-заставки?
2. Почему нельзя использовать в качестве заставки обычную форму проекта,
которая выводится на экран первой?
3. Как задать положение формы-заставки в центре экрана?
4. Каким образом можно задать время демонстрации заставки?
5. В каких случаях можно обойтись без введения исскуственной задержки
заставки на экране? В чём недостаток этого метода?
6. Как реализовать управление выводом форм?
7. Какой окно называется модальным?
8. Какие изменения следует ввести в файл проекта при использовании для
заставки модального окна?
9. Перечислите компоненты и события, которые могут использоваться для
завершения демонстрации заставки, реализованной модальным окном.
10. Используя примеры кода, приведённые в этом разделе и в разделе 13,
создайте два проекта с заставками, выполненными разными способами. В
одном случае на заставке нарисуйте «деревья», а в другом – выведите
видеофрагмент.
138
15. СОЗДАНИЕ СПРАВОЧНОЙ СИСТЕМЫ
15.1. Справочная система Windows
Обычно
Windows-приложения
снабжаются
справочной
системой
с
привычным для пользователя интерфейсом. В настоящее время используются
две технологии создания справочной системы.
Традиционный подход предусматривает создание справочного файла с
расширением .hlp, который подсоединяется к проекту штатными средствами
Delphi и вызывается через меню или клавишей F1. При запуске справочной
системы автоматически выполняется программа winhelp.exe или winhlp32.exe.
В результате открывается главное окно справочной системы, в которое
загружается соответствующий справочный файл. Для компиляции файла
справки .hlp используется утилита Microsoft Help Workshop. Исходные сведения
оформляются в виде определённым образом сформированного текстового
документа в формате rtf. Утилита Microsoft Help Workshop входит в комплект
поставки Delphi.
Появившаяся позднее технология предназначена для создания файлов
справки .chm (формат файла справки Microsoft Internet Explorer), используя
html-файлы. Файл справки создается путем компиляции любого числа htmlфайлов и прилегающих к ним элементов (например картинок) в один файл
формата chm, который вызывается через отдельный URL-указатель. Для
компиляции файла справки .chm используется утилита HTML Help Workshop.
Эту утилиту можно скачать с сайта фирмы Microsoft.
15.2. Создание справочного файла формата hlp
Выполняемую работу можно разбить на четыре этапа:
1) подготовка в текстовом редакторе исходного файла;
2) определение номеров контекста справочной системы для управляющих
элементов форм;
3) создание с помощью Microsoft Help Workshop справочного файла;
139
4) подключение справочных файлов к приложению и организация их
вызова.
Второй и четвертый этапы выполняются в среде Delphi. Каждый
управляющий элемент (компонент) формы может иметь номер контекста для
справочной
системы.
Контекст
представляет
собой
число,
задаваемое
значением свойства HelpContext, по значению которого определяется раздел
справочной системы, соответствующий данному элементу. При выполнении
приложения, если управляющий элемент находится в фокусе ввода, нажатие
клавиши F1 приводит к выводу на экран раздела справки, связанной именно с
данным элементом.
Подготовка текстового файла справки
Текстовый файл справки создается как документ формата rtf. Для его
подготовки можно использовать любой редактор, позволяющий работать с
документами этого формата, в том числе Microsoft Word. В исходный файл
помимо текста разрешено включать таблицы и графические изображения,
использовать разные шрифты. Подготовленный текст необходимо разбить на
разделы. Раздел справочной системы представляет собой фрагмент документа,
отображемый в окне (возможно, с линиями прокрутки). Технически разделы
формируются добавлением разрывов страниц.
Таким образом, текст справочной системы состоит из многих разделов,
связанных между собой перекрестными ссылками. Каждый раздел имеет
заголовок, отображаемый в верхней части окна просмотра, идентификатор,
набор ключевых слов, по которым можно найти раздел, а также ссылки на
другие разделы. Для характеристики разделов используются атрибуты:
• идентификатор – строка, однозначно определяющая раздел, может
состоять из русских и латинских букв, цифр, символа подчёркивания.
Максимальная длина – 255 символов;
• заголовок – название, под которым раздел появляется при поиске в окне
справки. Максимальная длина – 128 символов;
140
• список ключевых слов – слова для поиска сведений в справочной
системе. Если слов несколько, то они разделяются точкой с запятой;
• номер в последовательности просмотра – положение раздела при
последовательном просмотре файла справки;
• макрокоманда – макрокоманда, выполняемая при отображении раздела;
• тег компиляции – признак, определяющий, включать или нет раздел в
справочную систему при компиляции.
Обязательным является задание идентификатора раздела.
Атрибуты назначаются с помощью сносок. Текст сносок располагается в
нижней части страницы и отделяется от основного текста горизонтальной
чертой. Чтобы задать сноску необходимо установить курсор слева или справа
от названия раздела и выполнить команду Вставка|Сноска. В открывшемся
диалоговом окне следует задать обычную сноску, переключатель Нумерация
установить в положение Другая и ввести в поле нужный символ:
# – идентификатор;
$ – заголовок;
К – список ключевых слов;
+ – номер в последовательности просмотра;
! – макрокоманда;
* – тег компиляции.
Символы сносок обязательно надо набирать на клавиатуре.
После вставки сноски документ разделяется на две части: в нижней
появляется окно сносок. Текст сноски вводится в окне сносок после
сответствующего символа. Причём, между символом сноски и текстом должен
быть один пробел. Сносок надо добавить столько, сколько атрибутов следует
задать. Для редактирования сносок следует выполнить команду Вид|Сноски.
Для организации переходов между разделами в текст включают ссылки.
Внешний вид ссылки при работе со справочной системой зависит от настроек
Windows. Обычно текст ссылки подчёркнут и отображается зелёным.
141
Ссылки оформляются в документе специальным образом и состоят из двух
частей. Первая часть – это текст, который виден пользователю и выделен
подчеркиванием и цветом. Для выполнения перехода на раздел, обозначенный
ссылкой, пользователь должен щелкнуть на выделенном тексте. Вторая часть
не видна пользователю и представляет собой идентификатор раздела, на
который выполняется переход.
Ссылку можно выполнить на другой раздел, на временное окно или на
раздел другого справочного файла. В зависимости от типа ссылки для её
оформления используется определённый шрифт. Если выполняется переход на
обычный раздел, то первая часть ссылки оформляется как перечеркнутая или
подчеркнутая двойной линией строка текста. При выполнении перехода во
временное справочное окно используется подчеркивание одной линией.
Идентификатор раздела оформляется скрытым текстом. Символ конца
строки оформлять как невидимый нежелательно, так как в этом случае строка
сливается со следующей строкой.
Для оформления символов подчеркиванием или скрытым текстом можно
использовать окно Шрифт, вызываемое командой Формат|Шрифт.
Для ссылки на другой раздел можно использовать не только текст, но и
рисунки. В этом случае рисунок должен быть соответствующим образом
подчёркнут или перечёркнут. При создании ссылки на раздел можно указать,
что его содержимое должно отображаться во вторичном окне. Для этого после
идентификатора раздела указываются символ > и имя окна.
Можно создать ссылку на раздел, расположенный в другом справочном
файле. Для этого после идентификатора раздела записываются скрытым
текстом символ @ и имя справочного файла. Раздел другого справочного файла
также может быть показан во временном или вторичном окнах.
Между всеми элементами ссылки не должно быть пробелов.
Чтобы часть ссылки, оформленная скрытым текстом, была видна в
документе, надо выполнить команду Сервис|Параметры и на странице Вид
установить флажок в переключателе Скрытый текст.
142
Примеры оформления ссылок:
задание маскиTop1 – ссылка на раздел с контекстом Top1 в обычном окне;
деление на нольTop12 – ссылка на раздел с контекстом Top12 в обычном окне;
режим наложенияTop13 – ссылка на раздел с контекстом Top13 во временном
окне;
устранение oшибокTop4>WindowFE – ссылка на раздел с контекстом Top4 во
вторичном окне с именем WindowFE;
создание гиперссылкиLes8@d:\myHtml\Lessons.hlp – ссылка на раздел с
контекстом Les8 справочного файла Lessons.hlp (в обычном окне).
Текстовый документ может содержать рисунки, которые вставляются
обычным образом. При этом рисунки, как и текст, можно использовать для
ссылки на другой раздел. Для этого рисунок соответствующим образом
подчеркивается или перечеркивается, а контекст раздела размещается сразу
после рисунка.
Подготовленный документ сохраняется как файл формата rtf.
Компиляция файла справки
При создании файла справки рекомендуется следовать приведённым ниже
инструкциям.
Открыть программу Microsoft Help Workshop командой C:\Program
Files\Borland\Delphi 7\ Help\Tools\ hcrtf.exe.
Начать создание нового проекта справочной системы. Для этого выполнить
команду File|New, в диалоговом окне New выбрать Help Project и нажать
кнопку OK.
В открывшемся окне сохранения файла выбрать папку, ввести имя
будущего файла справки и дать команду Сохранить. В окне программы
Microsoft Help Workshop в поле Help file отобразится имя создаваемого файла
справки, появятся кнопки и в основном поле в секции options будут приведены
некоторые параметры проекта.
Перейти в режим задания исходных файлов rtf. Для этого щелкнуть по
кнопке Files. Откроется окно для подсоединения файлов, входящих в проект.
143
В окне Topic files щёлкнуть по кнопке Add и в диалоговом окне открытия
файла задать нужный файл .rtf. Если справочные тексты сохранены в
нескольких файлах, то с помощью кнопки Add надо добавить все
подготовленные текстовые файлы, а затем нажать кнопку OK. В основном поле
компилятора появится раздел FILES c перечнем выбранных файлов .rtf.
Нажать на кнопку Save and Compile, чтобы сохранить и откомпилировать
проект. После компиляции, которая выполняется очень быстро, появится окно
отчёта. Внимательно прочитать сообщения системы. Если нет сообщений об
ошибках (Error), то даже при наличии предупреждений (Warning), справка
будет работоспособной.
Перейти в папку, отведённую для хранения файлов проекта справки, найти
и запустить двойным щелчком файл с расширением .hlp. Откроется окно
справочной
системы
с
загруженным
начальным
текстом.
Проверить
работоспособность созданной справочной системы.
Создание содержания
Составление содержания представляет собой самостоятельную часть
работы, приступая к которой следует иметь подготовленную структуру
документа: иерархию разделов и их названия. При формировании содержания
потребуются заголовки и идентификаторы, использованные в rtf-файле
справки, поэтому желательно открыть соответствующий текстовый файл или
выписать из него нужные сведения.
Начать создание файла содержания. Для этого выполнить команду
File|New, в диалоговом окне New выбрать Help Contents и нажать кнопку OK.
Откроется окно, предназначенное для формирования и редактирования
содержания. В поле Default filename указать имя файла типа .hlp,
используемого по умолчанию. В поле Default title ввести заголовок первого
выводимого окна справочной системы.
Щёлкнуть по кнопке Add Below. Кнопки Add Below и Add Above
используются для добавления в содержание пункта ниже или выше текущего.
144
Эти команды позволяют записать заголовок, который будет помечен
«книжкой», или задать раздел (Topic), предназначенный для чтения и
обозначенный листочком с вопросом. Действия выполняются в окне Edit
Contents Tab Entry.
Установить переключатель в положение Heading. В единственно доступное
поле Title ввести заголовок и нажать OK. Текст заголовка записывается в
соответствии с разработанной предварительно иерархией. В окне содержания
появится раскрытая книжка и введённый заголовок. При использовании
готового справочного файла заголовки будут помечены закрытыми книжками,
которые раскрываются двойным щелчком и показывают вложенный список
разделов (уровень вложения до 9).
Щёлкнуть по кнопке Add Below. Для записи вложенного заголовка
повторить предыдущий пункт.
Для включения в содержание раздела, предназначенного для чтения,
установить переключатель в положение Topic и заполнить поля:
в поле Title записать название раздела;
в поле Topic ID ввести идентификатор (контекст) раздела. В файле rtf
идентификатор задавался символом #;
в поле Help file ввести имя файла типа .hlp, в котором хранится раздел.
Далее процесс добавления разделов надо согласовать с включением в
содержание заголовков («папок-книжечек»). Чтобы добавить раздел внутрь
«книжки», используется кнопка Move Right.
При необходимости подготовленный файл можно отредактировать. Для
изменения значений Default filename и Default title используется кнопка Edit,
расположенная на уровне этих полей. Для изменения и удаления пунктов
содержания используются расположенные справа кнопки Edit и Remove.
Структуру подготовленного содержания позволяют откорректировать кнопки
Move Left и Move Right, которые изменяют уровень пункта. Добиться
желаемого результата очень просто, так как вносимые изменения наглядно
отображаются в окне.
145
Сохранить созданный файл с расширением .cnt. Для этого выполнить
команду File|Save as.
Перейти в окно проекта (через меню Window) и нажать кнопку Options.
Откроется окно задания параметров проекта.
В окне Options перейти на вкладку Files и в поле Contents file указать файл
содержания и нажать OK. Для поиска файла удобно использовать кнопку
Browse. В результате в секции FILES главного окна программы должно
появиться имя файла содержания.
Сохранить и перекомпилировать проект.
Проверить работоспособность созданной справочной системы.
Подготовка карты соответствия
Для задания связи между идентификаторами разделов и номерами
контекста в контекстно-зависимой справочной системе используется секция
Map. Номер контекста сообщает сведения об элементе, для которого должен
быть отображён текст раздела. Если номер контекста задаётся числом, которое
начинается не с нуля, то Workshop интерпретирует его как десятичное.
Формирование карты соответствия должно быть согласовано с назначением
номеров контекста управляющих элементов приложения (что выполняется
раньше – не имеет значения).
Далее приведена рекомендуемая последовательность действий по созданию
контекстно-зависимой справки.
Загрузить программу Microsoft Help Workshop и командой File|Open
открыть файл проекта, если это не было сделано раньше.
В главном окне программы щёлкнуть по кнопке Map. Откроется
диалоговое окно Map, в котором с помощью кнопок Add, Remove, Edit
задаются соответствия между номерами контекстов и разделами справки.
Щёлкнуть по кнопке Add и в появившемся окне Add Map Entry вести:
в поле Topic ID записать идентификатор раздела (текст сноски
соответствующего раздела, помеченной символом # в файле .rtf);
146
в поле Mapped numeric value ввести номер контекста управляющего
элемента приложения (значение свойства HelpContext).
Используя кнопку Add, добавить нужное количество строк соответствия.
При необходимости с помощью кнопок Edit и Remove отдельные введённые
строки можно отредактировать или удалить.
Завершив создание карты соответствия, нажать OK. В главном окне
программы Workshop появится секция Map с назначенными соответствиями.
Сохранить файл проекта (команда File|Save).
Перекомпилировать проект. Для этого выполнить команду File|Compile, в
открывшемся диалоговом окне установить флажок Include rtf file name and topic
ID in Help File и щёлкнуть по кнопке Compile.
Подключение справочного файла
Подключение справочного файла к проекту выполняется в среде Delphi.
Предварительно следует скопировать подготовленные файлы справки в папку с
проектом приложения.
Подсоединить справку к проекту. Для этого на этапе дизайна (в среде
Delphi) выполнить команду Project|Options. В диалоговом окне задания
параметров проекта перейти на вкладку Application и в поле Help file указать
имя справочного файла (.hlp).
Назначить обработчик пункту меню (Помощь, Справка и т.п.):
Application.HelpCommand(Help_Contents,0); {для вывода начального раздела}
Application.HelpCommand(Help_Finder,0); {для вывода окна с содержанием}
В свойстве формы Helpfile записать имя справочного файла.
В свойствах HelpContext управляющих элементов задать значения.
Назначение номеров контекста должно быть согласовано с формирование
карты соответствия (что выполняется раньше – не имеет значения).
Для подсоединения (или изменения) файла справки программно, в
обработчик соответствующего пункта меню следует включить команду:
Application.HelpFile := <Имя справочного файла>;
147
15.3. Создание справочного файла формата chm
Выполняемую работу можно разбить на этапы:
1) подготовка html-файлов;
2) компиляция файла справки утилитой HTML Help Workshop;
3) организация вызова справки из приложения.
На первом этапе все сведения, которые необходимо включить в
справочную систему, оформляются в виде html-файлов любым доступным
способом. На третьем этапе в обработчик пункта меню, вызывающего
справочную систему, включается команда для запуска файла формата chm.
Этот файл запускается командой API Windows как внешний (раздел 8.3).
Таким образом, более подробного рассмотрения требует этап компиляции
файла справочной системы. Предварительно необходимо установить на
компьютере программу HTML Help Workshop.
При создании файла справки рекомендуется придерживаться приведённой
ниже последовательности действий.
1. Создать папку и поместить в неё все подговленные html-файлы и
сопутствующие материалы.
2. Открыть утилиту HTML Help Workshop командой Пуск|Программы|HTML
Help Workshop.
3. Выполнить команду File|New, в появившемся окне выбрать в списке Project
и нажать кнопку OK.
4. На запрос мастера New Project ответить Далее. Флажок в переключателе
Convert WinHelp Project не ставить!
5. Используя кнопку Browse открыть папку с подготовленными файлами и в
поле имя файла записать имя проекта справочной системы, например,
HelpNew (кириллицу при записи имени лучше не использовать).
6. В окне New Project – Destination проверить правильность записи имени и
расположения файла проекта и, если всё верно – нажать кнопку Далее.
148
7. В окне New Project – Existing Files отметьте флажком HTML Files (.htm) и
нажать кнопку Далее.
8. Добавить .htm-файлы, которые будут использоваться при создании файла
справки. Файлы можно добавлять по одному либо группой. Для добавления
файлов используется кнопку Add, а для удаления – Remove.Чтобы добавить
файлы, надо:
− нажать кнопку Add;
− в окне Открыть выделить группу файлов и нажать кнопку Открыть;
− убедившись, что в окне New Project – HTML Files приведены все
необходимые файлы, нажать кнопку Далее.
9. В окне New Project – Finish нажать кнопку Готово.
10. Откроется страница Projects с перечнем файлов и значениями параметров,
используемых в файле проекта. Посмотреть, какой используется язык.
Нужен русский. Если указан английский, то щёлкнуть по кнопке Change
Project Options и задать русский. В этом же окне можно изменить текст,
открываемый по умолчанию (Default topic).
11. Нажать кнопку Save all files and compile. Будут сохранены все файлы,
выполнена компиляция проекта и в окне справа появятся сведения о
результатах компиляции. В папке с исходными файлами появится файл
справочной системы HelpNew.chm. Если в отчёте о компиляции будут
указаны ошибки error, то файл .chm не скомпилируется.
12. Запустить
файл
работоспособности
HelpNew.chm
справочной
на
выполнение
системы
и
и
отсутствии
убедиться
в
привычных
элементов: оглавления, указателя, окна поиска.
13. Создать оглавление. Для этого перейти на страницу Contents. Появится окно
Table of Contents Not Specified. Появление этого окна означает, что
оглавление еще не задано. Предлагается либо создать новое, либо
использовать уже имеющееся оглавление.
149
14. Выбрать создание нового оглавления (Create a new Contents file) и в
открывшемся окне сохранения файла задать имя оглавления. Система
предлагает использовать имя Table of Contents. Целесообразно согласиться
с предложенным именем и сохранить файл Table of Contents.hhc в той же
папке, что и html-файлы. Файл оглавления нужен только на этапе
подготовки справочной системы.
15. Сформировать оглавление.
− Нажать кнопку Insert a heading для того, чтобы вставить заголовок в
оглавление. Появится окно Table of Contents Entry
− В поле Entry title ввести заголовок. Если это только название раздела, то
добавлять файл с текстом не надо. Если же с заголовком связан текст, то
необходимо нажать на кнопку Add и выбрать соответствующий файл.
Закрыть окно кнопкой OK.
− Создать пункт оглавления, который будет относиться к определённому
ранее разделу. Для этого выделить заголовок (если он не выделен) и
нажать кнопку Insert a page, чтобы вставить пункт оглавления. Появится
окно Table of Contents Entry.
− В окне Table of Contents Entry дать имя пункту и нажать на кнопку Add,
чтобы связать с пунктом соответствующий файл.
− Повторить действия по созданию оглавления нужное число раз. При
создании оглавления вложенные пункты должны быть сдвинуты вправо.
Добиться нужной иерархии и требуемой последовательности файлов
можно с помощью кнопок со стрелками.
17. Перейдите на страницу Index для создания списка ключевых слов. Так как
списка не было, то создать новый файл.
18. Создать три ключевых слова, следует действовать точно так же, как и на
странице Contents. Каждое ключевое слово связать с соответствующим
файлом.
150
19. Перейти на страницу Project и нажать кнопку Change Project Options.
Появится окно Options, в котором имеется возможность изменить опции
проекта. На вкладке General в поле Title ввести название справки. В
выпадающем
списке
Default
file
выбрать
файл,
который
будет
отображаться при запуске справочной системы.
20. Откомпилировать проект.
Созданный
файл
справочной
системы
можно
использовать
самостоятельно, либо подсоединить к проекту.
ВОПРОСЫ ДЛЯ САМОКОНТРОЛЯ
1. Какие утилиты используются для создания файла справки?
2. Какой, по Вашему мнению, способ создания справочной системы более
гибкий?
3. Какие правила используются при подготовке текстового файла справки?
4. Как обеспечить вывод раздела справочной системы по клавише F1?
5. Как создать ссылки для перехода к другим разделам в файле справки
формата hlp?
6. Как оформляется ссылка для перехода во временное справочное окно?
7. Как организовать подсоединение к приложению нескольких файлов
справки?
8. В приложении предусмотрена кнопка для вывода на экран справочной
системы.
Запишите
обработчик
щелчка
по
кнопке,
открывающий
справочную систему в случае использования файла формата hlp и в случает
применения файла формата chm.
9. Как изменить последовательность и иерархию разделов в оглавлении файла
справки?
10. Рассмотрите самостоятельно создание окна поиска в справочной системе,
скомпилированной из html-файлов.
11. Как в утилите HTML Help Workshop изменить картинки, отмечающие
разделы справочной системы?
151
16. СОЗДАНИЕ И ИСПОЛЬЗОВАНИЕ DLL В DELPHI
16.1. Основные понятия
DLL – Dynamic Link Library – это разновидность исполняемых файлов
Windows. Файл, в котором располагается динамическая библиотека, обычно
имеет расширение .dll, но может быть и другое, например, .exe.
Динамически подключаемая библиотека представляет собой выполняемый
модуль, код и ресурсы которого могут использоваться другими динамическими
библиотеками и приложениями. DLL-библиотека подключается в период
выполнения приложения, её код не копируется в исполняемые файлы программ
(в отличие от обычных библиотечных модулей, которые подсоединяются на
этапе компоновки). Достоинства:
• не увеличивает объём кода приложений;
• одним экземпляром DLL могут совместно пользоваться несколько
прикладных программ;
• подключение библиотеки происходит динамически (runtime);
• DLL можно обновлять не меняя приложений, использующий эту
библиотеку, при условии сохранения интерфейса вызова её функций;
• поддерживают многоязыковые проекты, то есть можно использовать
библиотеки, написанные на других языках программирования.
Итак, основные достоинства – это гибкость и экономия памяти и дискового
пространства. Компоновка обычных модулей Delphi выполняется статически, то
есть во время компиляции, копия кода всех используемых модулей помещается
в exe-файл. Это приводит к тому, что программы, использующие один и тот же
модуль, будут содержать большое количество повторяющегося кода. При
одновременном запуске таких программ код будет дублироваться в памяти.
В некоторых случаях основная причина использования DLL заключается в
гибкости создаваемого приложения. Например, при создании текстового
редактора невозможно предусмотреть форматы файлов, которые появятся в
152
будущем. Однако разрабатываемое приложение должно быть приспособлено к
работе с новыми версиями форматов. При использовании динамических
библиотек поддержка нового формата сводится к написанию DLL и
распространению её среди пользователей, которым она может потребоваться. В
этом случае в exe-файл включается инструкция о том, где программа должна
искать необходимый код.
Динамические библиотеки могут экспортировать только процедуры и
функции. Описанные в них типы, константы, массивы и другие языковые
конструкции предназначены исключительно для внутреннего использования. В
DLL
рекомендуется
помещать
процедуры
и
функции,
реализующие
дополнительные возможности программы.
Как и любая программа DLL компилируется совместно с модулем System,
что позволяет определить ссылку на экземпляр DLL через переменную
HInstance и передать ссылку тем функциям, которые ожидают её в качестве
параметра. При обращении к DLL включается счётчик (Hprevinst) и при
каждом новом обращении счетчик увеличивается на единицу. DLL не
выгружается из памяти до тех пор, пока значение счётчика не станет равным
нулю.
Проблем с поиском DLL не возникает, если DLL и исполняемый файл
программы располагаются в одном каталоге. Если программы, использующие
DLL, находятся в разных каталогах, то целесообразно поместить DLL в каталог,
просматриваемый Windows по умолчанию при загрузке DLL. Windows ищет
DLL в следующих местах и в следующем порядке:
• каталог, из которого было загружено приложение;
• текущий каталог;
• системный каталог Windows;
• только для Windows NT: системный каталог 16-разрядной Windows;
• каталог Windows;
• каталоги, перечисленные в переменной окружения PATH.
153
В случае динамического импорта при вызове LoadLibrary можно указать
для DLL полный путь, тогда Windows просмотрит только заданный каталог.
При статическом импорте такой возможности нет.
Основной недостаток DLL – это отсутствие проверки типов. Обращаясь к
функции, фактически даём указание компилятору вызвать функцию, о которой
он ничего не знает. Если будет указано неверное количество параметров или
параметры будут неверных типов, то вызов функции может привести к
непредсказуемым последствиям. Найти подобную ошибку очень сложно.
Изучение DLL предусматривает рассмотрение двух вопросов: создание
библиотеки и её использование.
Структура DLL
По своей сути DLL похожи на модули, но их код больше напоминает
программы. По функциональному назначению и модуль и DLL представляют
собой
библиотеки
Динамические
подпрограмм,
библиотеки
предоставляющих
код
или
–
но
организованы
они
это
особая
разновидность
данные
другим
программам.
по-разному.
программ,
DLL
имеет
обязательный заголовок, который начинается со служебного слова library.
Процедуры и функции записываются так же, как принято в программах, но
их необходимо явным образом экспортировать, чтобы они стали доступны
другим программам или динамическим библиотекам. Для этого вводится
секция exports, в которой перечисляются экспортируемые библиотекой
процедуры и функции. В качестве разделителя при перечислении используется
запятая, завершается секция exports точкой с запятой. В DLL может быть
несколько секций exports. Обязательно включается секция инициализации,
которая, однако, может быть пустой. Шаблон DLL приведён ниже.
library MyDll;
uses
//Перечень подключаемых модулей
{Описания процедур и функций}
exports
//Перечень экспортируемых процедур и функций
begin
{Секция инициализации}
end.
154
Создание DLL
Для создания DLL необходимо выполнить действия:
• командой File|New|Other открыть диалоговое окно New Items и на
вкладке New выбрать DLL Wizard;
• в появившейся заготовке DLL целесообразно (но не обязательно) убрать
лишние строки (директиву компилятору и комментарий);
• присвоить библиотеке имя и сохранить её в файле .dpr под тем же
именем, что записано после слова library;
• описать необходимые процедуры и функции;
• перед блоком begin … end добавить секцию exports, в которой
перечислить экспортируемые процедуры и функции;
• сохранить внесённые изменения и откомпилировать DLL командой
Project|Compile.
В результате появится файл с расширением .dll, для использования
которого нужна запускающая программа.
Далее приведена заготовка DLL.
Library MathLib;
uses
SysUtils, Classes;
{$R *.RES}
begin
end.
В примере 1 реализована простейшая библиотека MathLib, содержащая
три функции. Процедуры и функции, которые будут вызываться из библиотеки
другими приложениями, могут быть объявлены с ключевым словом stdcall
или export. Директива stdcall означает, что при компиляции надо
использовать стандартное соглашение о вызове процедур и функций. Это
позволит обращаться к подпрограммам из приложений, написанных на других
языках программирования. Ключевое слово export указывает компилятору на
необходимость создания специального пролога и эпилога для таких функций –
они называются экспортируемыми.
155
В теле DLL могут быть объявлены константы, типы, переменные,
процедуры и функции, но экспортировать она может только процедуры и
функции.
16.2. Способы экспорта
Каждая экспортируемая из DLL подпрограмма может идентифицироваться
двумя уникальными ключами: числовым индексом (index) и строковым
именем (name). Индекс – это целое положительное число в диапазоне от 1 до
32767. Имя представляет собой последовательность символов, в которой
строчные и прописные буквы различаются. Например, секция exports может
быть оформлена следующим образом:
exports
Myproc1, //По имени процедуры
Myproc2 name 'MyTest',
//По новому имени
Myproc3 index 3,
//По номеру
Myfunc4 index 4 name 'MaxInt',
//По номеру и новому имени
Myfunc5 index 5 name 'MinInt' resident;
//По номеру и резидентному новому имени
Использование нового имени или индекса является необязательным, но в
некоторых случаях очень полезно. Например, при вызове из DLL функции с
именем, недопустимым по правилам языка Pascal. Если имя или индекс не
заданы, то компилятор в качестве индекса назначает порядковый номер, а в
качестве имени – имя процедуры или функции. Если индекс не задан, то при
импортировании можно использовать только имя. Для вызова подпрограммы
по индексу его надо задавать явно.
Для
хранения
предусмотрены
имён
экспортируемых
специальные
таблицы.
Если
подпрограмм
к
имени
в
dll-файлах
экспортируемой
подпрограммы в секции exports добавлено ключевое слово resident, то
компилятор помещает его в таблицу резидентных имён, в противном случае – в
таблицу нерезидентных имён. Таблица резидентных имён всегда загружается в
оперативную память вместе с программным кодом DLL и остаётся там вплоть
до выгрузки библиотеки. Резидентные процедуры и функции отыскиваются
быстрее.
156
16.3. Использование DLL
Для того чтобы процедуры и функции DLL стали доступны прикладной
программе, они должны быть импортированы. Различают два способа доступа:
• статический импорт – с помощью директивы компилятора external;
• динамический импорт – с использованием функций ядра Windows:
LoadLibrary, FreeLibrary и GetProcAddress.
Статический импорт применяют чаще, так как он удобнее и проще в
реализации. Однако достоинства DLL в полной мере проявляются при
использовании динамического импорта.
Статический импорт
В текст приложения в интерфейсную секцию помещают externalобъявления подпрограмм DLL, которые предполагается вызывать:
• записывают ключевое слово procedure или function;
• указывают название подпрограммы;
• добавляют служебное слово external, сообщающее компилятору, что
код подпрограммы расположен вне программы или модуля;
• записывают строку, задающую имя библиотеки, в которой находится
процедура или функция;
• при необходимости вводят идентификатор index и уникальный номер
или идентификатор name и новое имя, позволяющие однозначно
определить подпрограмму в библиотеке.
В примере 1 объявлены функции Max, Min и Mean из библиотеки Mathlib.
После этого объявленные функции можно использовать так, как будто они
являются частью программы. Рассмотренный пример является простейшим
способом импорта подпрограмм из DLL, так как помимо собственно имени
подпрограммы её можно импортировать по номеру и имени в библиотеке. Если
подпрограмма в библиотеке была объявлена с модификатором stdcall, то при
организации импорта надо добавить этот модификатор.
157
Интерфейсный модуль
Доступ к данным dll-библиотеки принято осуществлять с использованием
процедурного интерфейса, то есть с помощью специальных интерфейсных
модулей.
При
создании
интерфейсного
модуля
(модуля
импорта)
рекомендуется следующая последовательность действий:
• открыть файл проекта, в котором надо организовать вызов процедур или
функций из динамической библиотеки;
• создать модуль импорта. Для этого выполнить команду File|New и в
открывшемся окне выбрать Unit. В файле проекта в разделе Uses
появится ссылка на созданный модуль;
• в секцию interface модуля импорта внести описания, указывающие
компилятору формат вызова процедур и функций;
• сохранить модуль импорта в файле.
Примеры 2 и 3 поясняют работу с библиотекой Beeper, содержащей
единственную процедуру BeepMe. При вызове этой процедуры компьютер
подаёт звуковой сигнал. В примере 2 используется статический импорт без
интерфейсного модуля.
В примере 3 приведён интерфейсный модуль SoundUnit, в котором
определены три разных варианта вызова процедуры BeepMe из Beeper.dll: по
имени, по имени в библиотеке и по номеру. Кроме того, показано, что в
приложении процедуре можно давать другое имя (BeepMeTwo, BeepMeThree).
Динамический импорт
Для организации динамического импорта надо программно задать
действия, которые при статическом импорте выполняет загрузчик DLL.
Действия выполняются через функции Windows в следующем порядке:
• загрузка DLL в память;
• получение адресов точек входа в процедуры и функции DLL;
• использование адресов для вызова процедур и функций;
• освобождение библиотеки.
158
Динамический импорт менее удобен и требует существенно больших
усилий при реализации. Но есть и достоинства: более эффективно
используется память; программа получает полный контроль над подключением
DLL-библиотек. Например, если окажется, что вызываемая подпрограмма
отсутствует,
то
соответствующее
есть
возможность
решение.
Более
обработать
того,
ошибку
обеспечивается
и
принять
возможность
организации работы с библиотекой, которой не существует на момент
компиляции приложения. Загрузка DLL выполняется функцией:
LoadLibrary(LibFileName:PChar):HModule;
где LibFileName – строка, содержащая имя библиотеки. Если загрузить
библиотеку не удалось, то функция возвращает код ошибки – число в
диапазоне от 0 до 32.
При завершении работы с библиотекой используется функция
FreeLibrary(LibModule: HModule):Boolean;
где LibModule – дескриптор DLL-библиотеки, возвращённый функцией
LoadLibrary.
Таким образом, при работе с библиотекой потребуется переменная типа
HModule для хранения дескриптора библиотек. После загрузки DLL можно
воспользоваться функцией:
GetProcAddress(Module: HModule; ProcName:PChar):Pointer;
где Module – дескриптор загруженного dll-модуля;
ProcName – имя
или
целочисленный
индекс
подпрограммы,
экспортируемой библиотекой.
Если подпрограмма вызывается по имени, то в параметре ProcName
передаётся указатель на нуль-терминальную строку, содержащую имя
подпрограммы. Если используется номер, то в двух младших байтах ProcName
передаётся индекс, а старшие два байта должны быть равны нулю.
Результат – указатель на точку входа в экспортируемую подпрограмму.
Если при вызове по имени окажется, что подпрограммы не существует, то
159
будет возвращено nil. Если же используется индекс, то при отсутствии
подпрограммы nil не возвращается, поэтому надёжнее пользоваться именем.
В примере 4 реализован динамический импорт функции Min из библиотеки
MathLib.dll. Для работы с адресом функции объявлен процедурный тип TMin и
переменная Min этого типа:
type TMin = function (X, Y: Integer): Integer;
Var Min: TMin;
В
дальнейшем
переменной
Min
присваивается
значение
адреса,
возвращаемого функцией GetProcAddress. Оперция @ означает получение
адреса:
@Min := GetProcAddress(LibHandle, 'Min');
16.4. Многомодульные библиотеки
Ранее были рассмотрены приёмы создания простейших DLL. Реальные
библиотеки часто являются многомодульными.
В этом случае файл проекта dll-библиотеки должен содержать раздел uses,
подключающий все необходимые модули, раздел exports и операторный блок
Begin ... end, инициализирующий библиотеку. При этом каждый модуль
может иметь секции initialization и finalization.
Последовательность создания многомодульной библиотеки:
1) выполнить команду File|New и выбрать DLL для получения заготовки
проекта библиотеки;
2) выполнить команду File|New, выбрать Unit для создания нового модуля;
3) сохранить заготовки под нужными именами;
4) наполнить модуль содержанием: объявить и сформировать процедуры и
функции (в интерфейсной секции выполнить объявления, а в секции
implementation – записать тексты соответствующих подпрограмм);
5) в файле проекта создать секцию exports; выбрать определённый
способ распознавания подпрограмм (по имени или по индексу);
6) сохранить модуль и проект;
160
7) скомпилировать проект командой Project|Build All.
При необходимости пункты 2-4 повторить требуемое число раз. В
результате появится файл библиотеки с расширением .dll.
16.5. Создание форм в DLL
Примером многомодульной библиотеки является DLL, содержащая форму.
Особенность
такой
библиотеки
заключается
в
том,
что
необходимо
предусмотреть команды для создания, отображения и уничтожения формы.
Воспользуемся приведённым в предыдущем разделе сценарием для
создания DLL с формой. В библиотеку поместим процедуру, которая будет
генерировать форму и строить на ней диаграмму по полученным данным. Затем
создадим приложение, вызывающее разработанную процедуру.
Этап 1. Создание библиотеки
С помощью команды File|New сформируем заготовку проекта библиотеки.
Добавим в проект форму.
Сохраним заготовку проекта библиотеки под именем MyLib.dpr, а модуль
формы – под именем fmGraph.pas. В разделе uses библиотеки MyLib появится
ссылка на модуль формы: fmGraph in 'fmGraph.pas' {Form1};
Поместим на форму нужные компоненты, в частности, Chart и зададим
значения свойств.
Объявим в секции interface экспортируемую процедуру drawchart с
директивой export:
procedure drawchart(Handle:tHandle; a,b,c,d:integer); export;
В разделе implementation сформируем текст процедуры drawchart:
ƒ сгенерируем форму командами
Application.Handle:=Handle;
Form1:=TForm1.Create(Application);
ƒ построим диаграмму;
ƒ выведем
на
экран
форму
в
модальном
режиме
Form1.ShowModal;
ƒ разрушим форму после её закрытия командой Form1.Free;
161
командой
В файле библиотеки MyLib.dpr сформируем раздел exports и зададим
способ экспорта drawchart. Например, exports drawchart index 1;
Сохраним доработанные файлы MyLib.dpr и fmGraph.pas.
Откомпилируем библиотеку командой Project|Build All.
Для
проверки
демонстрационную
работоспособности
программу,
которая
библиотеки
будет
надо
создать
использовать
функцию
drawchart.
Этап 2. Создание приложения
Начнём создание нового приложения.
Разместим на форме нужные элементы (например четыре однострочных
редактора для ввода данных и кнопку) и зададим их свойства.
Сохраним проект под именем Demo.dpr, а модуль формы – под именем
fmDemo.pas.
Впишем в секцию implementation сведения о нужной процедуре и
правила её вызова:
procedure drawchart(Handle:tHandle; a,b,c,d:integer); external
'mylib' index 1;
Запишем обработчик для кнопки. Предусмотрим в нём вызов процедуры из
DLL: drawchart(Handle,a,b,c,d);
Сохраним изменённые файлы.
Командой Run запустим проект на компиляцию и выполнение.
Полные тексты библиотеки и приложения приведены в примере 5.
16.6. Примеры создания и использования DLL
Пример 1. Библиотека MathLib. Статический импорт
Библиотека
library MathLib;
uses SysUtils, Classes;
function Min(x,y:integer):integer;
begin
if x<y then Min:=x else Min:=y;
end;
function Max(x,y:integer):integer; stdcall;
begin
162
if x>y then Max:=x else Max:=y;
end;
function Mean(x,y:integer):extended; export;
begin
Mean:=(x+y)/2;
end;
exports
Min, Max, Mean;
begin
end.
Приложение
unit Unit1; .//Модуль, использующий функции из DLL
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
function Max(x,y:integer):integer; stdcall; external 'Mathlib';
function Min(x,y:integer):integer; external 'Mathlib';
function Mean(x,y:integer):extended; external 'Mathlib';
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Button1: TButton;
Edit4: TEdit;
Label4: TLabel;
Edit5: TEdit;
Label5: TLabel;
procedure Button1Click(Sender: TObject);
end;
var Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var
a,b:integer;
begin
a:=strtoint(edit1.text);
b:=strtoint(edit2.text);
edit3.text:=inttostr(max(a,b));
edit4.text:=inttostr(min(a,b));
edit5.text:=floattostr(mean(a,b));
end;
end.
Пример 2. Библиотека Beeper. Статический импорт
Библиотека
library Beeper;
163
uses Windows;
procedure BeepMe; stdcall;
begin
MessageBeep (0);
end;
Exports
BeepMe index 1 name 'BeepMe';
begin
end.
Приложение
unit SoundForm;
// Модуль формы
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
procedure BeepMe; stdcall; external 'Beeper';
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
BeepMe;
end;
end.
program SoundApp;
// Файл проекта
uses
Forms,
SoundForm in 'SoundForm.pas' {Form1};
{$R *.RES}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Пример 3. Библиотека Beeper. Статический импорт с интерфейсным
модулем
Приложение
unit SoundUnit;
// Интерфейсный модуль
164
interface
procedure BeepMe; external 'Beeper';
procedure BeepMeTwo; external 'Beeper' name 'BeepMe';
procedure BeepMeThree; external 'Beeper' index 1;
implementation
end.
unit SoundUnitForm;
// Модуль формы
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
uses SoundUnit;
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
BeepMe;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
BeepMeTwo;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
BeepMeThree;
end;
end.
program Sound;
// Файл проекта
uses
Forms,
SoundUnitForm in 'SoundUnitForm.pas' {Form1},
SoundUnit in 'SoundUnit.pas';
{$R *.RES}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
165
Пример 4. Библиотека MathLib. Динамический импорт
Приложение
unit DinMath2;
//Модуль формы
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
type
TMin = function (X, Y: Integer): Integer;
var
LibHandle: HModule; { handle of the loaded DLL }
Min: TMin;
{ pointer to the Min function }
a,b:integer;
begin
{ Загружаем динамическую библиотеку }
LibHandle := LoadLibrary('MathLib.dll');
{ Проверяем, нормально ли загружена библиотека }
if LibHandle < 32 then
begin
ShowMessage('Could not load DLL.');
Halt;
end;
{ Получаем адрес функции вычисления минимума }
@Min := GetProcAddress(LibHandle, 'Min');
{ Проверяем корректность указателей }
if @Min = nil then
begin
FreeLibrary(LibHandle);
ShowMessage('Could not link to procedure in DLL.');
Halt;
end;
{ Теперь можно вызывать функции Min и Max }
a:=strToInt(edit1.text);
b:=strToInt(edit2.text);
166
edit3.text:=intToStr(min(a,b));
{ Освобождаем библиотеку }
FreeLibrary(LibHandle);
end;
end.
Пример 5. Библиотека, использующая форму
Библиотека
library MyLib;
uses
SysUtils, Classes,
fmGraph in 'fmGraph.pas' {Form1};
exports
drawchart index 1;
begin
end.
unit fmGraph;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, TeeProcs, TeEngine, Chart, Series;
type
TForm1 = class(TForm)
Chart1: TChart;
Series1: TBarSeries;
end;
var
Form1: TForm1;
procedure drawchart(Handle:tHandle; a,b,c,d:integer); export;
implementation
{$R *.DFM}
procedure drawchart(Handle:tHandle; a,b,c,d:integer);
begin
Application.Handle:=Handle;
Form1:=TForm1.Create(Application);
Form1.Series1.AddBar(a,'',clteecolor);
Form1.Series1.AddBar(b,'',clteecolor);
Form1.Series1.AddBar(c,'',clteecolor);
Form1.Series1.AddBar(d,'',clteecolor);
Form1.ShowModal;
Form1.Free;
end;
end.
Приложение
program Demo;
uses
Forms,
fmDemo in 'fmDemo.pas' {Form1};
{$R *.RES}
167
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
unit fmDemo;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure drawchart(Handle:tHandle; a,b,c,d:integer); external
'mylib' index 1;
procedure TForm1.Button1Click(Sender: TObject);
var
a,b,c,d:integer;
begin
a:=strtoint(edit1.text);
b:=strtoint(edit2.text);
c:=strtoint(edit3.text);
d:=strtoint(edit4.text);
drawchart(Handle,a,b,c,d);
end;
end.
ВОПРОСЫ ДЛЯ САМОКОНТРОЛЯ
1. Чем объясняется широкое использование DLL?
2. Какую структуру имеет DLL?
3. Что и как записывается в секции exports?
4. Может ли имя процедуры в вызывающем приложении не совпадать с
именем процедуры в библиотеке?
5. По
какому
признаку
компилятор
определяет,
что
код
процедуры
расположен вне приложения?
6. В чём принципиальное отличие динамического импорта от статического?
168
БИБЛИОГРАФИЧЕСКИЙ СПИСОК
1. Архангельский А.Л. Delphi 7. – М.: Бином, 2004. – 1120 с.
2. Бобровский С.И. Delphi 7: Учебный курс. – СПб.: Питер, 2004. – 736 с.
3. Гофман В.Э, Хомоненко А.Д. Delphi 5. – СПб.: БХВ – Санкт-Петербург,
2000. – 800 с.
4. Сурков К.А., Сурков Д.А., Вальвачёв А.Н. Программирование в среде
Delphi 2. – Минск.: ООО «Попурри», 1997. – 640 с.
5. Тейлор Д. и др. Delphi 3: библиотека программиста – СПб: Питер, 1998. –
560 с.
6. Фаронов В.В. Система программирования Delphi. – СПб.:БХВ – СанктПетербург, 2003. – 912 с.
7. Фаронов В.В. Delphi 6:Учебный курс. – М.: Издатель Молгачева С.В., 2003.
– 672 с.
8. Фёдоров А.Г. Delphi 2 для всех. – 2-е изд., перераб. и доп. – М.: ТОО фирма
«КомпьютерПресс», 1997. – 464 с.
9. Шейкер Т.Д. Delphi: Метод. указания. – Владивосток: Изд-во ДВГТУ, 2004.
– 64 с.
10. Delphi 7. Наиболее полное руководство/Хомоненко А.Д. и др.. – СПб.: БХВ
– Санкт-Петербург, 2004. – 1216 с.
169
ОГЛАВЛЕНИЕ
ВВЕДЕНИЕ .................................................................................................................. 3
1. ПРОЕКТ И УПРАВЛЕНИЕ ПРОЕКТОМ............................................................ 4
1.1. Проект Delphi .................................................................................................. 4
1.2. Управление проектом..................................................................................... 7
1.3. Репозиторий .................................................................................................... 8
1.4. Настройка параметров проекта ..................................................................... 9
1.5. Компиляция и выполнение проекта ........................................................... 10
2. СОЗДАНИЕ ПРИЛОЖЕНИЯ ............................................................................. 12
2.1. Хорошее приложение................................................................................... 12
2.2. Этапы создания приложения ....................................................................... 12
2.3. Создание интерфейса приложения ............................................................. 13
2.4. Определение функциональности проекта.................................................. 17
2.5. События и их обработка............................................................................... 18
2.6. Формирование кода ...................................................................................... 19
2.7. Организация взаимодействия форм............................................................ 20
3. ФОРМА ................................................................................................................. 24
3.1. Свойства формы............................................................................................ 24
3.2. События формы ............................................................................................ 25
3.3. Создание форм разного вида ....................................................................... 26
4. КОМПОНЕНТЫ ................................................................................................... 29
4.1. Общие свойства управляющих элементов................................................. 29
4.2. Общие события управляющих элементов ................................................. 31
4.3. Кнопки ........................................................................................................... 35
4.4. Контейнеры ................................................................................................... 38
4.5. Компоненты для работы со строками ........................................................ 41
4.6. Компоненты для отображения текста ........................................................ 48
4.7. Компоненты для работы с графикой .......................................................... 49
4.8. Формирование меню .................................................................................... 51
4.9. Другие компоненты...................................................................................... 54
5. ОБРАБОТКА ИСКЛЮЧИТЕЛЬНЫХ СИТУАЦИЙ В DELPHI ..................... 57
6. СОЗДАНИЕ ОКОН ДИАЛОГА.......................................................................... 63
6.1. Процедуры и функции, реализующие диалоги ......................................... 63
6.2. Стандартные диалоговые панели................................................................ 64
6.3. Использование модального окна ................................................................ 66
6.4. Использование заготовок............................................................................. 68
7. ВВОД И ВЫВОД ДАННЫХ............................................................................... 70
7.1. Общие сведения ............................................................................................ 70
7.2. Формирование данных случайным образом.............................................. 71
7.3. Ввод данных с клавиатуры .......................................................................... 72
7.4. Контроль вводимых данных........................................................................ 73
7.5. Загрузка данных из файлов.......................................................................... 75
7.6. Примеры ........................................................................................................ 76
170
8. ОРГАНИЗАЦИЯ ПРИЛОЖЕНИЙ ..................................................................... 83
8.1. Консольные приложения ............................................................................. 83
8.2. Фокус ввода................................................................................................... 86
8.3. Запуск других приложений ......................................................................... 87
9. ДИАГРАММЫ...................................................................................................... 92
9.1. Компоненты для построения диаграмм ..................................................... 92
9.2. Использование компоненты Сhart .............................................................. 93
10. ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ ................... 96
10.1. Объектная модель ......................................................................................... 96
10.2. Объекты и классы ......................................................................................... 97
10.3. Поля................................................................................................................ 99
10.4. Свойства ........................................................................................................ 99
10.5. Методы.........................................................................................................101
10.6. Управление доступом к классу .................................................................106
11. КЛАСС TAPPLICATION...................................................................................108
12. КЛАССЫ ОБЩЕГО НАЗНАЧЕНИЯ...............................................................114
12.1. Класс TList – списки...................................................................................114
12.2. Классы TStrings и TStringList ....................................................................117
13. ГРАФИКА И МУЛЬТИМЕДИА.......................................................................121
13.1. Поддержка графики в Windows ................................................................121
13.2. Вывод графической информации в Delphi...............................................122
13.3. Классы и компоненты для работы с графикой ........................................123
13.4. Программное рисование ............................................................................124
13.5. Использование средств мультимедиа.......................................................126
14. СОЗДАНИЕ ПРИЛОЖЕНИЯ С ЗАСТАВКОЙ...............................................133
14.1. Особенности формы-заставки ...................................................................133
14.2. Управление выводом форм........................................................................134
14.3. Использование для заставки модального окна........................................137
15. СОЗДАНИЕ СПРАВОЧНОЙ СИСТЕМЫ.......................................................139
15.1. Справочная система Windows ...................................................................139
15.2. Создание справочного файла формата hlp...............................................139
15.3. Создание справочного файла формата chm .............................................148
16. СОЗДАНИЕ И ИСПОЛЬЗОВАНИЕ DLL В DELPHI.....................................152
16.1. Основные понятия ......................................................................................152
16.2. Способы экспорта.......................................................................................156
16.3. Использование DLL....................................................................................157
16.4. Многомодульные библиотеки ...................................................................160
16.5. Создание форм в DLL ................................................................................161
16.6. Примеры создания и использования DLL................................................162
БИБЛИОГРАФИЧЕСКИЙ СПИСОК....................................................................169
171
Учебное издание
Татьяна Давидовна Шейкер
Разработка приложений в системе DELPHI
Редактор В.В. Сизова
Техн. редактор Н.М. Белохонова
Подписано в печать 06.05.06. Формат 60x84/16
Усл. печ. л. 10. Уч.-изд. л. 6, 96. Тираж 100 экз. Заказ 079
________________________________________________________________________________________________________________________
Издательство ДВГТУ, 690950, Владивосток, ул. Пушкинская, 10
Типография издательства ДВГТУ, 690950, Владивосток, ул. Пушкинская, 10
172
Download