Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
СРЕДСТВА ВИЗУАЛЬНОГО ПРОГРАММИРОВАНИЯ.doc
Скачиваний:
13
Добавлен:
02.05.2019
Размер:
2.13 Mб
Скачать

10.5. Пользовательские варианты

Стандартный вариант может хранить только одно из значений, указанных в табл. 10.2. В версии Delphi 6 появились так называемые пользовательские варианты, которые фактически снимают ограничения на характер значений варианта.

Чтобы познакомиться со свойствами новых вариантов, воспользуемся одним из них - вариантом, способным хранить комплексные числа, преобразовывать их в другие типы и осуществлять над ними нужные действия. Как мы увидим дальше, создание пользовательского варианта может быть весьма трудоемким делом - все зависит от сложности хранимых в нем данных. Мы воспользуемся вариантом, созданным разработчиками Delphi и включенным в модуль

VarCmplx.

Создайте такой обработчик bbRunClick:

uses VarCmplx; // Эта ссылка обязательна!

procedure TfmExample.bbRunClick(Sender: TObject);

var

VI, V2: Variants-begin

// Создаем два случайных комплексных числа:

VI := VarComplexCreate(Trunc(Random*1000)/100,

Trunc(Random*1000)/100) ;

V2 := VarComplexCreate(Trunc(Random*1000)/100,

Trunc(Random*1000)/100) ;

with mmOutput.Lines do

begin

// Пустая строка-разделитель

Add ( ' ' ) ;

