программирование :: delphi

От Delphi 4 к Delphi 5



От Delphi 4 к Delphi 5 Тип данных Variant.
В Delphi представлен качественно новый подход к обработке переменных тип Variant. Этот тип впервые был введен для поддержки OLE, но оказал большое влияние на весь язык. Тип данных Variant позволяет хранить любые типы данных и выполнять ряд специфических операций и преобразования типов.
Данный подход противоречит основному принципу языка Pascal и хорошему стилю программирования. Варианты вычисляются и проверяются на этапе выполнения. Вам не придет на помощь компилятор и не предупредит о несовместимости типов.
Но во многих случаях без типа Variant действительно не обойтись.
Рассмотрим пример использования типа данных Variant. Для этого поместите на форму три компонента Edit и кнопку Button.
Напишите следующий программный код:
procedure TForm1.Button1 Click(Sender: TObject);
var
V:Variant;
begin
V:=15;
Edit1.Text:=V;
V:=’Я и Delphi’;
Edit2.Text:=V;
V:= 78.56;
Edit3.Text:=V;
end;

end.
Результат работы программы показан на рисунке 1.
Что вы видите? Вы видите, что свойству Text элемента редактирования через переменную Variant можете присвоить не только строку, но также целое число или вещественное число.
Процесс компиляции прошел успешно.
Переменные типа Variant можно эффективно использовать для проведения вычислений.
Поместите на форму два компонента Edit и кнопку Button.
Напишите следующий программный код:
procedure TForm1.Button1 Click(Sender: TObject);
var
V:Variant;
K:Integer;
begin
V:=Edit1.Text;
K:=Integer(V)*6;
V:=K;
Edit2.Text:=V;
end;

