Правильная ссылка на эту страницу
http://az-design.ru/Support/SoftWare/Delphi/D3/SB02.shtml

Глава 2. Основы VCL

  • Программирование с использованием объектов
    • Чистые и гибридные языки
    • Концепции ООП
  • Модули и классы
    • Видимость класса
  • Visual Component Library
    • Обработка событий
    • Использование свойств
    • Методы
    • Директивы методов
  • Информация о типе времени выполнения
  • Использование Object Browser
  • Самостоятельное исследование VCL

       Visual Component Library (VCL) является ядром Delphi — первого языка визуального программирования с полностью интегрированной, объектно-ориентированной структурой. Являетесь ли вы прикладным программистом или разработчиком компонентов, изучение VCL и ее работы обязательно для овладения Delphi. Прикладные программисты должны знать свойства, методы и события, доступные для используемых компонентов. Разработчики компонентов для создания новых порожденных компонентов должны дополнительно представлять подробности внутренней работы VCL. Глава 2 представляет концепции, лежащие в основе объектно-ориентированного программирования в том виде, в котором они применяются в Delphi, и обсуждает структуру объектно-ориентированного каркаса Delphi — VCL. Однако глава не предназначена в качестве учебника для начинающих. Учебниками по своей сути являются многие из книг, перечисленных в приложении А, "Дополнительная литература".

Программирование с использованием объектов
       При наличии опыта работы с Visual Basic считайте, что Delphi — это "Visual Pascal". Начинающие программисты Delphi могут работать в новой среде во многом так же, как это делают пользователи Visual Basic: размещать объект в форме, посредством мыши изменять его размер, нажимать кнопку Run и — presto! — получилась настоящая Windows-программа. На первый взгляд среда программирования Delphi кажется подозрительно похожей на среду Visual Basic и, действительно, для простых задач так оно и есть. Программисты могут и не подозревать о мощи, которая скрывается в Delphi. Однако, в конце концов, понимание способов реализации и использования объектов становится критическим для задействования всего потенциала Delphi.

Чистые и гибридные языки
       Объектно-ориентированные языки можно разделить на две группы — на языки, которые считаются "чистыми" реализациями ООП, подобные SmallTalk и Simula, и языки-гибриды, например, C++ и Delphi. Object Pascal из Delphi является объектно-ориентированным расширением Pascal точно так же, как C++ является объектно-ориентированным расширением С. Цели Object Pascal и C++ одни и те же — они должны выполнять унаследованный код без изменений и в то же время обеспечивать все достоинства объектной ориентированности. Хотя адвокаты Pascal могут и скривиться, но использование ООП Delphi базируется в основном на модели C++, очень популярной в последние годы. Фактически гибридные языки, подобные C++ и Delphi, достигли больших успехов по сравнению с чистыми языками ООП, в основном благодаря тому факту, что их базовые языки были широко распространены и понятны. Программистам С и Pascal при переходе к объектно-ориентированному программированию не пришлось изучать совершенно новый язык.

Концепции ООП
       Объектно-ориентированному программированию (ООП) давно не достает краткого определения, хотя оно может быть совершенно простым, например: Приложение, созданное с помощью объектно-ориентированного языка, состоит из объектов. Каждый объект имеет определенные характеристики или свойства, поведение или методы и события, на которые объект отвечает. Класс является типом, шаблоном или прототипом, описывающим объект. Объект является экземпляром класса (переменной классового типа).
       Фрагмент кода в листинге 2-1 показывает простую программу Delphi (исключая для ясности несколько лишних строк), которая создает один экземпляр класса. Данный код, соответствующий пустой форме, генерируется Delphi автоматически при запуске нового проекта.

Листинг 2-1 Код базовой формы Delphi

unit Unitl; 
 
interface
 
uses
   Windows,Messages,SysUtils,Classes,Graphics,Controls,Forms,Dialogs;
 
type
   TForm1 = class(TForm)
 end;
 
var
   Form1: TForm1;
 
implementation
 
end.