Add('1-e число: '# 9+V1) ;

Add('2-е число: '#9+V2);

Add('Сложение'#9+(V1+V2));

Add('Вычитание'#9+(V1-V2));

Add('Умножение'# 9+(VI*V2)) ;

Add('Деление'#9#9+(V1/V2))

end

end;

Небольшой комментарий: сложная конструкция Trunc (Random*1000) /100 понадобилась только для того, чтобы реальные и мнимые части комплексных чисел содержали по три значащих цифры.

Вид экрана работающей программы показан на рис. 10.1. Как видим, новый вариант легко справляется с поддержкой комплексных чисел: функция VarComplexCreate создает вариант, содержащий комплексное число, а дальнейшее поведение варианта -стандартное (он поддерживает математические операции и преобразование к строковому типу). Однако эта легкость обманчива: исходный текст модуля VarCmplx, который, собственно, и придал варианту дополнительные свойства (по умолчанию располагается в файле Source\Rtl\Common\VarCmplx.pas), содержит более 30000 байт..

На с. 229 показана структура записи TVarData. Два первых байта в этой записи (поле VType) хранят признак значения варианта, остальные 14 могут использоваться для размещения данных.

Рис. 10.1. Демонстрация комплексных вариантов

Создание пользовательского варианта проходит в три этапа.

  1. Сначала в записи rvarData размещаются новые данные или ссылка на них.

  2. Объявляется класс, который является прямым или косвеннымпотомком специального класса TCustomVariantType. В этомклассе предусматриваются все необходимые методы для реализации свойств варианта: присваивания ему новых значений, преобразования хранящихся значений к другим типам, выполнения необходимых математических действий.

  3. Создаются вспомогательные методы для объявления потомков нового класса и определения их типов.

В результате перечисленных шагов вы получаете полноценный вариант, обогащенный новыми свойствами: он может хранить не только те значения, которые перечислены в табл. 10.2, но и любые другие, в том числе свойства и методы! (В этом последнем случае наследником для исполняемого класса нового варианта вместо TCustomVariantType является TInvokeableVariantType или TPublishableVariantType.)

10.5.1. Размещение в варианте новых значений

Для размещения в варианте нового (не предусмотренного стандартным вариантом) значения нужно создать соответствующий класс и поместить в подходящее поле rvarData объект этого класса. Вот как, например, размещаются комплексные данные в модуле VarCmplx:

TComplexVarData = packed record

VType: TVarType;

Reserved1, Reserved2, Reserved3: Word;

VComplex: TComplexData;

Reserved4: Longint;

end;

Такая запись лишь сохраняет 16-байтную структуру TVarData, помещая в поле VComplex ссылку на объект класса TComplexData. Собственно комплексные числа хранятся в полях достаточно сложного класса:

type

TComplexData = class(TPersistent) private

FReal, FImaginary: Double;

end;

В этом классе предусмотрены многочисленные методы, управляющие новыми данными. Так, простой вызов VarComplexCreate

приводит к срабатыванию нескольких методов, создающих объект VComplex и наполняющих его поля:

procedure VarComplexCreateInto(var ADest: Variant;

const AComplex: TComplexData);

begin

VarClear(ADest);

TComplexVarData(ADest).VType := VarComplex;

TComplexVarData(ADest).VComplex := AComplex;

end; function VarComplexCreate(const AReal, AImaginary: Double):

Variant;

begin

VarComplexCreateInto(Result,

TComplexData.Create(AReal, AImaginary)) ;

end;

(CM. файл Source\Rtl\Common\VarCmplx.pas).

З апись в которой размещаются новые данные или ссылка на поддерживающий их обьект, должно обьявляться как packed record.

10.5.2. Создание наследника TCustomVariantType

Тип TCustomVariantType или его ближайшие Наследники TPublishableVariantType и TInvokeableVariantType Содержат методы и

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

type

TComplexVariantType =

class(TPublishableVariantType, IVarStreamable) protected

function LeftPromotion(const V: TVarData;

const Operator: TVarOp;

out RequiredVarType: TVarType): Boolean; override;

function RightPromotion(const V: TVarData;

const Operator: TVarOp;

out RequiredVarType: TVarType): Boolean; override;

function Getlnstance(const V: TVarData): TObject; override;

public

procedure Clear(var V: TVarData);

override;

function IsClear(const V: TVarData): Boolean; override;

procedure Copy(var Dest: TVarData;

const Source: TVarData;

const Indirect: Boolean);

override;

procedure Cast(var Dest:

TVarData;

const Source: TVarData);

override;

procedure CastTo(var Dest: TVarData;

const Source: TVarData;

const AVarType: TVarType);

override;

procedure BinaryOp(var Left: TVarData;

const Right: TVarData;

const Operator: TVarOp); override;

procedure UnaryOp(var Right: TVarData;

const Operator: TVarOp);

override;

function CompareOp(const Left: TVarData;

const Right: TVarData;

const Operator: Integer): Boolean;

override;

procedure Streamin(var Dest: TVarData;

const Stream: TStream) ;

procedure StreamOut(const Source: TVarData;

const Stream: TStream) ;

end;

Обратите внимание: класс TComplexVariantType - интерфейсный (см. п. 9.4.1). Помимо общих для варианта методов он реализует также два метода, специфичных для интерфейса Ivarstreamabie -Streamin и StreamOut, с помощью которых значения нового интерфейса сохраняются в потоке и считываются из него.

Задача этого класса - дать единообразные команды, способные интерпретироваться объектом vcomplex как команды преобразования типа хранящихся данных, их сравнения, реализации над ними тех или иных операций, наконец, записи их в поток и чтения из него. Например, метод cast этого класса вызывается для преобразования других типов значений к комплексному типу, метод castTo - для обратного преобразования, метод BinaryOp реализует бинарную операцию, a Unarydp - унарную и т. д.

Еще раз подчеркну, что основная работа (например, по выполнению бинарных операций) реализуется методами класса TComplex-Data. Класс TCompiexVariantType перекрывает абстрактные методы своего родителя, подключая TComplexData к решению той или иной проблемы.

Поскольку для создания экземпляра нового варианта необходим уже готовый экземпляр (объект) класса TCompiexVariantType, он создается в секции инициализации модуля varcmpix и уничтожается в завершающей секции:

initialization

ComplexVariantType := TCompiexVariantType.Create;

finalization

FreeAndNil(ComplexVariantType);

10.5.3. Создание вспомогательных методов

Несмотря на интенсивное использование классов TCompiexData и TCompiexVariantType, эти классы в конечном счете остаются скрытыми от пользователя нового варианта за счет набора вспомогательных

методов, таких как VarComplexCreate, VarIsComplex, VarAsComplex и т.

п., которые преобразуют обычные процедурные вызовы в вызовы методов и обращения к свойствам соответствующих классов.

  • Лекция 11. ФАЙЛЫ

    • ДОСТУП К ФАЙЛАМ

    • ПРОЦЕДУРЫ И ФУНКЦИИ ДЛЯ РАБОТЫ С ФАЙЛАМИ

    • ТЕКСТОВЫЕ ФАЙЛЫ

    • ТИПИЗИРОВАННЫЕ ФАЙЛЫ

    • НЕТИПИЗИРОВАННЫЕ ФАЙЛЫ

    • СРЕДСТВА WINDOWS ДЛЯ РАБОТЫ С ФАЙЛАМИ

    • ОТОБРАЖЕНИЕ ФАЙЛОВ В ПАМЯТЬ

      • Создание/открытие файла

      • Создание объекта отображения

      • Создание окна просмотра

      • Освобождение ресурсов отображения

      • Пример использования

    • ОБЪЕКТНАЯ МОДЕЛЬ РАБОТЫ С ФАЙЛАМИ

Под файлом понимается именованная область внешней памяти ПК (жесткого диска, гибкой дискеты, диска CD-ROM).

Любой файл имеет три характерные особенности. Во-первых, у него есть имя, что дает возможность программе работать одновременно с несколькими файлами. Во-вторых, он содержит компоненты одного типа. Типом компонентов может быть любой тип Object Pascal, кроме файлов. Иными словами, нельзя создать “файл файлов”. В-третьих, длина вновь создаваемого файла никак не оговаривается при его объявлении и ограничивается только емкостью устройств внешней памяти.

Файловый тип можно задать одним из трех способов:

<имя> = File of <тип>;

<имя> = TextFile;

<имя> = File;

Здесь <имя> - имя файлового типа (правильный идентификатор);

File, of - зарезервированные слова (файл, из); TextFile - имя стандартного типа текстовых файлов; <тип> - любой тип Object Pascal, кроме файлов. Например:

type

Product = record Name: String; Code : Word;

Cost: Comp

end;

TextSO = File of String[80];

var

Fl: File of Char;

F2: TextFile;

F3: File;

F4: TextSO;

F5: File of Product;

В зависимости от способа объявления можно выделить три вида файлов:

  • типизированные файлы (задаются предложением File of ...);

  • текстовые файлы (определяются типом TextFile);

  • нетипизированные файлы (определяются типом File).

 В наших примерах f1, F4 и F5 - типизированные файлы, F2 - текстовый файл, F3 - нетипизированный файл. Вид файла, вообще говоря, определяет способ хранения в нем информации. Однако в Object Pascal нет средств контроля вида ранее созданных файлов. При объявлении уже существующих файлов программист должен сам следить за соответствием вида объявления характеру хранящихся в файле данных.