Чтобы полностью понять и
почувствовать все преимущества
Delphi, Вам нужно хорошо изучить язык
Object Pascal. И хотя возможности
визуальной части Delphi чрезвычайно
богаты, хорошим программистом
может стать только тот, кто хорошо
разбирается в технике ручного
написания кода.
По мере обсуждения темы данного
раздела мы рассмотрим несколько
простых примеров, которые, тем не
менее, демонстрируют технику
использования важных управляющих
элементов Windows.
Создание методов с
помощью визуальных средств
В предыдущем уроке Вы видели, что
синтаксический “скелет” метода
может быть сгенерирован с помощью
визуальных средств. Для этого,
напомним, нужно в Инспекторе
Объектов дважды щелкнуть мышкой на
пустой строчке напротив названия
интересующего Вас события в
требуемом компоненте. Заметим, если
эта строчка не пуста, то двойной
щелчок на ней просто переместит Вас
в окне Редактора Кода в то место,
где находится данный метод.
Для более глубокого понимания
дальнейшего изложения кратко
остановимся на концепции
объектно-ориентированного
программирования. Для начала
определим базовое понятие
объектно-ориентированного
программирования - класс. Класс -
это категория объектов, обладающих
одинаковыми свойствами и
поведением. При этом объект
представляет собой просто
экземпляр какого-либо класса.
Например, в Delphi тип “форма” (окно)
является классом, а переменная
этого типа - объектом. Метод - это
процедура, которая определена как
часть класса и инкапсулирована
(содержится) в нем. Методы
манипулируют полями и свойствами
классов (хотя могут работать и с
любыми переменными) и имеют
автоматический доступ к любым
полям и методам своего класса.
Доступ к полям и методам других
классов зависит от уровня
“защищенности” этих полей и
методов. Пока же для нас важно то,
что методы можно создавать как
визуальными средствами, так и путем
написания кода вручную.
Давайте рассмотрим процесс
создания программы CONTROL1, которая
поможет нам изучить технику
написания методов в Delphi.
Для создания программы CONTROL1
поместите с помощью мышки
компонент Edit (находится на
страничке “Standard” Палитры
Компонентов) на форму. После этого
ваша форма будет иметь вид,
показанный на 8.
Теперь
перейдите в Object Inspector, выберите
страничку “Events” и дважды щелкните
в пустой строчке напротив события
OnDblClick, как показано на 8. После этого
в активизировавшемся окне
Редактора Вы увидите
сгенерированный “скелет” метода
Edit1DblClick, являющегося реакцией на
событие OnDblClick:
procedure TForm1.Edit1DblClick(Sender: TObject);
begin
end;
После генерации процедуры Вы
можете оставить ее имя таким, каким
“установил” Delphi, или изменить его
на любое другое (для этого просто
введите новое имя в указанной выше
строке Инспектора Объектов справа
от требуемого события и нажмите
Enter).
Теперь в окне Редактора Кода
введите смысловую часть метода:
procedure TForm1.Edit1DblClick(Sender: TObject);
begin
Edit1.Text:= 'Вы дважды щелкнули в строке редактирования';
end;
Сохраните программу. Во время
выполнения дважды щелкните на
строке редактирования. Текст в этой
строке изменится в соответствии с
тем, что мы написали в методе
Edit1DblClick: см. 8.
Рис. 8: Содержимое
управляющего элемента TEdit
изменяется после двойного щелчка
по нему
8 и 8 предоставляют полный код
программы 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.
Далее мы не будем подробно
останавливаться на том, как
размещать компоненты на форме -
считаем, что это Вы уже умеете.
После того как Вы разместили на
форме семь компонентов 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.
Это, напомним, можно сделать двумя
способами:
Перейти в Инспекторе Объектов
на страничку “Events”
(предварительно выбрав
компонент Button1 на форме),
выбрать слово OnClick и дважды
щелкнуть мышкой на пустой
строчке справа от него
Просто дважды щелкнуть на
компоненте 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 показывает полный текст
головного модуля программы PARAMS. Мы
не включили сюда файл проекта,
поскольку, как уже упоминалось, он
практически одинаков для всех
программ.
Листинг -C: Исходный код головного
модуля программы PARAMS показывает,
как использовать строки
редактирования и как передавать
параметры.
Unit Main;
interface
uses
WinTypes, WinProcs, Classes,Graphics, Controls,Printers, Forms,
StdCtrls;
tye
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.
Заметим, что Вы должны “положить”
компонент 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.
Итак, мы видим, что используя
информацию периода выполнения,
можно сделать программу очень
гибкой и универсальной.
Заключение
В этом уроке мы рассмотрели, как
управлять методами компонент во
время выполнения программы. Кроме
того, мы изучили, как что такое
информация периода выполнения и
научились использовать ее в целях
создания гибких и универсальных
приложений.
[ Предыдущий урок | Содержание | Следующий урок ]
|