В листинге 2-1 Delphi создает новый класс (тип данных) под названием TForm1, который порождается от класса TForm:

type
   TForml = class(TForm)
end;

       Если читать это по-русски, получится: "Я объявляю новый тип под названием TForm1, который является подвидом TForm".
       Для создания экземпляра нового класса следует определить переменную типа TForm1. Это делается в разделе var:

var
   Form1: TForm1;


       Приведенная запись означает: "Я хочу определить (создать в памяти экземпляр) переменную — объект — типа TForm1 под названием Form1". Происходящее концептуально похоже на определение экземпляра простого, родного Паскалю типа, подобного Integer.

var
   MyInteger: Integer;

Наследование
       Наследование, или порождение новых типов, случается даже в самых простейших программах Delphi и является одним из основных механизмов объектно-ориентированного программирования. Наследование — это то, что превращает VCL в иерархию. В Delphi все классы в конечном счете порождены от одного базового класса под названием TObject с порожденными классами, наследующими атрибуты порождающих классов и добавляющими собственную функциональность. Однако чаще всего новые классы Delphi порождаются от классов далеко внизу иерархии так, чтобы унаследовать больше атрибутов, чем имеется в TObject.
       Классовые структуры, подобные VCL, связаны отношениями родительский-дочерний, где на порождающий класс обычно ссылаются как на родителя или на базовый класс, а порожденный или производный класс рассматривается как дочерний (ребенок) базового класса. Классы ближе к корню иерархии имеют тенденцию быть более абстрактными или общими, тогда как классы дальше от корня — более специализированы и конкретны.

Полиморфизм
       Атрибуты, которые порожденные классы наследуют от своих родителей, в зависимости от необходимости можно использовать в неизменном виде или в модифицированном. Причина того, что атрибуты объявляются в классах-предках, состоит в совместном использовании атрибутов группой порожденных классов. Например, TObject, предок всех классов, содержит метод (процедуру или функцию Pascal) под названием Create. Все остальные классы наследуют данный метод, но каждый класс волен реализовать свою подходящую версию Create.
       Объектно-ориентированный механизм под названием полиморфизм делает возможным и желательным изменение поведения метода Create в зависимости от того, какой объект использует Create. Данный механизм предоставляет возможность получать доступ к разным объектам похожим способом, используя совместимый интерфейс. Если необходимо изменить реализацию свойства (одну из характеристик класса) или метод, перекрыть свойство или метод можно с использованием полиморфизма. Механизм полиморфизма интенсивно используется в VCL.

Инкапсуляция
       Еще одним базовым механизмом ООП является инкапсуляция, касающаяся сохранения свойств и методов класса в одном и том же блоке кода и определяющем отдельное хранение интерфейса класса и сто реализации. Интерфейс является частью программы, видимой пользователю (имеется в виду программист, получающий доступ к коду), и реализация является частью программы, которая видна только тому, кто написал код для класса. Object Pascal в Delphi принимает описанное правило буквально: обратите внимание на то, что в листинге 2-1 есть разделы по названиями interface и implementation. В таком маленьком примере в разделе implementation нет кода, но обычно это как раз то место, где содержится код обработчиков событий и методов. Инкапсуляция предоставляет программисту возможность получать доступ к объектам через их свойства, ничего не зная о деталях внутренней обработки.

Модули и классы
       Модуль представляет собой файл исходного кода Delphi, состоящий как минимум из трех частей — оператора unit, раздела interface и раздела implementation. Оператор unit является первой строкой кода и содержит имя, идентифицирующее модуль. В листинге 2-1 оператор unit выглядит следующим образом:

unit Unit1;

       При первом сохранении модуля ему обычно присваивается более описательное название. Если бы, например, данный модуль сохранялся с именем LoanTable.pas, оператор модуля изменился бы на

