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

От Delphi 4 к Delphi 5 часть 33



От Delphi 4 к Delphi 5 Записи
Запись представляет собой набор именованных элементов данных, обрабатываемых как единое целое. Каждый элемент является полем, т.е. элементы записи называются полями. Записи представляют собой набор переменных. Обращение к записи возможно как к единому объекту, но возможно обращение и к отдельным элементам.
Синтаксис объявления типа записи:
type
ИмяТипа = record
ИмяПоля1: ТипПоля1;
ИмяПоля2: ТипПоля2;
...
ИмяПоляN: ТипПоляN;
end;
или
type
recordTypeName = record
fieldList1: type1;
fieldList2: type2;
...
fieldListN: typeN;
end;
где recordTypeName — идентификатор, который обозначает имя типа;
fieldList — разграниченный точкой с запятой список идентификаторов.
После зарезервированного слова record следует произвольное число описаний полей. Каждое описание оканчивается точкой с запятой. В конце определения типа записи стоит зарезервированное слово end.
Вы видите, что описание отдельного поля похоже на описание переменной. Поля являются переменными, объединенными вместе для образования новой структуры. Описание каждого поля начинается с названия поля, представляющего собой обычный идентификатор Паскаля, за которым следует двоеточие и указание типа. Описание каждого типа заканчивается точкой с запятой.
Например, следующее объявление создает тип записи под именем TDateRec:
type
TDateRec = record
Year: Integer;
Month: (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec);
Day: 1..31;
end;
Запись TDateRec содержит три поля: поле Year, имеющее целочисленное значение, поле Month, имеющее значение перечислимого типа, и поле Day, принимающее значение целых чисел от 1 до 31.
Идентификаторы Year, Month, Day являются полями для TDateRec, и они ведут себя подобно переменным. Объявление типа TDateRec, однако, не распределяет никакую память, память распределена, когда вы производите описание записи следующим образом:
var
Record1, Record2: TDateRec;
Такое объявление переменных создает два образца записи TDateRec, с именем Record1 и Record2.
Вы можете обращаться к полям записи, квалифицируя полевые указатели с именем записи:
Record1.Year:= 1904;
Record1.Month:= Jun;
Record1.Day:= 16;
При групповых операциях с полями удобно использовать оператор with. do, позволяющий не указывать перед каждым полем имя переменной типа записи:
with Record1 do
begin
Year:= 1904;
Month:= Jun;
Day:= 16;
end;
Вы можете также копировать значения полей из Record1 в Record2:
Record2: = Record1;
Поскольку возможности полей ограничены записью, в которой они описаны, вы не должны волноваться относительно возникновения конфликтов между полями записи и другими переменными.
Вместо определения типов записи, вы можете использовать определение записи в конструкции объявления переменных:
var
S: record
Name: string;
Age: Integer;
end;
Приведенное описание определяет переменную S безымянного типа записи, структура которой явно указана как часть описания переменной. Этот тип записи называется безымянным, или анонимным, так как он не имеет названия. Он используется только один раз для определения единственного объекта данных S. Не существует способа сослаться на этот тип вновь, например, для объявления другой переменной. Даже если вы введете другую переменную, скажем SS, аналогичным образом:
var
S: record
Name: string;
Age: Integer;
end;
то эти две переменные будут рассматриваться как относящиеся к различным типам.
Если вы попытаетесь выполнить присваивание подобно тому, что показано ниже, то транслятор выдаст сообщение об ошибке:
S:= SS;
[Error] Unit1.pas(38): Incompatible types — [Погрешность] Unit1.pas (38): Несовместимые типы.
Это происходит потому, что вторая переменная создает анонимный тип, и нет способа сообщить транслятору, что вы намереваетесь создать две переменные одинакового типа.
Единственный выход из этого положения — это введение типа с явно указанным именем в блоке объявления типов:
type
Swith = record
Name: string;
Age: Integer;
end;
var
S, SS: Swith;
Здесь тип Swith = record указан явно, и обе переменные относятся к одному типу.
Однако объявление анонимных типов наносит записям вред, вы не должны использовать такие объявления переменных.
Могут быть определены более сложные записи с вариантной частью. Основная цель указания вариантной части — экономия памяти. Синтаксис такого объявления следующий:
type <имя типа записи> = record
<список имен полей> : <тип> ;
...
<список имен полей> : <тип> ;
case <тег> : <порядковый тип> of
<список констант> : (<вариант 1> );
...
<список констант> : (<вариант 2> );
end;
или
type
recordTypeName = record
fieldList1: type1;
...
fieldListN: typeN;
case tag: ordinalType of
constantList1: (variant1);
...
constantListN: (variantN);
end;
Первая часть этого объявления до ключевого слова case не отличается от той, что была описана ранее. За словом case следует не обязательный элемент <тег> — произвольный допустимый идентификатор. Он вводится только для удобства и может быть пропущен вместе с последующим двоеточием. Затем указывается любой порядковый тип. После слова of следуют строки со списками констант типа, указанного как <порядковый тип> , завершающиеся двоеточиями. И после двоеточия в круглых скобках с завершающей точкой с запятой (не обязательно) записываются поля соответствующего варианта. Эти поля представляются в той же форме, как и основные поля структуры:
<список имен полей> : <тип> ;
...
<список имен полей> : <тип> ;
В полях вариантов нельзя использовать типы длинных строк, динамических массивов, variant, а также структуры, содержащие поля этих типов.
Тег и списки констант вводятся для удобства программирования. Никакой смысловой нагрузки они не несут, а просто помогают разобраться, к чему относится каждый вариант. Константы в списках не должны повторяться.
Поля различных вариантов размещаются в одной и той же области памяти, перекрывая друг друга. Размер этой перекрываемой области компилятор выбирает по размеру, необходимому для наиболее объемного варианта.
В записи могут быть поля, содержащие указатели на другие аналогичные записи. Такие записи называются самоадресуемыми и используются для организации в динамически распределяемой области памяти списков структур. Пример такой самоадресуемой структуры.
type
trec=^rec;
rec = record
in1,in2:word;
s:string[10];
pr:trec
end;
Подобное описание является исключением из общего правила языка Pascal, по которому нельзя использовать в предложениях еще не объявленные типы и переменные. В данном случае первое предложение объявляет тип trec как указатель на структуру типа, объявленного после этого. Сразу за этим предложением следует объявление самой структуры. В этом объявлении имеется поле pr, представляющее собой указатель на структуру аналогичного вида.
Вариантные записи имеют две цели. Сначала вы предполагаете, что хотите создать тип записи, который имеет поля для различных видов данных, но вы знаете, что, возможно, никогда не будете использовать все поля в данной записи.
Например,
type
TEmployee = record
FirstName, LastName: string[40];
BirthDate: TDate;
case Salaried: Boolean of
True: (AnnualSalary: Currency);
False: (HourlyWage: Currency);
end;
Так, когда вы объявляете запись TEmployee, распределятся достаточно памяти для обоих полей. В этом случае единственная разница между вариантами находится в именах полей, но поля могут иметь различные типы. Рассмотрим более сложные примеры:
type
TPerson = record
FirstName, LastName: string[40];
BirthDate: TDate;
case Citizen: Boolean of
True: (Birthplace: string[40]);
False: (Country: string[20];
EntryPort: string[20];
EntryDate, ExitDate: TDate);
end;
type
TShapeList = (Rectangle, Triangle, Circle, Ellipse, Other);
TFigure = record
case TShapeList of
Rectangle: (Height, Width: Real);
Triangle: (Side1, Side2, Angle: Real);
Circle: (Radius: Real);
Ellipse, Other: ();
end;
Вторая причина применения вариантных записей — то, что они позволяют вам обрабатывают данные, принадлежащие к различным типам, даже в случаях, где транслятор не позволил бы их обработать.
Вариантная часть напоминает условный оператор case. Между словами case и of записывается особое поле записи — поле признака. Оно определяет, какой из вариантов в данный момент будет активизирован. Поле признака должно быть равно одному из расположенных следом значений. Каждому значению соответствует вариант записи. Он заключается в круглые скобки и отделяется от своего значения двоеточием.
Обратите внимание, что у вариантной части нет отдельного слова end, как это можно было ожидать по аналогии с оператором case. Одно слово end завершает и вариантную часть, и запись.

