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

От Delphi 4 к Delphi 5
Трехмерные массивы.
Такие массивы могут быть представлены в виде трехмерного куба, имеющего ячейки одинакового типа и размера (рисунок 1).
Синтаксис объявления типов трехмерных массивов следующий:
type
ИмяТипаМассива = array [Определение индекса1, Определение индекса2, Определение индекса3] of Базовый тип;
Например:
TheTthreeDimensionalArray = array [1..3, 1..3, 1..3] of Real;
Array3D = array [1..4,Boolean, 1..50] of Byte;
Доступ к конкретному элементу массива возможен с использованием выражения:
ИмяМассива[Индекс1, Индекс2, Индекс3];
где Индекс1, Индекс2, Индекс3 — выражения, которые относятся к величинам соответствующего типа.
Например:
type
TheTthreeDimensionalArray = array [1..3, 1..3, 1..3] of Real;
procedure TForm1.Button1 Click(Sender: TObject);
var
AD: TheTthreeDimensionalArray;
R:Real;
begin
AD[1,1,1]:= 15;
AD[1,1,2]:= 28;
R:= AD[1,1,1] + AD[1,1,2];
Edit1.Text:= FloatToStr(R);
end;
end.

Многомерные массивы
В более редких ситуациях, когда требуется больше, чем три размерности, Object Pascal позволяет вам объявлять массивы любой размерности.
Синтаксис объявления типа многомерного массива следующий:
type
ИмяТипаМассива = array [ОпределениеИндекса1, ОпределениеИндекса2,..., ОпределениеИндексаN] of БазовыйТип;
например:
type
MonthlyAmounts = array [1..12,1..3,Boolean,-1..1] of Real;
TemperatureGrid = array [1..100,1..100,1..100,-1..1] of Byte;
Общее определение типа массива допускает любое число размерностей, обозначаемых произвольным выражением порядкового типа.
Object Pascal не накладывает ограничений на размерность массивов. Вы можете объявить столько размерностей, то есть, столько независимых индексов, сколько требуется. Существует, однако, ограничение на общий размер массива и на общий размер любой структуры данных, которая может быть определена.

Использование многомерных массивов
Отдельные элементы массива доступны через их индексы.
Ниже приведен синтаксис ссылки на конкретный элемент массива:
ИмяМассива[Индекс1, Индекс2, ИндексЗ,..., ИндексN]
Индекс1...ИндексN — в этом операторе произвольные выражения порядкового типа.
Доступ к отдельным элементам массива осуществляется путем указания имени массива и вслед за ним индекса (или списка индексов, разделенных запятыми, если у массива их несколько) в квадратных скобках. Вы можете, таким образом, получать значения отдельных элементов и заносить в указанные элементы новые значения.
Когда вы обращаетесь к элементам массива в своей программе, индексом массива может быть произвольное арифметическое выражение, результатом которого является целое число или выражение, которое можно привести к величине перечислимого типа, если эта величина совместима с указанным типом индекса и находится в указанных границах изменения индекса.
Объявление типа массива не создает действительного экземпляра массива. Вы уже знаете, что для резервирования места в памяти под переменную надо эту переменную определить. Указанное правило применимо и для массивов.
Элемент массива — это переменная, точно такая же, как и любая другая переменная базового типа массива. Просто вместо того, чтобы прямо ссылаться на переменную, указав ее название, в случае элемента массива приходится использовать имя массива и выражение для индекса в квадратных скобках, однозначно определяющее элемент в массиве. Различают статические и динамические массивы.