unit LoanTable;

       Раздел interface модуля содержит информацию, которая видна или может совместно использоваться другими модулями программы. Здесь размещаются объявления типов, переменных, констант, функций. Тела функций и процедур (реальные коды) в разделе interface никогда не встречаются.
       Раздел implementation следует за разделом interface и состоит из реального кода функций и процедур, объявленных в разделе интерфейса. Здесь могут объявляться любые типы, переменные, константы и методы, которые не должны быть видимы другим модулям.
       В модуле может быть необязательный раздел initialization, который используется для однократного выполнения кода при первой загрузке программы в память. По выбору включается также и раздел finalization, который выполняется при закрытии приложения. Общая структура модуля представлена в листинге 2-2.

Листинг 2-2 Разделы файла модуля

unit Unit1;
 
interface
 
uses <список других модулей доступных данному>;
 
// объявления типов, которые могут использоваться другими модулями 
type
   TForm1 = class(TForm)
private
   { Private declarations }
public
   { Public declarations  }
end;
 
// переменные,   которые могут использоваться другими модулями 
var
   Form1:   TForm1;
 
implementation
// переменные, которые скрыты от других модулей
// тела функций и процедур, объявленных в разделе interface
 
initialization
// необязательная инициализация модуля
 
finalization
// необязательная финализация модуля
 
end.


       Разделы файла модуля подытожены в таблице 2-1.

Таблица 2-1 Разделы файла модуля

Раздел модуля Используется для ...
interface Объявления, которые видимы другим модулям.
implementation Код методов и объявления, невидимые другим модулям.
initialization Необязательный раздел для кода, который выполняется при первой загрузке программы в память.
finalization Необязательный раздел для кода, который выполняется при закрытии программы.

       Модули являются основным способом, по которому Delphi определяет диапазон или видимость идентификаторов в программе. Все, что объявлено в разделе реализации, является локальным для данного модуля и не видно другим модулям. С другой стороны, раздел интерфейса является "лицом", которое модуль предоставляет внешнему миру.
       Файлы модулей всегда содержат пункт uses непосредственно за оператором unit. В пункте uses перечислены различные модули, к которым осуществляется доступ в данном модуле. По умолчанию во время старта нового проекта в пункте uses перечислены следующие файлы:

Windows, Messages, SysUtils, Classes,Graphics,Controls,Forms,Dialogs;

Пункт uses по сути дает данному модулю доступ к разделам интерфейса перечисленных модулей.

Видимость класса
       Разные разделы файла модуля используются для управления видимостью свойств, методов и событий внутри классов программы. Хотя большинство объявлений классов происходит внутри раздела интерфейса модуля, часто оказывается, что доступ к некоторым свойствам, методам и событиям необходимо ограничить. Delphi поддерживает различные уровни защиты доступа посредством спецификаторов видимости private, protected, public и published. Если объявление типа для TForm в листинге 2-2 расширить для демонстрации всех имеющихся спецификаторов видимости, объявление выглядело бы так:

TForm1 = class(TForm)
   private
      { Приватные объявления }
   protected
      { Защищенные объявления }
   public
      { Общедоступные объявления }
   published
      { Опубликованные объявления }
end;

Private


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

Protected
       Раздел Protected объявления класса содержит свойства, методы и события, которые доступны самому классу, порожденным классам и другим классам, объявленным в том же самом модуле, но не доступны коду в других модулях.

Public Свойства, методы и события Public доступны из любого места программы, независимо от того, находится ли код, осуществляющий доступ в том же самом модуле, что и объявление. Для того, чтобы модуль А имел доступ к общедоступным свойствам, методам и событиям модуля В, необходимо всего лишь включить имя модуля В в пункт uses модуля А.

Published
       Свойства, методы и события Published имеют тот же диапазон видимости, что и общедоступные (public) свойства, методы и события, но доступны из интерфейса времени выполнения и порождают информацию о типе времени выполнения (Run-Time Type Information — RTTI). Свойства, видимые в Object Inspector, объявлены в разделе published. Фактически это и является основным назначением спецификатора published: опубликованные свойства визуально доступны программисту во время конструирования. По умолчанию видимость для свойств, методов и событий класса — published, поэтому любое объявление сразу под объявлением класса в непоименованном разделе является по умолчанию published. В приведенном ниже объявлении типа формы к форме добавлена командная кнопка. Ее собственное объявление появляется непосредственно под объявлением формы, поэтому свойства, методы и события кнопки являются опубликованными.