Константы-записи
Чтобы объявлять константу-запись, определите значение каждого поля как величины, отделенные точками с запятой в круглых скобках в конце объявления. Эти значения должны быть представлены постоянными выражениями. Поля перечисляются в порядке, в котором они появляются в объявлении типа записи и поле отметки.
Определение константы записи имеет следующий вид:
<идентификатор> : <тип> = (<список значений полей> );
где <идентификатор> — идентификатор константы;
<тип> тип записи;
Например:
type
TPoint = record
X, Y: Single;
end;
TVector = array[0..1] of TPoint;
TMonth = (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec);
TDate = record
D: 1..31;
M: TMonth;
Y: 1900..1999;
end;
const
Origin: TPoint = (X: 0.0; Y: 0.0);
Line: TVector = ((X: -3.1; Y: 1.5), (X: 5.8; Y: 3.0));
SomeDay: TDate = (D: 2; M: Dec; Y: 1960);
Поля должны указываться в той последовательности, в какой они перечислены в объявлении типа. Если в записи используется хотя бы одно поле файлового типа, такую запись нельзя объявить типизированной константой. Для записей с вариантными полями указывается только один из возможных вариантов констант.
Вы можете в качестве элемента массива использовать запись.
Например:
type
Trec = record
Field1:Integer;
Field2:String;
Field3:Real;
end;
TArray = array [1..5] of TRec;
end.