Статические массивы
Статические массивы предполагают определение его размеров в блоке type или var. Массивы, которые были рассмотрены ранее, относятся к статическим массивам.
Статические типы массива объявляются следующим образом:
array[indexType1,..., indexTypeN] of baseType
где каждый indexType — перечислимый тип, чей размер не превышает 2GB.
Самый простой случай — это одномерный массив, в нем имеется только единственный indexType.
Например:
var MyArray: array[1..100] of Char;
Объявляется переменная с именем MyArray, которая определена как массив из 100 символьных значений. Объявление вида MyArray [3] обозначает третий символ в массиве MyArray. Если вы создаете статический массив, но не назначаете значения для всех его элементов, то неиспользованные элементы распределены, но содержат случайные данные; они в этом случае подобны неинициализированным переменным.
Статический двумерный массив. Например,
type TMatrix = array[1..10] of array[1..50] of Real;
Является эквивалентным объявлению:
type TMatrix = array[1..10, 1..50] of Real;
Какой бы путь ни был для TMatrix объявлен, он представляет массив из 500 реальных значений. Переменная MyMatrix типа TMatrix может быть определена таким образом:
MyMatrix [2,45]; или: MyMatrix [2] [45].
Точно так же
packed array[Boolean,1..10, TShoeSize] of Integer;
Является эквивалентным следующему объявлению:
packed array[Boolean] of packed array[1..10] of packed array[TShoeSize] of Integer;
С целью экономии памяти, занимаемой массивами и другими структурными данными, вы можете предварять описание типа зарезервированным словом packed, например:
vаг A: packed array [I.. 10] of Byte;
Ключевое слово packed указывает компилятору, что элементы структурного типа должны храниться, т.е. располагаться плотно друг возле друга, даже если это замедляет к ним доступ. Если структурный тип данных описан без ключевого слова packed, компилятор выравнивает его элементы на 2-x и 4-байтовых границах, чтобы ускорить к ним доступ.
Ключевое слово packed применимо к любому структурному типу данных, т.е. к массиву, множеству, записи, файлу, классу, ссылке на класс.

Параметры в виде открытых массивов
Функции и процедуры в Object Pascal могут воспринимать в качестве параметров не только массивы фиксированного размера, но и так называемые открытые массивы, размер которых неизвестен. В этом случае в объявлении функции или процедуры они описываются как массивы базовых типов без указания их размерности. Например:
procedure SumArray(A:array of integer; var В: array of integer);
При таком определении передаваемый в функцию первый массив будет копироваться и с этой копией — массивом А, будет работать процедура. Второй открытый массив определен как var. Выбирая, как передавать открытый массив в функцию, надо учитывать, что если его размер очень велик, то при копировании будут большие затраты памяти и времени, а может произойти и аварийное завершение, если в стеке не хватит места.
Массив, переданный как открытый, воспринимается в теле процедуры или функции как массив с целыми индексами, начинающимися с 0. Размер массива может быть определен функциями Length — число элементов и High — наибольшее значение индекса. Очевидно, что всегда High = Length — 1.
В качестве примера рассмотрим процедуру, которая принимает два открытых одинакового размера массива целых чисел, суммирует их и заносит результат во второй из переданных массивов.
procedure SumArray(A:array of Integer; var В: array of Integer);
var
I:Word;
begin
for I:=0 to High(A) do B[I]:=A[I]+B[I];
end;
Вызов этой процедуры может иметь вид:
var
A1,A2: array [1..3] of Integer
begin
{операторы заполнения массивов}
SumArray(А1,А2);
end;
Обратите внимание на то, что массивы А и В, передаваемые в качестве аргументов, имеют значения индексов от 1 до 3, а процедура оперирует с индексами в диапазоне 0—2. Однако никакой путаницы не возникнет. Просто, например, элемент А[0] в теле процедуры будет соответствовать элементу А1[1] в массиве А1.
При вызове функции или процедуры с параметром в виде открытого массива можно использовать в качестве аргумента конструктор открытого массива, который формирует массив непосредственно в операторе вызова. Список элементов такого конструктора массива заключается в квадратные скобки, а значения элементов разделяются запятыми. Например, функцию Sum, суммирующую элементы числового массива, можно вызвать следующим образом:
S:= Sum([1.2,4.45,0.1]);

Динамические массивы
Среда Delphi 4 вводит концепцию динамических массивов.
Динамический массив не имеет установленного размера или длины. При этом память для динамического массива не распределяется при его объявлении.
В процессе разработки приложения вы можете установить массив с точно установленным размером, используя процедуру SetLength.
Например,
var MyFlexibleArray: array of Real;
Объявляется одномерный динамический массив вещественных чисел. Объявление не распределяет память для MyFlexibleArray.
Чтобы создавать массив в памяти, вызовите процедуру SetLength.
Например:
SetLength(MyFlexibleArray, 20);
Производится определение массива из 20 вещественных чисел, индексированного от 0 до 19. Динамические массивы, индексированные целым числом, всегда начинаются от 0 значения.
Используя динамические массивы, вы можете распределять памяти столько, сколько требуется в данное время. Вы можете перераспределять массив, используя функцию Copy.