type
   TForm1 = class(TForm)
   Button1: TButton;
end;


       Использование обсуждавшихся спецификаторов подытожено в таблице 2-2.

Таблица 2-2. Спецификаторы видимости класса

Модификатор Доступен из любого места того же самого модуля? Доступен из других модулей? Доступен из порожденных классов? Доступен через интерфейс времени конструирования? RTTI
Private   Нет Да (не рекомендуется) Нет Нет
Protected Да Нет Да Нет Нет
Public Да Да Да Нет Нет
Published Да Да Да Да Да

Visual Component Library
       Данная книга организована вокруг структуры Visual Component Library (Библиотеки визуальных компонентов). Как показано на рисунке 2-1, VCL имеет пять главных ветвей.
       Части книги со второй по шестую и посвящены этим ветвям: самому TObject (часть 2: Объекты), TPersistent (часть 3: Устойчивые объекты), TComponent (часть 4: Компоненты), TGraphicControl (часть 5: Неоконные элементы управления) и TWinControl (часть 6: Оконные элементы управления).
       Наиболее широко используется ветвь дерева TComponent, реализующая компоненты. Компоненты видны во время конструирования и к ним имеется доступ через Component Palette (Палитру компонентов). Они являются визуальными объектами, используемыми программистами Delphi во время конструирования. Обычно конструкторы компонентов создают новые компоненты порожденными от одного из множества дочерних компонентов TComponent. При необходимости новые компоненты наследуют функциональность указанных классов.
       Не все компоненты видны во время выполнения. Видимые носят название элементов управления и происходят от TControl - прямого потомка TComponent. Ниже по дереву есть оконные и неоконные элементы управления, которые инкапсулируют знакомые элементы Windows, такие как командные кнопки, кнопки линейки инструментов и метки. Как видите, классы в нижней части дерева являются гораздо более специфичными и функциональными, нежели абстрактные классы у корня дерева. Это хорошая объектно-ориентированная конструкция и многие структуры классов в VCL имитируют ее на разных уровнях.


Рис.2-1 Корень дерева VCL и часть ее самой важной ветви TControl

Обработка событий
       Общая цель VCL состоит в инкапсуляции требуемых программисту Windows элементов для создания живучих приложений. В отличие от других прикладных структур, подобных Object Windows Library от Borland (OWL) и Microsoft Foundation Classes (MFC), VCL связывает структуру ООП в действительно визуальную среду. Всякий раз, когда компонент выбирается из Палитры компонентов и помещается в форму, в коде Object Pascal создается экземпляр данного объекта. Если дважды щелкнуть на элементе управления в форме, в окне кода будет отображен обработчик событий по умолчанию. Delphi создает объявление метода и пустое тело метода, чтобы можно было сконцентрироваться на написании кода, выполняющегося при возникновении события. Объявление обработчика события помещается в интерфейсный раздел модуля текущей формы.

TForm1 = class(TForm)
   Button1: TButton;
   procedure ButtonlClick(Sender: TObject);
end;

       Пустое тело метода помещается в раздел реализации:

procedure Button1Click(Sender: TObject);
begin
end;

       В приведенном примере событие по умолчанию для кнопки — это OnClick, при этом имя по умолчанию, использованное для реализации обработчика события, следует синтаксису:

ClassName.ComponentNameClick(Sender: TObject)

       Такое стандартное соглашение упрощает создание обработчиков событий в Delphi.
       В случае необходимости создания обработчика события для события не по умолчанию, можно получить доступ к списку событий для каждого компонента. Это делается на вкладке Events окна Object Inspector. Например, тип TButton предоставляет возможность обрабатывать события для одиночного щелчка, двойного щелчка, транспортировки, нажатия и отпускания клавиши, удерживания клавиши, нажатия и отпускания кнопки мыши и для многого другого.