Компонент ControlBar
ControlBar предназначен для размещения инструментальных панелей ToolBar. Он использует технологию Drag & Dock для управления положением панелей.
Свойство AutoDrag разрешает или запрещает компонентам ToolBar покидать границы ControlBar.
Свойство Picture содержит изображение, которое, периодически повторяясь, создает фон компонента.
Свойство RowSize задает высоту одного ряда инструментальных панелей. Умалчиваемое значение 25 в точности соответствует высоте одной панели, и в этом случае между рядами нет зазора.
Свойство RowSnap содержит True, “причаливаемая” панель будет выравниваться по высоте ряда.
Рассмотрим некоторые события компонента ControlBar.
type TBandDragEvent = procedure (Sender: TObject; Control: TControl; var Drag: Boolean) of object;
property OnBandDrag: TBandDragEvent;
Используйте событие OnBandDrag, чтобы иметь возможность производить перемещение, установленное параметром Control. Измените параметр Drag на False, чтобы предотвратить операцию перемещения.
TBandInfoEvent = procedure (Sender: TObject; Control: TControl; var Insets: TRect; var PreferredSize, RowCount: Integer) of object;
Происходит, когда инструментальная панель корректирует прикрепляющуюся позицию полосы.
Событие используется, чтобы иметь информацию инструментальной линейки, которую он может использовать при перемещении компонентов, расположенных на ней. OnBandInfo имеет несколько параметров, которые могут применяться, чтобы возвратить информацию относительно того, как компонент должен быть установлен, включая его размер и число строк.
TBandMoveEvent = procedure (Sender: TObject; Control: TControl; var ARect: TRect) of object;
Возникает это событие при перемещении панели внутри компонента.
Sender — компонент, на котором происходит перемещение.
Control — компонент, обычно ToolBar.
ARect — область (прямоугольник), в которую панель собирается быть перемещенной.
TBandPaintEvent = procedure (Sender: TObject; Control: TControl; Canvas: TCanvas; var ARect: TRect; var Options: TBandPaintOptions) of object;
Это событие происходит при необходимости прорисовки панели. Назначение составляющих: Sender — компонент, Control — панель, Canvas — канва для прорисовки, Options — определяет, какая часть панели нуждается в прорисовке.
Рассмотрим пример использования компонента ControlBar.
1. Запустите Delphi.
2. Сохраните файл модуля под именем UsageOfAToolbar_.dpr, а файл проекта под именем UsageOfAToolbar.dpr.
3. Поместите на форму компонент ContRolBar со страницы Additional, установите свойство Align равным alTop, свойство AutoSize равным True. Установите свойство DragKind равным DkDock.
4. Поместите на форму два компонента ImageList со страницы Win32 палитры компонентов. Для заполнения их изображениями произведите двойной щелчок мышью по этим компонентам или щелкните правой кнопкой мыши над ним и из всплывающего меню выберите команду ImageList Editor. В окне Редактора нажмите кнопку Add, выберите любой файл с расширением .bmp из каталога C:\Program Files\Common Files\Borland Shared\ Images\Buttons. Файлы в этом каталоге имеют по два изображения, в то время как компонент может хранить только одиночные изображения одинакового размера. ImageList Editor предложит вам разделить два изображения, согласитесь с ним. Произведите щелчок по правому изображению в окне редактора (оно предназначено для отображения кнопки в запрещенном состоянии) и нажмите по кнопке Delete для ее уничтожения.
5. Поместите еще несколько изображений в компоненты, например два или три.
6. Поместите компонент ToolBar на компонент ControlBar. Установите для него значение Width равным 20 для Delphi 4. Это необходимо, так как в этой версии он сожмется и будет трудно щелкать по нему правой кнопкой мыши.
7. Установите в свойство Images компонента ToolBar1 значение ImageList1 и поместите в него столько кнопок, сколько изображений вы подготовили в ImageList1. Для того чтобы вставить кнопки на компонент Toolbar1, необходимо щелкнуть правой кнопкой мыши на нем и выбрать опцию NewButton такое количество раз, сколько рисунков вы поместили в компонент ImageList1.
8. Поместите на форму еще один компонент ToolBar. Он автоматически прижмется к нижнему краю компонента ControlBar1. Для того чтобы вставить кнопки на компонент Toolbar2, необходимо щелкнуть правой кнопкой мыши на нем и выбрать опцию NewButton такое количество раз, сколько рисунков вы поместили в компонент ImageList2.
9. Измените в его свойстве Align значение alTop на alNone и мышью сместите компонент несколько вниз. Далее свяжите ToolBar2 c ControlBar1, используя свойство Images.
10. Для обоих компонентов поместите в свойства DragKind значения dkDock, в DragMode — dmAutoMatic, AutoSize — True.
11. Запустите приложение на компиляцию. Вы можете перемещать компонент ToolBar2 в любое место экрана и компонента ControlBar. Сам компонент ControlBar вы также можете поместить в любое место экрана.

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

Владимир Скуратов


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





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