Компонент StaticText
Отображение надписей на форме осуществляется с использованием компонента StaticText.
Для ввода текста применяется свойство Caption.
Цвет фона определяется свойством Color, а цвет надписи — свойством Color, являющегося комплексным свойством раздела Font. Если значение цвета специально не задавать, то цвет фона обычно сливается с цветом контейнера, содержащего компонент, так что фон просто не заметен.
Компонент StaticText имеет свойство BorderStyie, определяющее рамку текста или бордюр. На рисунке 2 вы можете видеть влияние бордюра на вид метки StaticText. При стиле sbsNone метка StaticText по виду не отличается от метки Label. Вероятно, если уж использовать бордюр, то наиболее приятный стиль sbsSunken.
Размещение компонента на форме определяется, в частности, свойствами Top, Left, Height, Width, Align, Anchors, Constraints. Они определяют координаты компонента, его размеры и их изменение при изменении пользователем размеров родительского компонента. При изменении пользователем размеров окна приложения надо перерисовывать компоненты, отображающие текст. Иначе выравнивание текста может нарушаться. Чтобы этого не было, надо в обработку события формы OnResize вставить операторы, перерисовывающие компоненты методом Repaint:
StaticTextl.Repaint;
Размер компонента StaticText определяется также свойством AutoSize. Если оно установлено в True, то вертикальный и горизонтальный размеры компонента определяются размером надписи. Если же AutoSize равно False, то выравнивание текста внутри компонента определяется свойством Alignment, которое позволяет выравнивать текст по левому краю, правому краю или центру клиентской области.
В компоненте StaticText перенос длинного текста осуществляется автоматически, если значение AutoSize установлено в False и размер компонента достаточен для размещения нескольких строк. Для того чтобы в StaticText осуществлялся перенос при изменении пользователем размеров окна, надо осуществлять описанную выше перерисовку компонента методом Repaint в обработчике события формы ОnResize.
Можно отметить еще одно свойство StaticText, превращающее его в некоторое подобие управляющих элементов. Это свойство FocusControl, фокусируемый компонент. Если в свойстве Caption поместить перед одним из символов символ амперсант "&", то символ, перед которым поставлен амперсант, отображается в надписи метки подчеркнутым (сам амперсант вообще не отображается). Если после этого обратиться к свойству метки FocusControl, то из выпадающего списка можно выбрать элемент, на который будет переключаться фокус, если пользователь нажмет клавиши быстрого доступа: клавишу Alt + подчеркнутый символ.
Для того чтобы клавиши быстрого доступа в компоненте работали, необходимо установить свойство ShowAccelChar в True.
Рассмотрим пример использования компонента StaticText. Главный смысл этого примера состоит в том, что вы вводите числовые значения в текстовые редакторы. Эти числа вы можете суммировать, умножать, делить, вычитать. Причем немного необычным способом. Например, чтобы провести умножение чисел, вы должны стать курсором на область формы, занимаемую компонентом StaticText2, нажать левую кнопку мыши и, не отпуская ее, перевести на компонент Edit4 справа от компонента Label 4 "Умножение". В результате в окне текстового редактора появится результат умножения двух чисел, причем атрибуты StaticText2 (шрифт, цвет) будут атрибутами компонента Edit2. В этом примере используется технология Drag & Drop.
1. Запустите Delphi.
2. Сохраните файл модуля под именем Account_.pas, файл проекта под именем Account.dpr.
3. Поместите на форму компонент StaticText1 со страницы Additional. В инспекторе объекта установите свойство Align равное alTop, свойство Alignment равное taCenter. Используя свойство Caption, запишите заголовок "StaticText1 Деление". Установите свойство Font по вашему желанию. Свойство Color установите равным clBtnHighlight.
4. Поместите на форму компонент StaticText2 со страницы Additional. В инспекторе объекта установите свойство Align равное alLeft, свойство Alignment равное taCenter. Используя свойство Caption, запишите заголовок "StaticText2 Умножение". Установите свойство Font по вашему желанию. Свойство Color установите равным clYellow.
5. Поместите на форму компонент StaticText3 со страницы Additional. В инспекторе объекта установите свойство Align равное alRight, свойство Alignment равное taCenter. Используя свойство Caption, запишите заголовок "StaticText3 Сумма". Установите свойство Font по вашему желанию. Свойство Color установите равным clLime.
6. Поместите на форму компонент StaticText4 со страницы Additional. В инспекторе объекта установите свойство Align равное alBottom, свойство Alignment равное taCenter. Используя свойство Caption, запишите заголовок "StaticText4 Разность". Установите свойство Font по вашему желанию. Свойство Color установите равным clInfoBk.
7. Поместите на форму шесть компонентов Edit, которые вы будете использовать следующим образом: для ввода первого числа, ввода второго числа, отображение результата умножения, деления, суммы и разности.
8. Поместите на форму шесть компонентов Label, для них введите соответствующие заголовки: "Первое число", "Второе число", "Деление", "Умножение", "Сумма", "Разность".
9. Для всех компонентов Edit и Static Text установите свойство DragMode равное dmAutomatic.
10. Для компонентов Edit3, Edit4, Edit5, Edit6, используя события DragOver и DragDrop, напишите программный код, показанный ниже.
implementation
{$R *.DFM}
var
A,B,C:Real;
procedure TForm1.Edit3Drag-Over(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
begin
Accept:= Source is TStaticText;
end;
procedure TForm1.Edit3DragDrop(Sender, Source: TObject; X, Y: Integer);
begin
if (Sender is TEdit) and (Source is TStaticText) then
begin
with Sender as TEdit do
begin
Font:= (Source as TStaticText).Font;
Color:= (Source as TStaticText).Color;
A:=StrToFloat(Edit1.Text);
B:=StrToint(Edit2.Text);
C:=A/B;
Edit3.Text:=FloatToStr(C);
end;
end;
end;
procedure TForm1.Edit4Drag-Over(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
begin
Accept:= Source is TStaticText;
end;
procedure TForm1.Edit4DragDrop(Sender, Source: TObject; X, Y: Integer);
begin
if (Sender is TEdit) and (Source is TStaticText) then
begin
with Sender as TEdit do
begin
Font:= (Source as TStaticText).Font;
Color:= (Source as TStaticText).Color;
A:=StrToFloat(Edit1.Text);
B:=StrToint(Edit2.Text);
C:=A*B;
Edit4.Text:=FloatToStr(C);
end;
end;
end;
procedure TForm1.Edit5Drag-Over(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
begin
Accept:= Source is TStaticText;
end;
procedure TForm1.Edit5DragDrop(Sender, Source: TObject; X, Y: Integer);
begin
if (Sender is TEdit) and (Source is TStaticText) then
begin
with Sender as TEdit do
begin
Font:= (Source as TStaticText).Font;
Color:= (Source as TStaticText).Color;
A:=StrToFloat(Edit1.Text);
B:=StrToint(Edit2.Text);
C:=A+B;
Edit5.Text:=FloatToStr(C);
end;
end;
end;
procedure TForm1.Edit6Drag-Over(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
begin
Accept:= Source is TStaticText;
end;
procedure TForm1.Edit6DragDrop(Sender, Source: TObject; X, Y: Integer);
begin
if (Sender is TEdit) and (Source is TStaticText) then
begin
with Sender as TEdit do
begin
Font:= (Source as TStaticText).Font;
Color:= (Source as TStaticText).Color;
A:=StrToFloat(Edit1.Text);
B:=StrToint(Edit2.Text);
C:=A-B;
Edit6.Text:=FloatToStr(C);
end;
end;
end;
end.
Результат работы программы показан на рисунке 3.
Вы можете в программе применить цикл for для уменьшения программного кода. В таком виде программа позволяет выполнять технологию Drag & Drop с любого компонента StaticText, причем вычисления производятся правильные, только поддерживаются атрибуты избранного компонента. Чтобы увидеть это, выберите курсором, например, компонент StaticText4, нажмите левую кнопку мыши и, не отпуская ее, протяните на компонент Edit4. Выполнится операция умножения, и атрибуты этого компонента будут соответствовать компоненту StaticText4.

Литература:
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) компьютерная газета


Компьютерная газета. Статья была опубликована в номере 45 за 2001 год в рубрике программирование :: delphi

©1997-2024 Компьютерная газета