- •Windows -приложение
- •Среда программирования
- •Встроенный отладчик
- •Использование графики
- •Графические данные и палитра
- •Сохранение проекта
- •Структура приложения
- •Структура модуля
- •Простые типы
- •Символьные типы
- •Логические типы
- •Тип перечень
- •Составной оператор
- •Оператор if
- •Оператор цикла for
- •Оператор цикла while
- •Оператор цикла repeat
- •Пример приложения 6
- •Пример приложения 7
- •Статические массивы
- •Динамические массивы
- •Оператор with
- •Идентичность типов
- •Совместимость типов
- •Преобразование типов
- •Операторы обработки исключительных ситуаций
- •Рекурсия
- •Процедура exit
- •Директивы подпрограммы
- •Класс как объектный тип
- •Наследование
- •Операции is и as
- •Типы ссылки на класс
- •Типизированные файлы
- •Файлы без типа
- •Пример приложения 17
- •Компонент tmainmenii
- •Двунаправленные списки
- •Потоки данных
- •Пример приложения 22
- •Интерфейс drag and drop
- •Пример приложения 24
- •С файлами
- •Пример приложения 26
- •Программные потоки
- •Приоритеты потоков
- •Класс tthread
- •Проблемы синхронизации потоков
Структура приложения
Выше было отмечено, что приложение - это "ловушка" событий плюс обработчики этих событий. Обработчик события реализует какие-либо действия. Самым простым событием является нажатие на клавишу клавиатуры
24
или кнопку мыши. Более сложные события формируются системой Windows или текущим приложением. Для того чтобы обеспечить требуемую реакцию на то или иное событие, необходимо разработать интерфейс пользователя. Пользовательский интерфейс - это некоторая графическая среда, через которую передаются события внутрь приложения. Простейший интерфейс состоит из меню. Более сложные интерфейсы включают в себя различные кнопки, панели, диалоговые окна и т.п. Для разработки интерфейса служит палитра компонентов, которая содержит более 100 различных элементов. Внешний вид интерфейсных элементов может задаваться программно или с помощью инспектора объектов.
Приложение обеспечивает решение всей задачи и по мере необходимости обращается к средствам модулей. Модули содержат отдельные элементы - это типы данных, константы, переменные, подпрограммы и др., которые необходимы для выполнения каких-либо операций. Модули фактически выступают в качестве библиотек этих элементов. В простейшем случае приложение может состоять из одной программы-проекта (используется очень редко). Приложение кроме модулей может иметь в своем составе динамические библиотеки (DLL). Программа-проект, модули и DLL называются программными единицами. Рассмотрим, из каких основных частей состоит программная единица, т.е. какова структура различных программных единиц.
СТРУКТУРА ПРОГРАММЫ-ПРОЕКТА
Программа-проект определяется заголовком. Заголовок состоит из зарезервированного слова Program и имени программы, например
Program Project1;
Uses Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.RES} begin
Application.Initialise;
Application.CreateForm{TForral, Form1);
Application.Run; end.
Имя программы совпадает с именем файла, в который она записывается. Непосредственно менять имя программы-проекта не следует - необходимо просто сохранить ее с другим именем. Текст программы-проекта очень редко приходится корректировать - Delphi создает его автоматически.
Текст программы-проекта записывается в файл Project1.dpr. Данная программа использует встроенный модуль Forms и модуль Unit1, который Должен разработать программист. В фигурных скобках можно задавать комментарии, или директивы. Признаком директивы является наличие
25
символа $. Используемая в данном случае директива SR читает файл ресурсов и подключает их к проекту. Вместо символа * в данном случае будет подставлено имя Project 1. Программа-проект стандартно вызывает три метода класса TApplication: Initialize, CreateForm и Run.
Структура модуля
Модуль является программной единицей для хранения элементов программирования. Модули бывают двух типов:
-
стандартные, заранее созданные разработчиками Delphi и включенные в среду программирования;
-
модули разработчика, создаваемые программистом. Модуль состоит из следующих частей:
-
заголовок (Unit);
-
интерфейс (interface);
-
исполнительная часть (Implementation);
-
секция инициализации (Initialization);
-
секция завершения (Finalization);
-
ключевое слово end с точкой.
Особенности этих частей заключаются в том, что каждая из них может присутствовать только один раз, их последовательность только такая, как указано выше. Секции инициализации и завершения могут отсутствовать.
Заголовок начинается с ключевого слова Unit, за которым следует имя. Имя модуля используется как имя файла, в который записывается текст программы. Delphi по умолчанию присваивает имя Unit1. В дальнейшем это имя можно изменить при сохранении файла.
Интерфейс модуля - часть модуля, доступная для других программных единиц. Интерфейс начинается с зарезервированного слова Interface. Заканчивается интерфейсная секция началом исполнительной части.
Исполнительная часть модуля начинается с ключевого слова Implementation, а завершается либо началом секции инициализации, если она есть, либо зарезервированным словом end. В этой секции определяются все процедуры и функции, методы классов и обработчики событий, объявленные в интерфейсной секции. Дополнительно могут содержаться определения программных элементов, которые не объявлены в интерфейсной части. Эти процедуры и функции являются недоступными для других программных единиц и используются для выполнения каких-либо внутренних действий в данной секции.
Секция инициализации содержит операторы, которые выполняют при запуске программной единицы какие-либо вспомогательные действия: открываются файлы, инициализируются переменные и т. д. Выполняются эти
26
операторы только один раз. Начинается эта секция ключевым словом Initialization. Эта секция необязательна.
Секция завершения содержит операторы, которые выполняются при завершении приложения. Они исполняются один раз. Обычно в этой секции удаляются какие-либо временные файлы, записывается какая-либо информация и т.п. Начинается эта секция с ключевого слова Finalization. Эта секция необязательна, однако, она должна присутствовать, хотя бы пустая, если есть секция инициализации.
Примером встроенного библиотечного модуля является модуль Forms, который содержит методы, позволяющие построить форму. Ниже приводится пример модуля:
Unit Unit1;
Interface
Uses {Подключаемые модули}
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
Type {Объявления типов используемых переменных} TForm1 = class(TForm)
Edit1: TEdit;
Button1: TButton;
Button2: TButton;
procedure Button1Cliclc(Sender: TObject) ;
procedure Button2Click(Sender: TObject);
end;
var {Объявления переменных}
Form1: TForm1; F: TextFile; S: String;
Implementation
{$R *.DFM} {Загрузка файла ресурсов формы}
procedure
ТForm1.Button1Click(Sender: TObject);
begin
S:=Edit1.Text; {Чтение строки S}
Edit1.Text:='';
end;
procedure
TForm1.Button2Click(Sender: TObject); begin
Close; end;
Initialization
AssignFilefF,'Myfile.txt'); Rewrite (F) ; {Открытие файла}
Finalization
WriteLn(F,S) ; {Запись в файл строки S}
27
{Закрытие
файла}
Текст этой программы записывается в файл Unit1.pas, автоматически создается файл ресурсов для формы, который будет иметь имя Unit1.dfm.
Данная программа открывает файл Myfile.txt и записывает туда строку S, которая вводится с клавиатуры, используя объект Edit1.
Структура DLL будет описана далее.
При запуске приложения на выполнение сначала формируется выполняемый файл. Этот процесс делится на две стадии. Во-первых, компилятор транслирует исходный текст кода программы и формирует двоичный объектный код (в частности, создается файл Unit1.dcu для откомпилированных файлов Unit1.pas и Unit1.dfm в данном случае). Во-вторых, компоновщик связывает полученный объектный код со встроенными библиотечными объектными кодами модулей. В результате создается исполняемый файл, в данном случае Project1.exe.
ПРИМЕР ПРИЛОЖЕНИЯ 1
Создадим приложение, выполняющее какие-либо "полезные" действия. Для этого продолжим работу над проектом, форма которого представлена т рис. 11. Пусть приложение будет выполнять сложение двух чисел: s=a+b. Создадим форму, приведенную на рис. 13.
Рис. 13
В данном проекте использовались два новых компонента TLabel и TEdit (по сравнению с рис. 11). Компонент TLabel позволяет отобразить статический, нередактируемый текст. Используя этот компонент, задают заголовки для других интерфейсных элементов. Текст заголовка вводится с помощью инспектора объектов (свойство Caption). Если свойство AutoSize равно "True", то размер компонента динамически изменяется в зависимости от размера текста. Дня того чтобы текст располагался в нескольких строчках, нужно свойству Wordwrap задать True.
Компонент TEdit понадобился для создания полей ввода. С помощью этого компонента строятся строки редактирования - прямоугольные окна, в
которых возможен ввод и редактирование текста. TEdit - однострочный редактор. Этот редактор содержит свойство Text, с помощью которого можно передавать данные внутрь приложения. Числа вводятся в виде текста, полученный текст программно преобразуется в числа с помощью функций преобразования. Окончание ввода осуществляется путем передачи фокуса другому компоненту, используя нажатие клавиши Tab. Если свойству ReadOnly задать значение True, то можно запретить ввод данных в данное поле ввода и использовать компонент TEdit для вывода результатов расчетов.
В качестве события, инициализирующего выполнение сложения, выберем нажатие на первую кнопку Button1 (кнопка "Расчет"). Выберем подходящее встроенное для кнопки Button1 событие - событие OnCIick.
В рассматриваемом примере используются Label1, Label2, LabeI3, Edit1, Edit2, Edit3, Button1, Button2. Так как вводятся числа, то первоначально в свойстве Text интерфейсных элементов Edit1 и Edit2 нужно удалить с помощью инспектора объектов имеющийся текст. Далее необходимо задать свойство TabOrder для всех элементов - оно задает порядок "обега-ния" всех объектов на форме с помощью клавиши Tab. После запуска приложения фокус должен быть на Edit1. Поэтому необходимо задать свойство TabOrder для элемента Edit1 равным 0. Для Edit2 свойство TabOrder необходимо задать равным 1, Button1 - 2, Button2 - 3.
Далее запрограммируем обработчик события на нажатие кнопки " Расчет". Для этого в редакторе кода необходимо "вызвать" заготовку требуемого обработчика. Заготовка события OnCIick в редакторе кода будет сгенерирована, если выполнить двойной щелчок с помощью левой клавиши мыши на элементе Button1. Между begin и end нужно написать код обработки события, выполняющий следующее:
-
взять строку Edit1. Text и преобразовать ее в число;
-
взять строку Edit2 . Text и преобразовать ее в число;
-
выполнить сложение этих чисел;
-
полученный числовой результат преобразовать в текст и этот текст по местить в свойство Edit3. Text для отображения на экране дисплея.
Примем, что в данном случае будем работать с целыми числами. Решим проблему ограничения ввода только цифр. Этого можно достичь, если задать обработчик событий OnKeyPress. Этот обработчик обрабатывает каждое нажатие клавиши на клавиатуре при вводе текста (в данном случае чисел). Таких обработчиков нужно два: для Edit1 и Edit2.
Вначале сформируем обработчик OnKeyPress для Edit1. Для этого необходимо выполнить следующее: мышью выбрать Edit1 на форме, в инспекторе объектов перейти на страницу событий (Events), выбрать OnKeyPress и выполнить двойное нажатие левой кнопкой мыши в поле справа от названия события. Появится редактор кода, в котором будет заготовка нужного обработчика. Введем текст:
28
29
If not (key in [‘O'..'9']) then Key:=#0;.
Этот оператор "отсеет" все символы, кроме цифр. Фактически этот обработчик исполняет роль фильтра, заменяя введенные нецифровые символы на самый первый символ (#0) из таблицы ASCII, который не имеет графического начертания.
Теперь сформируем обработчик OnKeyPress для Edit2. Так как он будет таким же, что и для Edit 1, поступим следующим образом. Выберем Edit2, перейдем на страницу событий в инспекторе объектов, мышью выберем OnKeyPress (справа в этой строчке будет стрелка). Мышью нажмем на стрелку - появится в окошке строка Edit1KeyPress. Выберем мышью эту строку - один обработчик события OnKeyPress будет работать на два элемента Edit1 HEdit2.
Ниже приведен полный текст модуля Unit1.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
(Список используемых интерфейсных элементов}
Label1: TLabel;
Edit1: TEdit;
Label2: TLabel;
Edit2: TEdit;
Label3: TLabel;
Edit3: TEdit;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Edit1KeyPress(Sender: TObject;
var Key: Char);
end;
var Form1: TForm1;
implementation
{$R *.dfm}
{Программные коды используемых обработчиков событий} procedure TForm1.Button1Click(Sender: TObject);
begin
Edit3.Text:=IntToStr(StrToInt(Edit1.Text)+
StrToInt(Edit2.Text));
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Close;
30
end;
procedure TForm1.Edit1KeyPress(Sender: TObject;
var Key: Char);
begin
if not (key in [‘O'..'9', '-',#8]) thenkey:=#0;
end; end.
В обработчике OnKeyPress фильтр был расширен, чтобы появилась возможность ввода следующих дополнительных символов: '-', #8 (Backspace).
Самым замечательным в приведенной выше программе является то, что разработчик должен набрать всего три строки - это строки между begin и end в трех обработчиках событий.
ОПИСАНИЯ ПРОГРАММНЫХ ЭЛЕМЕНТОВ
Любая программа состоит из программных элементов и операторов управления этими элементами. К программным элементам относятся константы, типы, переменные, процедуры, функции, объекты и некоторые другие. К операторам управления относятся следующие операторы: присваивания, построения разветвлений в расчетах, построения циклических вычислений и др.
С помощью объявления в программу вводится какой-либо программный элемент. Ему присваивается имя и, возможно, начальное значение. Object Pascal является строго типизированным языком. Это означает, что каждому программному элементу до первого применения необходимо задать его тип, чтобы сообщить компилятору, к какого вида сущностям относится объявленный программный элемент. Эта сущность определяет, какие операции можно применить и как эти операции должны интерпретироваться.
ПРОГРАММНЫЕ ЭЛЕМЕНТЫ И АДРЕСА ПАМЯТИ
Каждый программный элемент занимает какую-либо область памяти. Компилятор неявно заменяет каждое имя определенным адресом в памяти. Иногда имя определяет не сам элемент, а "нечто в памяти". В этом случае имя представляет собой явно указываемый адрес размещения некоторого программного элемента. Такой программный элемент называется ссылкой, или указателем. Таким образом, имена могут представлять или программные элементы или адреса размещения этих элементов.
ОБЛАСТИ ВИДИМОСТИ
Объявление вводит имя в области видимости, т. е. имя может использоваться только в определенной части программы. Для имени, описанного,
31
например, в процедуре кого-либо обработчика событий (такое имя часто называют локальным - Sender в примере 1), область видимости простирается только в блоке процедуры. Имя, описанное, например, в интерфейсной секции модуля (такое имя называют глобальным - TForm, Form1 в примере 1, имена в подключаемых модулях, например в Forms), имеет область видимости, простирающуюся на весь модуль. Области видимости иногда задают с помощью ключевых слов Private, Public, Protected.
ПРАВИЛА ЗАПИСИ ИМЕН
Имя (идентификатор) состоит из последовательности букв и цифр. Первый символ должен быть буквой. Символ подчеркивания "__" считается буквой. Количество символов в имени может быть достаточно большим, но значимыми являются первые 63 символа. Буквы в верхнем и нижнем регистре неразличимы в имени, однако, для удобочитаемости программ следует использовать прописные и строчные буквы.
ВРЕМЯ ЖИЗНИ ИДЕНТИФИКАТОРОВ
Если программист не указал иного, то программный элемент, например локальный, создается, когда встречается его объявление, и уничтожается, когда его имя выходит из области видимости. Элементы с глобальными именами создаются и инициализируются автоматически при объявлении или с помощью инспектора объектов. Иногда они создаются не автоматически, а явно в программе (очень часто один раз) и "живут" до завершения программы. Если элемент создан явно программистом, то при выходе из области видимости его явно необходимо уничтожить, иначе можно непроизводительно занять всю память.
ИСПОЛЬЗОВАНИЕ ЛОКАЛЬНЫХ ПЕРЕМЕННЫХ В ПРИМЕРЕ 1
Рассмотрим другие варианты решения примера 1. Вначале исследуем понятие "локальных переменных", введенное выше. Использование локальных переменных, в данном случае, повышает "'наглядность" программного кода. Для реализации этой идеи достаточно изменить один обработчик -нажатие на кнопку Button1 (рис. 13):
procedure TForm1.Button1Click(Sender: TObject); {объявление локальных переменных)
var а,Ь,s:integer; begin
а:=StrToInt(Edit1.Text);
Ь:=StrToInt(Edit2.Text);
s:=a+b;
Edit3.Text:=IntToStr(s); end;
ИСПОЛЬЗОВАНИЕ ГЛОБАЛЬНЫХ ПЕРЕМЕННЫХ В ПРИМЕРЕ 1
Как можно заметить из сравнения двух приведенных выше вариантов решения примера 1, применение локальных переменных привело к небольшому изменениию программного кода. Еще один вариант решения можно получить, используя глобальные переменные. Их применение изменяет структуру приложения - добавляются новые обработчики событий.
Глобальные переменные (var a,b,s:integer;) объявляются в интерфейсной секции модуля Unit1 (пример 1). Значения глобальным переменным а и Ь присваиваются на уровне работы соответствующих компонентов, в данном случае Edit1 и Edit2. Это означает, что при выходе, например, из элемента Edit1 (при потере фокуса элементом Edit1) необходимо присвоить значение соответствующей числовой переменной. Такое присваивание можно выполнить с помощью обработчика OnExit Таким образом, структурно приложение дополняется двумя обработчиками Edit1 Exit и Edit2Exit. Ниже представлены программные коды этих обработчиков:
procedure TForm1.EdxtlExit(Sender: TObject) ; TObject) ; |
|
begin |
|
a:=StrToInt(Edit1.Text); |
|
end; |
|
procedure TForm1.Edit2Exit(Sender: TObject); TObject); |
|
begin |
|
b:=StrToInt(Edit2.Text); |
|
end;. |
|
Соответственно в обработчике Buttoniciick необходимо убрать строчки вычисления значений переменных а и Ь. Учитывая еще, что переменная s объявлена глобально, перепишем код рассматриваемого обработчика событий:
procedure TForm1.Button1Click(Sender: TObject); begin s:=a+b;
Edit3.Text:=IntToStr(s); end;
ТИПЫ
Тип в простейшем случае определяет вид конкретно представляемой в памяти информации, например переменных, констант. В более широком смысле тип есть конкретное представление некоторой концепции (понятия),
32
3-- 4758
33
применяемой к тем или иным данным. Например, имеющийся тип double с его операциями +, -, *, / и встроенными математическими функциями вычисления логарифма, синуса и т. д. обеспечивает ограниченную, но конкретную версию математического понятия действительного числа. Язык программирования имеет множество встроенных типов, а также предоставляет инструменты построения собственных типов. Собственный тип создается для того, чтобы дать специальное и конкретное определение понятия, которому среди встроенных типов ничто не отвечает, например, построить отсутствующий в Object Pascal тип, позволяющий работать с комплексными числами. Хорошо выбранные типы делают программу более четкой и короткой.
Итак, каждое имя в программе имеет ассоциированный с ним тип. Этот тип определяет:
-
структуру программного элемента, т. е. ту или иную интерпретацию памяти;
-
множество допустимых значений;
-
совокупность возможных операций с ним.
В Object Pascal можно выделить следующие типы:
-
простые;
-
структурированные;
-
указатели;
-
классы;
-
вариантный тип.
Самую обширную группу представляют структурированные типы. Структурированные типы данных определяют наборы однотипных или разнотипных компонентов. Типы компонентов образуются из других типов данных. Можно выделить следующие структурированные типы:
-
массивы;
-
строки;
-
записи;
-
множества;
-
файлы.
Задание типа тому или иному элементу в программе необходимо для того, чтобы компилятор мог выделить соответствующую память и установить механизм доступа к самому элементу и его компонентам.