end.
Перед запуском приложения на компиляцию введите числовые значения в свойство Text компонента Edit1. Результат работы представлен на рисунке 2.
Удобно использовать тип данных Variant, когда число вводится одного типа, а вычисления проводятся с данными другого типа, в дальнейшем преобразуя результат в значение, возможно, третьего типа.
Но во всех случаях необходимо соблюдать осторожность при работе с типом данных Variant.
Итак, мы установили, что тип данных Variant разработан для тех случаев, когда на этапе компиляции программист не может сказать, какого типа данные будут использоваться в выражении.
Язык Object Pascal является строго типизированным языком. Но тип Variant отступает от этих правил. В переменных типа Variant могут храниться данные любых типов, кроме записей, множеств, статических массивов, файлов, классов, ссылок на классы, указателей и Int64. Иначе говоря, переменные типа Variant могут хранить все, кроме структур, указателей и Int64. Они могут также хранить объекты COM и CORBA, обеспечивая доступ к их методам и свойствам, динамические массивы и специальные массивы Variant.
Variant имеет смысл использовать в тех случаях, когда тип того или иного объекта заранее не известен или когда какие-то функции и процедуры требуют именно такой тип аргументов. При этом надо иметь в виду, что затраты памяти и времени на работу с переменными типа Variant больше, чем при работе с обычными типами. К тому же недопустимые операции с переменными типа Variant приводят к ошибкам времени выполнения, тогда как недопустимые аналогичные операции с переменными других типов выявляются на этапе компиляции.
Переменные Variant занимают 16 бит и содержат код типа и значение переменной или указатель на это значение. В момент создания эти переменные инициализируются специальным значением Unassigned. Значение переменной null свидетельствует о неизвестном или ошибочном значении переменной.
В Object Pascal определены два особых значения Variant. Значение Unassigned применяется для указания, что вариантной переменной пока не присвоено значение какого бы то ни было типа. Значение Null указывает на наличие в переменной данных неизвестного типа или потерю данных. Разницу между этими двумя значениями трудно уловить. Значение Unassigned присваивается вариантным переменным автоматически при их создании, независимо от того, локальная это переменная или глобальная, и является ли она частью другой, структурной, переменной, такой как запись или массив. Unassigned означает, что к данной вариантной переменной еще не обращались. Null же означает, что к вариантной переменной обращались, но не ввели в нее никакой информации. Таким образом, Null указывает, что значение вариантной переменной недействительно или отсутствует.
Переменные типа Variant могут использоваться в выражениях как операнды любых операций, кроме ^, is и in, совместно с другими величинами типов variant, integer, real, string, boolean. Компилятор в этих случаях автоматически осуществляет приведение типов величин в выражении. Если оба операнда операции имеют тип Variant и один или оба операнда равны null, то результат операции тоже равен null. Если один или оба операнда имеют значение Unassigned, то генерируется исключение. Если в бинарной операции только один из операндов имеет тип Variant, то другой тоже преобразуется в тип Variant.
Приведение типов при вычислении выражений, содержащих операнды Variant, осуществляется обычным образом. Например, если V1 и V2 типа Variant содержат данные типов integer и real, то выражение V1 + V2 вернет значение real.
Узнать действительный тип значения переменной Variant можно с помощью функции VarType, возвращающей значение типа TVarData, содержащее код типа.
Следующий код демонстрирует использование вариантов и некоторых автоматических преобразований (конверсия), выполненных, когда варианты смешиваются с другим типом.
var
V1, V2, V3, V4, V5: Variant;
I: Integer;
D: Double;
S: String;
begin
V1 := 1; { целый тип }
V2 := 1234.5678; { действительный тип }
V3 := ‘Hello world!’; { строковый тип }
V4 := ‘1000’; { строковый тип }
V5 := V1 + V2 + V4; { действительный тип 2235.5678}
I := V1; { I = 1 (целый тип) }
D := V2; { D = 1234.5678 (действительный тип) }
S := V3; { S = ‘Hello world!’ (сроковый тип) }
I := V4; { I = 1000 (целый тип) }
S := V5; { S = ‘2235.5678’ (строковый тип) }
Правила преобразования при участии вариантов в выражениях, а также при присваивании их значений переменным других типов, размещенных в варианте данных, см в таблице 1.
Функция VarType позволяет узнать действительный тип значения переменной Variant. Функция возвращает значение типа TVarData, содержащее код типа. Запись TVarData определена в модуле System. Имеется также предопределенная константа varTypeMask, сложение которой по операции and с переменной типа TVarData возвращает истинный тип переменной. Например, выражение
VarType(V) and varTypeMask = varDouble
вернет True, если в переменной V в данный момент хранится значение типа Double или массив значений типа Double.
Возможные значения типов, возвращаемых функцией VarType, следующие:
varEmpty $0000 переменная в состоянии Unassigned;
varNull $0001 значение переменной равно null;
VarSmallint $0002 тип Smallint;
varInteger $0003 тип Integer;
varSingle $0004 тип Single;
varDouble $0005 тип Double;
varCurrency $0006 тип Currency;
varDate $0007 тип TDateTime (дата и время);
varOLEStr $0008 ссылка на динамически размещаемую строку UNICODE;
varDispatch $0009 ссылка на автоматический объект (указатель на интерфейс IDispatch);
varError $000A код ошибки операционной системы;
varBoolean $000B тип WordBool;
varUnknown $000D ссылка на неизвестный объект COM (указатель на интерфейс IUnknown);
varByte $0011 тип Byte;
varString $0100 ссылка на динамически размещаемую строку в стиле Pascal (тип AnsiString);
varTypeMask $0FFF битовая маска для извлечения кода типа;
varArray $2000 бит, устанавливаемый при ссылке на массив variant;
varByRef $4000 бит, устанавливаемый при ссылке на тип variant.
Двенадцать младших битов, определенные маской varTypeMask, соответствуют типу данных. Бит varArray установлен, если в переменной хранится массив данного типа. Бит varByRef установлен, если переменная является ссылкой на данный тип.
Необходимо обратить внимание, что использование вариантов приводит к увеличению длительности процесса вычислений и других операций.
Чтобы сравнить скорость работы программы с использованием данных типа Variant целого типа, проделайте следующие операции.
1. Запустите Delphi.
2. Поместите на форму четыре компонента Label, две кнопки Button, два компонента ProgressBar.
3. Запишите следующий программный код:
procedure TForm1.Button1 Click(Sender: TObject);
var
time1, time2: TDateTime;
n1, n2: Variant;
begin
time1 := Now;
n1 := 0;
n2 := 0;
ProgressBar1.Position := 0;
while n1 < 500000 do
begin
n2 := n2 + n1;
Inc (n1);
if (n1 mod 5000) = 0 then
ProgressBar1.Position := n1 div 5000;
end;
time2 := Now;
Label1.Caption := TimeToStr (Time2-Time1);
end;
procedure TForm1.Button2 Click(Sender: TObject);
var
time1, time2: TDateTime;
n1, n2: Integer;
begin
time1 := Now;
n1 := 0;
n2 := 0;
ProgressBar2.Position := 0;
while n1 < 500000 do
begin
n2 := n2 + n1;
Inc (n1);
if (n1 mod 5000) = 0 then
ProgressBar2.Position := n1 div 5000;
end;
time2 := Now;
Label2.Caption := TimeToStr (Time2-Time1);
end;
end.
Щелчок по кнопкам выдаст результат работы аналогичных программ, но работа с типом данных Variant требует большего времени (рисунок 3).

