Содержание
Обзор
Создание методов с помощью визуальных средств
Передача параметров
Более сложные методы и
управляющие элементы
Информация периода
выполнения. Программа CONTROL3
Заключение
-
-
-
- Обзор
- Чтобы
полностью понять и
почувствовать все
преимущества Delphi, Вам
нужно хорошо изучить
язык Object Pascal. И хотя
возможности
визуальной части Delphi
чрезвычайно богаты,
хорошим программистом
может стать только
тот, кто хорошо
разбирается в технике
ручного написания
кода.
По
мере обсуждения темы
данного раздела мы
рассмотрим несколько
простых примеров,
которые, тем не менее,
демонстрируют технику
использования важных
управляющих элементов
Windows.
- Создание
методов с помощью
визуальных средств
- В
предыдущем уроке Вы
видели, что
синтаксический
“скелет” метода
может быть
сгенерирован с
помощью визуальных
средств. Для этого,
напомним, нужно в
Инспекторе Объектов
дважды щелкнуть
мышкой на пустой
строчке напротив
названия
интересующего Вас
события в требуемом
компоненте. Заметим,
если эта строчка не
пуста, то двойной
щелчок на ней просто
переместит Вас в окне
Редактора Кода в то
место, где находится
данный метод.
Для
более глубокого
понимания дальнейшего
изложения кратко
остановимся на
концепции
объектно-ориентированного
программирования. Для
начала определим
базовое понятие
объектно-ориентированного
программирования -
класс. Класс -
это категория
объектов, обладающих
одинаковыми
свойствами и
поведением. При этом объект
представляет собой
просто экземпляр
какого-либо класса.
Например, в Delphi тип
“форма” (окно)
является классом, а
переменная этого типа
- объектом. Метод - это
процедура, которая
определена как часть
класса и
инкапсулирована
(содержится) в нем.
Методы манипулируют
полями и свойствами
классов (хотя могут
работать и с любыми
переменными) и имеют
автоматический доступ
к любым полям и
методам своего класса.
Доступ к полям и
методам других
классов зависит от
уровня
“защищенности” этих
полей и методов. Пока
же для нас важно то,
что методы можно
создавать как
визуальными
средствами, так и
путем написания кода
вручную.
Давайте
рассмотрим процесс
создания программы
CONTROL1, которая поможет
нам изучить технику
написания методов в
Delphi.
Для
создания программы
CONTROL1 поместите с
помощью мышки
компонент Edit
(находится на
страничке “Standard”
Палитры Компонентов)
на форму. После этого
ваша форма будет иметь
вид, показанный на Рис.
8-A.
Теперь
перейдите в Object Inspector,
выберите страничку
“Events” и дважды
щелкните в пустой
строчке напротив
события OnDblClick, как
показано на Рис. 8-B. После
этого в
активизировавшемся
окне Редактора Вы
увидите
сгенерированный
“скелет” метода Edit1DblClick,
являющегося реакцией
на событие OnDblClick:
procedure
TForm1.Edit1DblClick(Sender: TObject);
begin
end;
После
генерации процедуры
Вы можете оставить ее
имя таким, каким
“установил” Delphi, или
изменить его на любое
другое (для этого
просто введите новое
имя в указанной выше
строке Инспектора
Объектов справа от
требуемого события и
нажмите Enter).
Теперь
в окне Редактора Кода
введите смысловую
часть метода:
procedure
TForm1.Edit1DblClick(Sender: TObject);
begin
Edit1.Text:=
'Вы дважды щелкнули в
строке
редактирования';
end;
Сохраните
программу. Во время
выполнения дважды
щелкните на строке
редактирования. Текст
в этой строке
изменится в
соответствии с тем,
что мы написали в
методе Edit1DblClick: см.
Рис. 8-C.