Использование свойств
       Свойства представляют собой атрибуты специальных классов, обеспечивающие возможность определения или изменения внешнего вида, положения и поведения объекта. Обычно они реализуются на уровне TPersistent или ниже по дереву VCL. Во время конструирования свойства текущего выделенного объекта видны на вкладке Properties окна Object Inspector. Во время выполнения свойства можно проверять и модифицировать посредством кода Object Pascal. Кроме того, многие объекты имеют свойства, которые можно изменять только во время выполнения (свойства времени конструирования всегда доступны во время выполнения). Многие из свойств времени выполнения предназначены только для чтения или только для записи.
       Внутренне свойства реализуются как поля или методы. Проверка значения свойства обычно вызывает приватный или защищенный метод данного класса — часто свойство бывает общедоступным интерфейсом к приватным данным. Это, конечно, прозрачно для пользователя компонента.

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

Директивы методов
       Object Pascal в Delphi для целей модификации области видимости и значения методов использует множество модификаторов. Они особенно распространены в исходном коде VCL. Если вы не пишете своих компонентов, можно не слишком беспокоиться по поводу директив. Однако ниже для наиболее передовых пользователей обсуждаются наиболее распространенные директивы методов.

virtual и dynamic
       Ключевые слова virtual и dynamic встречаются в VCL повсюду. Они используются для создания виртуальных методов, т.е. таких методов, которые разрешаются во время выполнения. По умолчанию методы, не являющиеся конструкторами, связываются статически во время компиляции. Ключевые слова virtual и dynamic перекрывают поведение по умолчанию, делая возможным динамическое или позднее связывание. Две директивы несколько отличаются друг от друга. Методы, объявленные dynamic, требуют немного меньше оперативной памяти, чем объявленные virtual, хотя выполняются медленнее. Для целей обсуждения будем считать, что virtual и dynamic являются одним и тем же.
       Методы делаются виртуальными путем добавления в объявление метода соответствующей директивы:

   procedure SetIndex(Value: Integer); virtual;
   procedure GetChildren(Proc: TGetChildProc); dynamic;

       Виртуальные методы можно перекрыть в порожденных классах. Когда виртуальный метод вызывается во время выполнения, тип объекта, вызывающего метод, определяет соответствующую реализацию метода, которую необходимо выполнять.

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

procedure SetIndex(Value: Integer); override;

abstract
       Метод abstract является виртуальным методом, обычно находящимся в абстрактном классе, для которого отсутствует определение реализации. Другими словами, абстрактный метод не определяется в том объекте, в котором объявляется — это "чистый" виртуальный метод. Абстрактные методы должны перекрываться, прежде чем их можно будет вызвать. В противном случае произойдет ошибка времени выполнения и программа завершится. Абстрактный метод объявляется с использованием директивы virtual или dynamic, за которой следует директива abstract:

function Get(Index: Integer): string; virtual; abstract;

Директивы методов подытожены в таблице 2-3.

Таблица 2-3 Распространенные директивы методов, имеющиеся в VCL

Директива метода Использовать для ...
Virtual Определения виртуального метода
Dynamic Определения виртуального метода
Override Перекрытия поведения метода в классе-предке
Abstract Создания интерфейса метода, но не его реализации

       К перекрытию абстрактного метода предъявляются те же требования, что и к перекрытию virtual или dynamic функции, хотя впоследствии использование inherited окажется невозможным. Inherited является ключевым словом, размещаемым в реализации метода в порожденном классе, используемым для выполнения одноименного метода в своем непосредственном предке.