Компонент Shape.
Этот компонент расположен на странице Additional, он позволяет рисовать простейшие геометрические фигуры (прямоугольник, квадрат, скругленный прямоугольник, эллипс, окружность).
Определенная вами фигура полностью занимает все пространство компонента. В случае если задан квадрат или круг, а размеры элемента по горизонтали и вертикали отличаются, фигура отображается с размером меньшего измерения.
Свойство Brush (кисть) определяет цвет очерченной поверхности. Кисть используется для закрашивания замкнутых фигур, таких, как окружности или прямоугольники. Свойствами кисти являются ее цвет, стиль и иногда растровое изображение.
Свойство Pen (перо) определяет цвет и размер линий и границ фигур. Свойствами пера являются его цвет, размер (если это сплошная линия) или стиль. Среди возможных стилей есть несколько пунктирных и штриховых (размером в 1 пиксель).
Свойство Shape определяет вид геометрической фигуры: stCircle — круг, stEllipse — эллипс, stRectangle — прямоугольник, stRoundRect — прямоугольник с закругленными углами, stRoundSquare — квадрат с закругленными углами, stSquare — квадрат.
Рассмотрим пример использования компонента Shape.
1. Запустите Delphi.
2. Сохраните файл модуля под именем Shape_.pas, а файл проекта под именем Shape.dpr. Для нашего примера используйте компонент Shape в форме квадрата. Он будет перемещаться вокруг клиентской области формы через определенное число пикселей, а также с интервалом времени, которое вы установите. При столкновении со стенками формы квадрат изменяет направление движения. Эта фигура в данном примере связана с параметром Dir (направление), принимающее одно из следующих значений:
type
Directions = (up_right, down_right, down_left, up_left);
TForm1 = class(TForm)
Shape1: TShape;
В разделе private сделайте следующую запись:
private
Dir : Directions;
Поместите компонент Schape на форму. Для нашего примера поместите на форму компонент Timer со страницы System палитры компонентов, компонент ColorDialog со страницы Dialogs, компонент MainMenu со страницы Standard. Для компонента Timer установите свойство Enabled на странице Properties в значение False.
3. Сформируйте меню данной программы как показано на рисунке 4.
4. Запишите следующий программный код:
procedure TForm1.Start1Click (Sender: TObject);
begin
Timer1.Enabled := True;
Start1.Enabled := False;
Stop1.Enabled := True;
end;
procedure TForm1.Stop1 Click(Sender: TObject);
begin
Timer1.Enabled := False;
Start1.Enabled := True;
Stop1.Enabled := False;
end;
procedure TForm1.Timer1 Timer(Sender: TObject);
begin
case Dir of
up_right: begin
Shape1.Left := Shape1.Left + 10;
Shape1.Top := Shape1.Top – 10;
if Shape1.Top <= 0 then
Dir := down_right;
if Shape1.Left + Shape1. Width > = ClientWidth then
Dir := up_left;
end;
down_right: begin
Shape1.Left := Shape1.Left + 10;
Shape1.Top := Shape1.Top + 10;
if Shape1.Top + Shape1. Height > = ClientHeight then
Dir := up_right;
if Shape1.Left + Shape1.Width > = ClientWidth then
Dir := down_left;
end;
down_left: begin
Shape1.Left := Shape1.Left – 10;
Shape1.Top := Shape1.Top + 10;
if Shape1.Top + Shape1. Height > = ClientHeight then
Dir := up_left;
if Shape1.Left <= 0 then
Dir := down_right;
end;
up_left: begin
Shape1.Left := Shape1.Left – 10;
Shape1.Top := Shape1.Top -10;
if Shape1.Top <= 0 then
Dir := down_left;
if Shape1.Left <= 0 then
Dir := up_right;
end;
end;
end;
procedure TForm1.N2Click (Sender: TObject);
begin
if ColorDialog1.Execute then
Shape1.Brush.Color := ColorDialog1.Color;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ColorDialog1.Color := Shape1.Brush.Color;
Dir := down_left;
end;
procedure TForm1.N3Click (Sender: TObject);
begin
MessageDlg (‘Положение фигуры на форме X, Y (‘ +
IntToStr (Shape1.Left) + ‘, ‘ + IntToStr (Shape1.Top) + ‘).’,
mtInformation, [mbOk], 0);
end;
procedure TForm1.FormClose (Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
end.
Через определенные интервалы времени, которые вы можете установить для компонента Timer (рисунок 5), квадрат перемещается в соответствующем направлении. Как только он достигает границы формы, изменяется направление. Проверяются верхние и правые значения координат относительно нуля, а также нижние и правые значения координат относительно размера области клиента. Нижнее и правое значения координаты невозможно определить сразу, поэтому их можно вычислить, добавляя значение высоты фигуры к ее верхнему значению (или величину ширины к левому значению):
if Shape1.Top <= 0 then…
if Shape1.Top + Shape1.Height > = ClientHeight then…
if Shape1.Left + Shape1.Width > = ClientWidth then…
В программе имеется возможность получить значения координат квадрата на форме в любой момент времени.
Результат работы программы в виде траектории движения фигуры показан на рисунке 6.
Следующий программный код превращает компонент Shape в круг, внутренняя часть которого заполнена диагональными линиями красного цвета:
procedure TForm1.Button1 Click(Sender: TObject);
begin
Shape1.Shape:=stEllipse; {форма фигуры}
Shape1.Brush.Color:=ClRed; {цвет внутреннего заполнения фигуры}
Shape1.Brush.Style:=bsBDiagonal; {заполнение диагональными линиями}
Shape1.Pen.Width:=10; {толщина линии, в данном случае круга}
end;
end.


На рисунке 7 показаны значения комплексного свойства Brush для компонента Shape.
На рисунке 8 показаны некоторые значения комплексного свойства Pen для компонента Shape.

Литература:
1. Марко Канту. Delphi 2 для Windows 95/NT. Москва. ООО “Малип”. 1997г.
2. Джон Матчо. Дэвид Р. Фолкнер. Delphi. Москва. БИНОМ. 1995г.
3. Эндрю Возневич. Delphi. Освой самостоятельно. Москва. Восточная книжная компания. 1996г.
4. В.В.Фаронов. Delphi 5. Учебный курс. Москва. Издательство Нолидж. 2000г.
5. А. Я. Архангельский. Программирование в Delphi 5. Москва. ЗАО “Издательство Бином”. 2000г.
Владимир Скуратов



(c) компьютерная газета





© компьютерная газета