Рис. -C:
Содержимое
управляющего элемента
TEdit
изменяется после
двойного щелчка по
нему
Листинг
8-A и
Листинг 8-B
предоставляют полный
код программы CONTROL1.
Листинг -A:
Программа CONTROL1
демонстрирует, как
создавать и
использовать методы в
Delphi.
program
Control1;
uses
Forms,
Main in
'MAIN.PAS' {Form1};
begin
Application.CreateForm(TForm1,
Form1);
Application.Run;
end.
Листинг -B:
Головной модуль
программы CONTROL1.
unit
Main;
interface
uses
WinTypes,
WinProcs,
Classes,
Graphics, Controls,
Printers,
Menus, Forms, StdCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
procedure
Edit1DblClick(Sender: TObject);
end;
var
Form1:
TForm1;
implementation
{$R *.DFM}
procedure
TForm1.Edit1DblClick(Sender: TObject);
begin
Edit1.Text :=
'Вы дважды щелкнули в
строке
редактирования';
end;
end.
После
того, как Ваша
программа загрузится
в память, выполняются
две строчки кода в
CONTROL1.DPR, автоматически
сгенерированные
компилятором:
Application.CreateForm(TForm1,
Form1);
Application.Run;
Первая
строка запрашивает
память у операционной
системы и создает там
объект Form1,
являющийся
экземпляром класса TForm1. Вторая
строка указывает
объекту Application, “по
умолчанию”
декларированному в
Delphi, чтобы он запустил
на выполнение главную
форму приложения. В
данном месте мы не
будем подробно
останавливаться на
классе TApplication и на
автоматически
создаваемом его
экземпляре - Application.
Важно понять, что
главное его
предназначение - быть
неким ядром,
управляющим
выполнением Вашей
программы.
Как
правило, у большинства
примеров, которыми мы
будем оперировать в
наших уроках, файлы
проектов .DPR
практически
одинаковы. Поэтому в
дальнейшем там, где
они не отличаются
кардинально друг от
друга, мы не будем
приводить их текст.
Более того, в файл .DPR,
автоматически
генерируемый Delphi, в
большинстве случаев
нет необходимости
заглядывать,
поскольку все
действия,
производимые им,
являются
стандартными.
Итак,
мы видели, что
большинство кода Delphi
генерирует
автоматически. В
большинстве
приложений все, что
Вам остается сделать -
это вставить одну или
несколько строк кода,
как в методе Edit1DblClick:
Edit1.Text :=
'Вы дважды щелкнули в
строке
редактирования';
Хотя
внешний интерфейс
программы CONTROL1
достаточно прост, она
(программа) имеет
строгую внутреннюю
структуру. Каждая
программа в Delphi
состоит из файла
проекта, имеющего
расширение .DPR и одного
или нескольких
модулей, имеющих
расширение .PAS. Модуль, в
котором содержится
главная форма проекта,
называется головным.
Указанием компилятору
о связях между
модулями является
предложение Uses,
которое определяет
зависимость модулей.
Нет
никакого
функционального
различия между
модулями, созданными
Вам в Редакторе, и
модулями,
сгенерированными Delphi
автоматически. В любом
случае модуль
подразделяется на три
секции:
· Заголовок
· Секция Interface
· Секция Implementation
Таким
образом, “скелет”
модуля выглядит
следующим образом:
unit
Main; {Заголовок
модуля}
interface
{Секция Interface}
implementation
{Секция Implementation}
end.
В
интерфейсной секции (interface) описывается
все то, что должно быть
видимо для других
модулей (типы,
переменные, классы,
константы, процедуры,
функции). В секции implementation
помещается код,
реализующий классы,
процедуры или функции.
- Передача
параметров
В Delphi
процедурам и функциям (а,
следовательно, и методам классов)
могут передаваться параметры для
того, чтобы обеспечить их
необходимой для работы
информацией. Программа PARAMS
демонстрирует, как использовать
передачу параметров в методы Delphi.
Кроме того, мы узнаем, как:
· создавать
свои собственные
процедуры· добавлять
процедуру в класс,
формируя метод класса
· вызывать одну
процедуру из другой.
Программа
PARAMS позволяет Вам вводить фразы в
строки редактирования. После
нажатия кнопки “Вызов процедуры
WriteAll” строка из управляющего
элемента EditSource скопируется в
шесть управляющих элементов - строк
редактирования, как показано на
Рис. 8-D.
Далее мы не
будем подробно останавливаться на
том, как размещать компоненты на
форме - считаем, что это Вы уже
умеете. После того как Вы
разместили на форме семь
компонентов Edit, переименуйте с
помощью Инспектора Объектов
седьмой компонент (Edit7) в EditSource. Положите на
форму компонент Button, и в Object Inspector измените
его заголовок (свойство Caption) на “Вызов процедуры
WriteAll” (естественно, Вы можете
заменить его шрифт, цвет и т.д.).
После
завершения проектирования формы
класс TForm1 будет выглядеть
следующим образом:
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
Edit5: TEdit;
Edit6: TEdit;
EditSource: TEdit;
Button1: TButton;
end;
Следующий
шаг состоит в добавлении метода,
вызываемого по нажатию
пользователем кнопки Button1. Это, напомним,
можно сделать двумя способами:
Delphi
сгенерирует следующую
“заготовку”:
procedure
TForm1.Button1Click(Sender: TObject);
begin
end;
Цель
программы PARAMS - научить Вас писать
процедуры и передавать в них
параметры. В частности, программа
PARAMS реагирует на нажатие кнопки Button1
путем вызова процедуры WriteAll
и передачи ей в качестве параметра
содержимого строки редактирования EditSource (EditSource.Text).
procedure
TForm1.Button1Click(Sender: TObject);
begin
WriteAll(EditSource.Text);
end;
Важно понять,
что объект EditSource является
экземпляром класса TEdit и, следовательно,
имеет свойство Text, содержащее набранный
в строке редактирования текст. Как
Вы уже, наверное, успели заметить,
по умолчанию свойство Text содержит значение,
совпадающее со значением имени
компонента (Name) - в данном случае
“EditSource”. Свойство Text Вы, естественно,
можете редактировать как в режиме
проектирования, так и во время
выполнения.
Текст,
который должен быть отображен в
шести строках редактирования,
передается процедуре WriteAll как параметр.
Чтобы передать параметр процедуре,
просто напишите имя этой процедуры
и заключите передаваемый параметр
(параметры) в скобки - вот так:
WriteAll(EditSource.Text);
Заголовок
этой процедуры выглядит следующим
образом:
procedure
TForm1.WriteAll(NewString: String);
где указано,
что передаваемый процедуре
параметр NewString должен иметь тип String.
Вспомним, что
задача процедуры WriteAll состоит в
копировании содержимого строки
редактирования EditSource в шесть других строк
редактирования Edit1-Edit6. Поэтому процедура
должна выглядеть следующим
образом:
procedure
TForm1.WriteAll(NewString: String);
begin
Edit1.Text := NewString;
Edit2.Text := NewString;
Edit3.Text := NewString;
Edit4.Text := NewString;
Edit5.Text := NewString;
Edit6.Text := NewString;
end;
Поскольку
процедура WriteAll не является
откликом на какое-либо событие в
Delphi, то ее нужно полностью написать
“вручную”. Простейший способ
сделать это - скопировать заголовок
какой-либо уже имеющейся процедуры,
исправить его, а затем дописать
необходимый код.
Возвратимся
еще раз к заголовку процедуры.
Заголовок состоит из пяти частей:
procedure
TForm1.WriteAll(NewString: String);
· Первая
часть - зарезервированное
слово “procedure”; пятая часть -
концевая точка с запятой “;”. Обе эти части
служат определенным
синтаксическим целям, а именно:
первая информирует компилятор
о том, что определен
синтаксический блок
“процедура”, а вторая
указывает на окончание
заголовка (собственно говоря,
все операторы в Delphi должны
заканчиваться точкой с
запятой).· Вторая
часть заголовка - слово “TForm1”, которое
квалифицирует то
обстоятельство, что данная
процедура является методом
класса TForm1.
· Третья
часть заголовка - имя
процедуры. Вы можете выбрать
его любым, по вашему
усмотрению. В данном случае мы
назвали процедуру “WriteAll”.
· Четвертая
часть заголовка - параметр.
Параметр декларируется внутри
скобок и, в свою очередь,
состоит из двух частей. Первая
часть - имя параметра, вторая -
его тип. Эти части разделены
двоеточием. Если Вы описываете
в процедуре более чем один
параметр, нужно разделить их
точкой с запятой, например:
procedure Example(Param1: String;
Param2: String);
После того
как Вы создали “вручную”
заголовок процедуры, являющейся
методом класса, Вы должны включить
его в декларацию класса, например,
путем копирования (еще раз
напомним, что для методов,
являющихся откликами на
дельфийские события, данное
включение производится
автоматически):
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
Edit5: TEdit;
Edit6: TEdit;
EditSource: TEdit;
Button1: TButton;
procedure Button1Click(Sender:
TObject);
procedure WriteAll(NewString: String);
end;
В данном
месте нет необходимости оставлять
в заголовке метода слово “TForm1”,
так как оно уже присутствует в
описании класса.
Листинг 8-C
показывает полный текст головного
модуля программы PARAMS. Мы не
включили сюда файл проекта,
поскольку, как уже упоминалось, он
практически одинаков для всех
программ.
Листинг
-C: Исходный код
головного модуля программы PARAMS
показывает, как использовать
строки редактирования и как
передавать параметры.
Unit Main;
interface
uses
WinTypes, WinProcs, Classes,
Graphics, Controls,
Printers, Forms, StdCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
Edit5: TEdit;
Edit6: TEdit;
EditSource: TEdit;
Button1: TButton;
procedure Button1Click(Sender:
TObject);
procedure WriteAll(NewString: String);
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure
TForm1.WriteAll(NewString: String);
begin
Edit1.Text := NewString;
Edit2.Text := NewString;
Edit3.Text := NewString;
Edit4.Text := NewString;
Edit5.Text := NewString;
Edit6.Text := NewString;
end;
procedure
TForm1.Button1Click(Sender: TObject);
begin
WriteAll(EditSource.Text);
end;
end.
При
экспериментах с программой PARAMS Вы
можете попробовать изменить имена
процедур и параметров. Однако,
следует помнить, что ряд слов в Delphi
являются зарезервированными,
и употреблять их в идентификаторах
(именах процедур, функций,
переменных, типов, констант) не
разрешается - компилятор сразу же
обнаружит ошибку. К ним относятся
такие слова, как “procedure”, “string”,
“begin”, “end” и т.п.; полный же список
их приведен в on-line справочнике Delphi.
Не
старайтесь запомнить сразу все
зарезервированные слова -
компилятор “напомнит” Вам о
неправильном их использовании
выдачей сообщения типа “Identifier
expected.” (Ожидался идентификатор, а
обнаружено зарезервированное
слово).
-
- Более
сложные методы и
управляющие элементы
Теперь, когда
Вы освоили базовые понятия в
системе программирования Delphi,
можно продолжить изучение
компонент и способов создания их
методов.
В программе
CONTROL1, рассмотренной в начале урока,
был сгенерирован метод, являющийся
откликом на событие OnClick строки редактирования
Edit1. Аналогично, можно
сгенерировать метод, являющийся
реакцией на событие OnDblClick. В программе CONTROL2,
имеющейся на диске, расширен список
находящихся на форме компонентов и
для многих из них определены
события OnClick и OnDblClick. Для исследования Вы
можете просто скопировать файлы
проекта CONTROL1 в новую директорию
CONTROL2, изменить имя проекта на
CONTROL2.DPR (в этом файле после
ключевого слова “program” также должно
стоять название “CONTROL2”) и добавить
компоненты Label, GroupBox, CheckBox, RadioButton, Button на форму (эти
компоненты находятся на страничке
“Standard” Палитры Компонентов). Ваша
форма будет иметь примерно
следующий вид - Рис. 8-E.
Заметим, что
Вы должны “положить” компонент GroupBox на форму до того,
как Вы добавите компоненты CheckBox и RadioButton, которые, в нашем
примере, должны быть “внутри”
группового элемента. Иначе, объекты
CheckBox1, CheckBox2, RadioButton1 и RadioButton2 будут “думать”,
что их родителем является форма Form1
и при перемещении GroupBox1 по форме не будут
перемещаться вместе с ней. Таким
образом, во избежание проблем,
компонент, который должен быть
“родителем” других компонент (Panel, GroupBox, Notebook, StringGrid, ScrollBox и т.д.), нужно помещать
на форму до помещения на нее его
“детей”. Если Вы все же забыли об
этом и поместили “родителя”
(например, GroupBox) на форму после
размещения на ней его “потомков”
(например, CheckBox и RadioButton) - не отчаивайтесь!
Отметьте все необходимые объекты и
скопируйте (с удалением) их в буфер
обмена с помощью команд меню Edit|Cut.
После этого отметьте на форме
нужный Вам объект (GroupBox1) и выполните
команду меню Edit|Paste. После этого все
выделенные Вами ранее объекты
будут помещены на форму, и их
“родителем” будет GroupBox1. Описанный
механизм является стандартным и
может быть использован для всех
видимых компонент.
Выберите
объект Label1. Создайте для
него метод, являющийся откликом на
событие OnDblClick (см. стр. *).
Введите в метод одну строчку,
например:
procedure
TForm1.Label1DblClick(Sender: TObject);
begin
Edit1.Text := 'Двойной
щелчок на Label1';
end;
Запустите
программу на выполнение и дважды
щелкните мышкой на метке Label1.
Вы увидите, что строка
редактирования изменится, и в ней
появится текст “Двойной щелчок на
Label1”.
Теперь
закройте приложение и возвратитесь
в режим проектирования. Добавьте
обработчики событий OnClick и OnDblClick для каждого объекта,
имеющегося на форме. Текст вашего
головного модуля будет выглядеть
следующим образом:
Листинг -D:
Головной модуль программы CONTROL2.
Unit Main;
interface
uses
WinTypes, WinProcs, Classes,
Graphics, Controls, StdCtrls,
Printers, Menus, Forms;
type
TForm1 = class(TForm)
Label1: TLabel;
Edit1: TEdit;
Button1: TButton;
GroupBox1: TGroupBox;
CheckBox1: TCheckBox;
CheckBox2: TCheckBox;
RadioButton1: TRadioButton;
RadioButton2: TRadioButton;
procedure Edit1DblClick(Sender:
TObject);
procedure Label1DblClick(Sender:
TObject);
procedure CheckBox1Click(Sender:
TObject);
procedure CheckBox2Click(Sender:
TObject);
procedure RadioButton1Click(Sender:
TObject);
procedure RadioButton2Click(Sender:
TObject);
procedure Button1Click(Sender:
TObject);
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure
TForm1.Edit1DblClick(Sender: TObject);
begin
Edit1.Text := 'Двойной
щелчок на Edit1';
end;
procedure
TForm1.Label1DblClick(Sender: TObject);
begin
Edit1.Text := 'Двойной
щелчок на Label1';
end ;
procedure
TForm1.CheckBox1Click(Sender: TObject);
begin
Edit1.Text := 'Щелчок на
CheckBox1';
end;
procedure
TForm1.CheckBox2Click(Sender: TObject);
begin
Edit1.Text := 'Щелчок на
CheckBox2';
end;
procedure
TForm1.RadioButton1Click(Sender: TObject);
begin
Edit1.Text := 'Щелчок на
RadioButton1';
end;
procedure
TForm1.RadioButton2Click(Sender: TObject);
begin
Edit1.Text := 'Щелчок на
Radiobutton2';
end;
procedure
TForm1.Button1Click(Sender: TObject);
begin
Edit1.Text := 'Щелчок на
Button1';
end;
end.
Эта
программа служит двум целям:
-
- Она
показывает, как создавать
процедуры (методы) и как
“наполнять” их
содержательной “начинкой”
-
- Она
демонстрирует технику работы с
управляющими элементами Windows.
-
- Информация
периода выполнения.
Программа CONTROL3
Как Вы,
наверное, заметили, методы
программы CONTROL2, являющиеся
откликами на события OnClick и OnDblClick, во многом похожи друг
на друга.
Открытость
среды Delphi позволяет получать и
оперировать информацией особого
рода, называемой информацией
периода выполнения (RTTI - run-time type information). Эта информация
организована в виде нескольких
уровней.
Верхний
уровень RTTI представлен
как средство проверки и приведения
типов с использованием ключевых
слов is и as.
Ключевое
слово is дает программисту
возможность определить, имеет ли
данный объект требуемый тип или
является одним из наследников
данного типа, например, таким
образом:
if MyObject is
TSomeObj then ...
Имеется
возможность использовать RTTI и для
процесса приведения объектного
типа, используя ключевое слово as:
if MyObject is TSomeObj
then
(MyObject as
TSomeObj).MyField:=...
что
эквивалентно:
TSomeObj(MyObject).MyField:=...
Средний
уровень RTTI использует методы
объектов и классов для подмены
операций as и is на этапе
компиляции. В основном, все эти
методы заложены в базовом классе TObject,
от которого наследуются все классы
библиотеки компонент VCL. Для любого
потомка TObject доступны, в числе
прочих, следующие информационные
методы:
-
- ClassName - возвращает
имя класса, экземпляром
которого является объект
-
- ClassInfo - возвращает
указатель на таблицу с RTTI,
содержащей информацию о типе
объекта, типе его родителя, а
также о всех его публикуемых
свойствах, методах и событиях
-
- ClassParent - возвращает
тип родителя объекта
-
- ClassType - возвращает
тип самого объекта
-
- InheritsFrom - возвращает
логическое значение,
определяющее, является ли
объект потомком указанного
класса
-
- InstanceSize - возвращает
размер объекта в байтах.
Эти методы
могут использоваться в Вашем коде
напрямую.
Нижний
уровень RTTI определяется в
дельфийском модуле TypInfo и представляет
особый интерес для разработчиков
компонент. Через него можно
получить доступ к внутренним
структурам Delphi, в том числе, к
ресурсам форм, инспектору объектов
и т.п.
Итак, доступ
к информации периода выполнения в
Delphi позволяет динамически получать
как имя объекта, находящегося на
форме, так и название класса,
которому он принадлежит (и еще
много другой полезной информации;
но об этом - в дальнейших уроках).
Для этого используется свойство Name, имеющееся у любого
класса-наследника TComponent (а таковыми
являются все компоненты, входящие в
дельфийскую библиотеку VCL), и метод ClassName, доступный для любого
потомка класса базового TObject.
А, поскольку класс TComponent, в свою очередь,
является наследником класса TObject,
то он доступен для всех компонент
из библиотеки VCL.
Вернувшись к
нашим примерам, мы можем заменить
целую “кучу” методов двумя,
реализующими события OnClick и OnDblClick для всех объектов
сразу. Для этого можно скопировать
все файлы из CONTROL2 в новый
директорий CONTROL3 или использовать
для работы уже имеющуюся на диске
программу. Создадим стандартным
образом методы ControlDblClick и ControlClick для какого-либо
объекта (например, для Label1).
Введем в них следующие строки:
procedure
TForm1.ControlDblClick(Sender: TObject);
begin
Edit1.Text := 'Двойной
щелчок на ' +
(Sender as TComponent).Name +
' (класс ' + Sender.ClassName +
')';
end;
procedure
TForm1.ControlClick(Sender: TObject);
begin
Edit1.Text := 'Щелчок на ' +
(Sender as TComponent).Name +
' (класс ' + Sender.ClassName +
')';
end;
Теперь
назначим данные методы всем
событиям OnClick и OnDblClick, имеющимся у
расположенных на форме объектов. Мы
видим, что размер программы
существенно сократился, а
функциональность ее значительно
выросла. В режиме выполнения после,
например, щелчка на объекте CheckBox1 приложение будет
иметь вид, изображенный на Рис. 8-F.
Итак, мы
видим, что используя информацию
периода выполнения, можно сделать
программу очень гибкой и
универсальной.
-
- Заключение
В этом уроке
мы рассмотрели, как управлять
методами компонент во время
выполнения программы. Кроме того,
мы изучили, как что такое
информация периода выполнения и
научились использовать ее в целях
создания гибких и универсальных
приложений.
|