Информация о типе времени выполнения
       Объекты в Delphi содержат информацию о собственном типе и наследовании, которая доступна во время выполнения. Такая информация называется run-type type information (RTTI) (информация о типе времени выполнения) и позволяет запрашивать тип объектов и затем действовать соответствующим образом. Это особенно важно в Delphi, поскольку большинство методов обработки событий принимают TObject как параметр Sender, чтобы метод можно было использовать в любом объекте. Например, обработчик события OnClick для командной кнопки можно вызывать различными объектами программы, а не только командной кнопкой.
       RTTI вводит новое ключевое слово is, которое идентифицирует тип объекта во время выполнения. Так, для примера командной кнопки кнопка линейки инструментов также может вызывать тот же самый метод. В таком случае следующий код используется для определения того, был ли вызывающий объект командной кнопкой:

procedure TForml.Button1Click(Sender: TObject);
begin
// если нажата командная кнопка, то просто закрыть программу
if Sender is TButton then Close
// в противном случае отобразить диалоговое окно и запросить пользователя, уверен ли он в
// своих действиях 
   else begin
      if Application.MessageBox('Really Close?','Are you sure?',MB_YESNO)=IDYES then Close; 
   end; 
end;

       RTTI чаще всего используется для безопасного приведения типов. Многие типы Object Pascal и Delphi нельзя законно привести к другим действительным типам. Если такая попытка приведения будет иметь место, возбуждается исключение. После того, как вы применили is для определения, совместим ли объект с указанным приведением, само приведение выполняется ключевым словом as

with Sender as TButton do 
// ...

Использование Object Browser
       Один из самых удачных способов изучения VCL предоставляет Object Browser — инструмент Delphi IDE, позволяющий исследовать классы, использованные в программах. Данный инструмент доступен в Delphi IDE после выбора Browse в меню View, хотя перед доступом программа должна успешно оттранслироваться. Отдельные объекты в программе можно просматривать, щелкая на них в исходном коде правой кнопкой и выбирая затем из всплывающего меню Browse Symbol at Cursor как показано на рисунке 2-2.
       Приведенный на рисунке 2-3 Object Browser предоставляет возможность избирательно отображать константы, методы, типы, переменные и свойства, их наследование и то, являются ли они приватными, защищенными, общедоступными или опубликованными. Виртуальные функции помечаются особо.
       Окно Object Browser разделено на две половины: панель Inspector, отображающую иерархию VCL в виде стандартного дерева, и панель Details, которая в свою очередь разделена на три страницы: Scope, Inheritance и Reference. Страница Scope панели Details отображает список тех символов, которые определены в просматриваемом модуле. Данная панель отображается по умолчанию. Страница Inheritance показывает вид просматриваемого дерева, похожего на отображаемое в панели Inspector. Последняя страница, Reference, показывает, где в исходном коде имеются ссылки на выбранный объект.
       Окно Object Browser оснащено полезными кнопками быстрого доступа (speedbar) (вид линейки инструментов Borland-стиля), расположенными вдоль верхнего края окна. Кнопки быстрого доступа предоставляют возможность настройки опций просмотра. Опции просмотра и отображения конфигурируются также и из быстрого меню (speedmenu) — всплывающего меню, которое активизируется щелчком правой кнопки мыши в любом месте окна Object Browser. Быстрое меню позволяет выполнять сортировку элементов по объектам, модулям, глобальным типам или символам.

Самостоятельное исследование VCL
       Супербиблия Delphi 3 представляет собой справочник программиста — головокружительный тур по иерархии и ее возможностям, сконструированный в виде краткого обзора. Сама организация книги отражает структуру VCL, поэтому при использовании книги вы начнете лучше понимать философию конструкции VCL. Кроме того, Система помощи Супербиблии Delphi 3, помещенная на CD-ROM, организует классы VCL в файл помощи стандартного формата, к которому можно обращаться во время работы с Delphi.
       Желаем успеха!


РИСУНОК 2-2 Запуск Object Browser с помощью щелчка правой кнопкой мыши


РИСУНОК 2-3 Окно Object Browser


<<< Пред. Оглавление
Начало раздела
След. >>>




Дата последнего изменения:
Thursday, 21-Aug-2014 09:10:56 MSK


Постоянный адрес статьи:
http://az-design.ru/Support/SoftWare/Delphi/D3/SB02.shtml