
- •Литература
- •Содержание
- •1. Основные понятия ооп
- •2. Программирование для Windows
- •3. Визуальное программирование и среда Delphi
- •Создание приложений в средеDelphi
- •Компоненты общего назначения tMainMenu- главное меню формы (программы)
- •TPopupMenu- вспомогательное (локальное) меню
- •TLabel- метка для отображения текста
- •TEdit-ввод и отображение строки
- •TMemo- ввод и отображение текста
- •TButton- кнопка
- •TBitBtn- кнопка с изображением
- •TSpeedButton- кнопка для инструментальных панелей
- •TCheckBox- независимый переключатель
- •TRadioButton- зависимые переключатели
- •TRadioGroup- группа зависимых переключателей
- •TListBox- список выбора
- •TComboBox- раскрывающийся список выбора
- •TPanel- панель
- •TTabControl- набор закладок
- •TPageControl- набор страниц с закладками
- •4. Особенности языка ооп Object Pascal
- •Процедуры и функции Выход из процедур и фукнций и возврат результата
- •Передача параметров
- •Параметры со значениями по умолчанию
- •Перегрузка функций
- •Динамическое распределение памяти
- •Указатели
- •Операции с указателями
- •Операция @
- •Самоадресуемые записи
- •Динамические массивы Одномерные динамические массивы
- •Многомерные динамические массивы
- •Исключения и их обработка
- •Защита кода зачистки в блокахtry...Finally
- •Защита кода зачистки на уровне модуля — разделfinalization
- •Обработка исключений в блокахtry...Except
- •Последовательность обработки исключений
- •5. Классы и объекты
- •Классы и объекты
- •Инкапсуляция
- •Наследование
- •Полиморфизм
- •Составляющие класса Поля
- •Одноименные методы
- •Свойства
- •События
- •Объявление класса
- •Операции с классами
- •Ссылки на классы
- •TObjectи информация о классах
- •Регистрация и обнаружение классов
- •6. Создание объектов во время выполнения, поиск компонентов
- •Клонирование объектов
- •Поиск компонента
- •Двукратное освобождение объекта
- •7. Построение собственных компонентов
- •Как и для чего следует строить компоненты
- •Общие руководящие принципы
- •Ключевые идеи
- •Компиляция компонентов
- •Отладка компонентов
- •Примечание
- •Примечание
- •Примечание
- •8. Работа с потоками
- •Классы потоковDelphi
- •Файловые потоки
- •Примечание
- •Методы потоков в действии: программаMemoStr
- •Потоки памяти
- •Пример программыMemoryS
- •Примечание
- •Написание заказного класса потока
- •9. Работа с com-объектами, использование серверов ole-автоматизации
TObjectи информация о классах
Первое, для чего предназначены ссылки на классы — это получение информации доступа, свойственной для полного класса. Для любой ссылки на класс TClass можно применять любой из методов класса TObject, перечисленных ниже:
• ClassName: возвращает строку с именем класса;
• ClassNameis: проверяет имя класса;
• ClassParent: возвращает ссылку на родительский класс;
• ClassInfo: возвращает указатель на информацию о типе класса во время выполнения программы (Run-Time Type Information — RTTI);
• InheritsFrom: проверяет, наследуется ли класс (прямо или косвенно) из данного базового класса;
• InstanceSize: возвращает размер объектов.
Однако некоторые методы класса TObject — это не методы классов, и поэтому их нельзя применить к ссылке на класс. Один пример — это функция ClassType, возвращающая тип класса.
Регистрация и обнаружение классов
Чтобы использовать методы класса, нам нужна ссылка на объект или класс. Очевидно, что этот класс должен быть доступен нашей программе (класс, для которого включены соответствующие модули), и нужно найти общие средства, которые можно использовать для доступа к методам класса. Один способ сделать это заключается в использовании функций FindClass или GetClass, возвращающих ссылку на класс по заданному имени класса. (Хотя и кажется, что эти две функции делают одно и то же, но на самом деле FindClass вызывает исключение, если она не находит имя класса, a GetClass возвращает указатель nil.)
На первый взгляд кажется, что эти функции дают нам именно то, что нужно: правильную ссылку на класс, которую можно использовать для вызова разных методов класса. Однако, необходимо зарегистрировать класс для каждой из этих функций для ее поиска. Это нужно сделать, так как система Delphi должна содержать полное описание того, как строить объекты данного класса в различных ситуациях. Для регистрации используется функция RegisterClass с параметром типа TPersistentClass.
Регистрацию классов можно выполнить слудеющим образом:
type
TClassArray = array[l..140] of TPersistentClass;
const
ClassArray: TClassArray =(
TBitmap, TGraphic, TOutlineNode, TGraphicsObject,
TBrush, THeaderSection, TParams, TCanvas,...
и так далее еще для 132 элементов. Теперь можно использовать этот массив и для регистрации классов, и для заполнения поля со списком:
procedure TForml.FormCreate(Sender: TObject);
var
i: integer;
begin
// регистрация всех классов
RegisterClasses{ClassArray);
// Использование - копирование имен классов в listbox
for i := Low(ClassArray) to High(ClassArray) do
ComboBoxl.Items.Add(ClassArray[i].ClassName);
end;
Этот код написан максимально пригодным для перестройки. Когда нам нужно добавить новый класс, мы можем просто увеличить размер массива в объявлении типа и добавить новый элемент.
6. Создание объектов во время выполнения, поиск компонентов
Сначала рассмотрим, как создать компонент периода выполнения, например, создание и размещение на форме кнопки:
procedure TForml.ButtonlClick(Sender: TObject);
var
NewButton: TButton;
begin
NewButton:= TButton.Create(self);
NewButton.Name := 'Button2';
NewButton.Left := 100;
NewButton.Top :=100;
NewButton.Parent := self;
End;
Этот код создает новую кнопку, дает ей имя, устанавливает ее позицию в форме и присваивает свойство Parent. Имя кнопки должно быть уникальным для данной формы. Каждый элемент управления (не все компоненты, производные только от TControl) должен иметь родителя, то есть компонент, производный от TWindow.
Примечание
Свойства Parent и Owner похожи, но различны. Свойство Parent позволяет компоненту, порожденному из TControl, связываться с его окном. Напротив, свойство Owner устанавливается во время вызова конструктора - в данном случае TButton. Create (self) . Свойство Owner определяет, какой компонент ответственен за разрушение другого компонента. В вышеприведенном коде форма является и владельцем и родителем компонента Button. Поэтому окно формы управляет отображением кнопки, и форма уничтожит кнопку, когда приложение уничтожает форму.
Если в программе требуется динамически создавать большое количество разнообразных компонентов, то целесообразно использовать более универсальные приемы, которые способны работать с объектами различных классов.
Для динамического создания объектов можно использовать ссылки на классы. Вместо создания конкретных экземпляров данного компонента, можно написать некоторый генерируемый код, способный создавать любой вид компонента.
procedure TForml.CreateComponents(X, У: Integer);
var
MyClass: TComponentClass;
MyComp: TComponent;
begin
MyClass := TComponentClass(GetClass(ComboBoxl.Text));
if MyClass = nil then Beep
else begin
MyComp := MyClass.Create(self);
MyComp.Name := GetNextName(MyClass);
if MyClass.InheritsFrom(TControl) then begin
TControl(MyComp).Left:= X;
TControl(MyComp).Top:= Y;
TControl (MyComp) . Parent := self;
end;
UpdateList;
end;
end;
Если исследовать этот код подробнее, то станет понятно, что приведение результата GetClass к классу TComponentClass является опасным. Необходимо убедиться, что все классы в глобальном массиве — действительно классы компонентов. Чтобы гарантировать это, можно временно изменить тип данных массива:
TClassArray = array[1..133] of TComponentClass;
Однако затем массив необходимо привести назад к типу данных TPersistentClass, чтобы суметь передать его в функцию RegisterClasses. Польза от этого изменения заключается в том, что оно позволяет нам скомпилировать код, чтобы подтвердить, что все классы, добавленные в массив, действительно происходят от TComponent.
Далее обратите внимание, что в этой функции свойство Name компонента установлено с использованием возвращаемого значения метода GetNextName. Этот метод ищет массив формы Components, подсчитывает число компонентов данного типа, уже существующих в форме, а затем добавляет это число в конец класса имени компонента (без начальной буквы "Т"), чтобы построить уникальное имя компонента внутри формы:
function TForml.GetNextName(MyClass: TComponentClass): string;
var
I, nTot: Integer;
begin
nTot := 0;
for I := 0 to ComponentCount - 1 do
if Components[I].ClassType = MyClass then Inc(nTot);
Result := Copy(MyClass.ClassHame, 2,
Length(MyClass.ClassName) - 1) + IntToStr(nTot);
end;
После установки свойства Name определяется позиция и родительское окно компонента, но только в том случае, если этот визуальный компонент -элемент управления. Обратите внимание на проверку:
if MyClass.InheritsFrom(TControl) then
Необходимо выполнить проверку этим способом, потому что оператор is неправомерен для проверки типа ссылки на класс. Конечно, проверку можно изменить следующим способом:
if MyComp is TControl then
и она бы работала точно также. В конце процедуры имеется вызов, UpdateList. Этот специальный метод просто заполняет второе поле со списком именами компонентов формы. Это делается для того, чтобы пользователи знали, какие компоненты созданы, так как некоторые из них не будут видимы. Вот код для метода UpdateList:
procedure TForrnl. UpdateList;
var
I: Integer;
begin
ComboBox2.Items.Clear;
for I:= 0 to ComponentCount - 1 do
ComboBox2.Items.Add(Components[I].Name);
end;
Delphi создает компоненты подобным способом. В некоторых ситуациях (таких как воссоздание объектов из информации в файлах или базе данных) может потребоваться создать компоненты, динамически использующие эти средства.