- •Windows -приложение
- •Среда программирования
- •Встроенный отладчик
- •Использование графики
- •Графические данные и палитра
- •Сохранение проекта
- •Структура приложения
- •Структура модуля
- •Простые типы
- •Символьные типы
- •Логические типы
- •Тип перечень
- •Составной оператор
- •Оператор if
- •Оператор цикла for
- •Оператор цикла while
- •Оператор цикла repeat
- •Пример приложения 6
- •Пример приложения 7
- •Статические массивы
- •Динамические массивы
- •Оператор with
- •Идентичность типов
- •Совместимость типов
- •Преобразование типов
- •Операторы обработки исключительных ситуаций
- •Рекурсия
- •Процедура exit
- •Директивы подпрограммы
- •Класс как объектный тип
- •Наследование
- •Операции is и as
- •Типы ссылки на класс
- •Типизированные файлы
- •Файлы без типа
- •Пример приложения 17
- •Компонент tmainmenii
- •Двунаправленные списки
- •Потоки данных
- •Пример приложения 22
- •Интерфейс drag and drop
- •Пример приложения 24
- •С файлами
- •Пример приложения 26
- •Программные потоки
- •Приоритеты потоков
- •Класс tthread
- •Проблемы синхронизации потоков
Динамические массивы
Динамический массив, в отличие от статического, объявляется как ссылка на некоторый адрес, по которому будут размещаться данные, например, Var V = array of real; VI = array of integer;.
Каждая из объявленных переменных (v или vi) может иметь значение какого-то адреса. Прежде чем располагать данные, этот адрес переменная
68
должна получить. Память под данные выделяется процедурой SetLength: SetLength(V,5); SetLength(VI,10);.
В данном случае объявлено 5 элементов одномерного массива вещественных чисел v и 10 элементов массива целых чисел vi. Нужное количество памяти выделится процедурой SetLength, эта же процедура присвоит конкретные значения адресов переменным v и vi.
Имеются особенности в использовании динамических массивов. Первая -нумерация индекса всегда начинается с нуля. Вторая особенность касается правил выполнения операции присваивания, например, пусть объявлено: lype Vekt = array of real; Var VI,V2:Vekt;. Присваивание VI :=V2; для статических массивов означает, что содержимое памяти VI заменяется содержимым памяти V2 (элементы массива VI получили значения элементов V2). Если учесть, что в случае с динамическими массивами vi и V2 являются ссьшками (адресами), адрес VI заменяется на адрес V2. Таким образом, присваивание vi: =V2; привело к тому, что VI и V2 ссылаются теперь на один и тот же участок памяти, т.е. элементы массива VI равны элементам V2, но потерялся адрес vi, соответственно потерялся и выделенный участок памяти, начиная с адреса VI.
Освободить память, выделенную под VI, можно, вызвав перед операцией присваивания vi :=V2; процедуру Finalize: Finalize (VI); или просто присвоив VI:=nil;.
Динамические массивы могут быть и многомерными, например объявив Var W:array of array of real;. Далее в программе можно задать размерности массива SetLength (W, 5,10) ;.
Динамические массивы позволяют, например, создавать треугольные матрицы, имеющие различные размерности индексов. Интерес к таким массивам в вычислительной математике очень большой. Для создания таких массивов сначала нужно задать размерность по первому индексу, например Для объявленного выше двумерного массива W так: SetLength (w,3) ;. Это означает, что массив будет состоять из 3 строк. Теперь длину каждой строки зададим отдельно: SetLength(W[0] ,1) ; SetLength(W[l] ,2) ; SetLength (w[2] ,3) ;• Если требуется освободить память из-под такого массива, то используется один вызов процедуры Finalize или одно присваивание W:=nil;.
Начальный и конечный индексы динамического одномерного массива v Можно определять функциями Low (V) (равно 0) и High (V) . Так, например, в следующем операторе For i: =Low (v) to High (V) do . . . ; целесообразно не указывать непосредственно верхнюю границу для циклических вычислений, поскольку в программе можно неоднократно менять размерность динамических массивов.
69
ПРИМЕР ПРИЛОЖЕНИЯ 8
Задан одномерный массив чисел X = (0,2; 0,7; 1,8; 3,1; 4,2). Получить таблицу косинусов для этих чисел, т.е. рассчитать cos(0,2), cos(0,7), cos(4,2). На рис. 23 представлен вариант решения этого примера.
Рис.23
Для решения задачи был использован новый компонент TStringGrid (таблица строк), который находится на странице Additional палитры компонентов. Данный компонент представляет собой двумерную таблицу. Число строк задается свойством RowCount, а число столбцов - ColCount. Размеры одной ячейки таблицы на экране задаются свойствами DefaultColHeight и DefaultRowWidth в пикселах. Компонент может использоваться для имитации чего-либо похожего на таблицу. Доступ к отдельной ячейке таблицы осуществляется с помощью свойства Cells[ij], где i - номер столбца, j - номер строки. Отсчет номеров столбца и строки начинается с нуля. Часть строк и столбцов, используемых в таблице, можно зафиксировать. Тогда они будут недоступны пользователю. Для этого нужно задать свойство FixedRows и FixedCols (фиксированное число строк и столбцов). Фиксированные колонки и строки закрашиваются в другой цвет. Используются они для заголовков. С помощью свойства goEdit можно запретить или разрешить редактирование ячеек таблицы.
В данном примере для StringGridl установлено: ScroIIBars = ssNone, RowCount = 6, ColCount = 3, FixedRows = 1, FixedCols = 1, GoEdit = false. Ниже приводится программа для данного примера.
unit prim8; interface
uses Windows, Messages, SysUtils,Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons, ExtCtrls, Grids;
70
type
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
BitBtnl: TBitBtn;
StringGridl: TStringGrid;
procedure Button1Click(Sender: TObnect);
end;
Form1: TForm1; implementation
Procedure TForm1.Button1Click(Sender: TObject) ;
,3.1,4.2);
x:array [l..n] of real =(0.2,0.7,1 var i:integer;
begin
for i:=l to n do
StringGridl.Cells[0,i]:=IntToStr(i)+’ элемент’;
StringGridl.Cells[1,0]: = ' x’;
StringGridl.Cells[2,0]: = ' x’;
for i:=l to n-do begin
StringGridl.Cells[l,i]: =
FormatFloat(' StringGridl.Cells[2,i] : = FormatFloat(' 0.0000’, cos(x[i]));
end; end; end.
СТРОКИ
В Delphi существует 5 типов строк:
-
ShortString - короткая строка;
-
AnsiString - длинная строка;
-
WideString - длинная строка в кодировке UNICODE;
-
String - универсальная строка;
-
PChar - строка, оканчивающаяся нулевым кодом (#0), введена для со вместимости с другими языками программирования (такие строки исполь зуются в C++ и Windows).
Переменная PChar - это ссылка на строку. Строки типа PChar размещаются в динамической памяти. Динамическая память - это свободная память, которая остается после загрузки программ и данных. Программный элемент
71
получает ее в процессе выполнения программы, а не на этапе компиляцщ! (статическая память). Переменная типа PChar - это ячейка памяти, содержа! щая адрес строки. По этому адресу записываются необходимые данные. Компилятор выделяет под переменную PChar всего 4 байта, а сама строка. которая размещается по адресу, записанному в эти 4 байта, может быть любой длины. Если строки не существует, а переменная PChar объявлена, то J эту переменную необходимо записать nil (пустой адрес).
Переменные типа AnsiString содержат динамические строки символов в ANSI-кодировке. Соответственно переменные типа WideString содержат динамические строки символов в кодировке UNICODE. Термин "динамические" означает, что переменные указанных типов, как и тип PChar, являются] адресами, т.е. ссылками на память с соответствующим типом данных.
ShortString - это фактически массив: array [0. .255] of char. Память в данном случае выделяется в 256 байт, а строка размещается динамически, т.е. через адрес. Символы строки содержатся в байтах с первого по 255. В байте с номером 0 содержится символ, порядковый номер которого представляет собой число фактически имеющихся в строке символов. Данный тип ShortString введен для совместимости с более ранними версиями языка Pascal.
Строка String в зависимости от директивы компилятора {$Н} может совпадать с AnsiString ({$H+} установлено по умолчанию) или с ShortString({$H-}).
Для строки String можно задавать максимальное количество символов с помощью следующего объявления; var str: string{25] ;, т.е. строка str может содержать не более 25 символов и в памяти она занимает 26 байт (не считая "накладных расходов").
Доступ к строке может осуществляться посимвольно, так как все символы в строке проиндексированы. В строке PChar символы нумеруются начиная с 0, в остальных строках - начиная с 1. Например, пусть объявлено: Var strl: string; str2: PChar; и выполнены присваивания: I strl:=' Pascal' ; str2:= ' Pascal' ; тогда atr[l] представляет символ! ЧР', a str2 [1] -символ *а'.
Co строками возможны операции конкатенации (сложения) и сравнения. Складываются строки, используя знак '+'. При сравнении строк действия выполняются слева направо в соответствии с ANSI-кодами отдельных символов. Например, код А меньше, чем а. Если строки разной длины, то короткая строка дополняется справа, причем код, который участвует в дополнении строки, меньше кода любого символа, существующего в ANSI-кодировке.
Если в операциях участвуют строки разного типа, то очень часто необходимо явное преобразование типов.
Для выполнения различных операций над строками существует множество подпрограмм (табл. 11).
72
Таблица 11 |
|
Операшя |
Описание |
copy(S, Pos, len) |
Возвращает подстроку длиной len символов из строки S начиная с символа номер pos |
lenght(S) |
Возврашает фактическую (динамическую) длину строки S |
Pos(substr, S) |
Возвращает позицию первого вхождения подстроки substr в строку S |
SetLenght(S, newlen) |
Задает новую гитну newlen строке S |
StringOfChar(Ch, Count) |
Возвращает строку, заполненную символом Ch в количестве Count |
Trim(s) |
Возвращает строку без начальных и конечных пробелов |
UpperCase(S) |
Возвращает строку с прописными буквами |
ПРИМЕР ПРИЛОЖЕНИЯ 9
Провести исследование различных видов диалоговых окон вывода сообщений. Для отображения сообщений существует пять основных диалоговых окон.
ShowMessage отображает статические сообщения. Это диалоговое окно отображает в центре экрана строку текста и кнопку "ОК" (рис. 24). Вызывается посредством использования процедуры ShowMessage(S), где S - строка типа String.
Рис. 25
Ряс. 24
В отличие от предыдущих диалоговых окон, MessageBox (рис. 26) позволяет задавать две строки: заголовок окна и поясняющий текст. Программно вызов оформлен в виде функции. Эта функция возвращает то значение, на какой кнопке щелкнул пользователь. Число отображаемых кнопок может быть одна или более и задается с помощью аргумента, представляющего собой набор предопределенных констант. Передаваемые в функцию строки заголовка и текста должны иметь тип PChar. Если эти строки типа String, то необходимо использовать преобразование типов, записывая Р = =PChar(S), где Р типа PChar, a S - String
MessageDlg
(рис. 27) отличается от MessageBox
тем, что заголовок этого окна
предопределен.
Функция MessageDlg имеет 4 аргумента: первый передает текст в виде
строки типа String, второй - вариант заголовка, третий - какие кнопки будут отображаться, четвертый позволяет организовать связь с файлом подсказки Help.
Рис. 28
Как и в случае предыдущего окна, функция возвращает, на какой кнопке щелкнул пользователь. Окно MessageDlg располагается в центре экрана. MessageDlgFos (рис. 28) является вариантом MessageDlg с той лишь разницей, что этому виду диалогового окна необходимо передавать координаты X и Y его расположения на экране.
Форма примера 9 представлена на рис. 29.
Рис. 29
Для реализации локального меню выбора варианта диалогового окна использовался компонент TRadioGroup - группа взаимосвязанных переключателей TRadioButton.
С помощью свойства Items создается список взаимоисключающих альтернатив, в данном случае из пяти строк, для каждой из которых создаете* переключатель. При выборе мышью (или стрелками) того или иного переключателя в списке фиксируется строка и ее номер, который позволяет в
74
программе обеспечить выполнение того или иного кода. Выбранный номер чаписывается в свойстве Itemlndex. Нумерация переключателей задается от ля. Переключатели можно располагать не только в один, но и в несколько столбцов. Число столбцов задается в свойстве Columns. С помощью свойства Caption можно задавать заголовок всей группе взаимозависимых переключателей.
Строки меню заносятся в список. Вызывая в инспекторе объектов свойство Items, можно набрать пять строк, а значение Itemlndex установить, например, равным 3. Для данного компонента необходимо создать обрабочик OnCHck.
Текст программы приводится ниже. В данном примере имя формы (Name) выбрано MainForm, соответственно порождающий эту форму класс имеет имя TMainForm.
unit Prim9;
interface
uses SysUtils, Windows, Messages, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls, ExtCtrls, Buttons;
type TMainForm = class (TForm)
RadioGroupl: TRadioGroup; Bevell: TBevel; Label1: TLabel; BitBtnl: TBitBtn;
procedure RadioGrouplClick(Sender: TObject); end;
var MainForm: TMainForm; imp1ementation {$R *.DFM}
procedure TMainForm.RadioGrouplClick(Sender: TObject); const sde=’Демонстрация '; sbi='Было выбрано’; var TheText,TheCaption: String;
S: String[6]; W: Word; X, Y: Integer; begin
case RadioGroupl.Itemlndex of 0 : ShowMessage(sde+'ShowMessage'); 1:begin
X := 50; Y := 60;
ShowMessagePos(sde+'ShowMessagePos',X,Y); end; 2: begin
TheText := 'Текст-пояснение к MessageBox'; TheCaption :- sde+'MessageBox '; if Application.MessageBox(PChar(TheText), PChar(TheCaption),MB_DEFBUTTON1 +
75
MB_ICONEXCLAMATION + MB_OKCANCEL) = IDOK
then ShowMessage(sbi+'OK') else ShowMessage(sbi+'Cancel'); end; 3:begin
W := MessageDlg(sde+'MessageDlg'
[mbYes, mbNo, mblgnore],0); case W of
mrYes: S := 'Yes'; mrNo: S := 'No'; mrlgnore: S := 'Ignore1; . end; {case} ShowMessage(sbi + S); end; ;
4:begin
X := 50; Y := 75;
W := MessageDlgPos(sde+'MessageDlgPos', mtWarning,mbAbortRetryIgnore, 0, X, Y) ; case W of
mrAbort: S := 'Abort'; mrRetry: S := 'Retry'; mrlgnore: S := 'Ignore'; end; {case} ShowMessage(sbi + S) ; end;
end; {case} end; end.
В программе при объявлении строки s задана максимальная длина при-сваимого ей значения, равная 6 символам. Аргумент функции MessageDlg, заданный в квадратных скобках, означает, что с помощью конструктора множества передается некоторое заданное множество.
ЗАПИСИ (ОБЪЕДИНЕНИЯ)
С помощью зарезервированного слова "record" в единой структуре можно объединить данные разных типов. Общий синтаксис объявления такого объединения следующий:
Туре <имя типа> = Record <СПисок полей>: <тип>; <Список полей>:
End;.
Поля
записи (или объединения) могут быть
любого типа, число их не ограничено.
Например,
{Тип
комплексных чисел}
Complex = record
Re, Im: real;
end;
{Тип
- дата
рождения}
Year:word;
Month: 1..12;
{Тип
- сведения о сотруднике}
Name: string[40];
Age: word;
Adres: string[80]; end;.
Количество памяти, выделяемой под запись, может быть различным в зависимости от директивы {$А} (выравнивание). Если установлено {$А+}, то поля выравниваются по четным адресам - уменьшается время доступа к переменной в памяти. По умолчанию установлено {$А-}. Перед ключевым словом "record" можно добавить слово "Packed". В этом случае под запись выделяется минимальное количество байт, причем директива {$А} игнорируется.
После объявления типа можно объявить переменные или типизированные константы, например,
Var Z: Data;
X: Complex; Const
Birthday:Data=(Year:197 4;Month:7;Day: 12) ; Petrov:Person=(Name:'Иван';Age:22;
Adres:'Новомосковск,Мира,20,3');
Доступ к полям записи в программе осуществляется следующим способом:
2.Year:=1969; {Z - селектор записи; Year - поле}. Z.Month:=7; Z.Day:=13; X.Re: 0.8; X.Im: 2.1; Z.Month:= Z.Day div 5+2;
Тип данных запись может иметь так называемую вариантную часть. Вариантная часть позволяет трактовать по-разному занимаемую полями одну и ту же память.
Туре
pigure=(Square,Triangle,Circle);
e a Record
integer;
76
77
Year:=
1971; Month:=5; Day:=28;
god;
ПРИМЕР ПРИЛОЖЕНИЯ
10
Пусть требуется рассчитать
зарплату 3, премию П и итоговую сумму И
явум сотрудникам в соответствии с табл.
12.
Square: (Side: integer);
Triangle: (Sidel,Side2,Angle: integer);
Circle: (Radius: integer); end;
В данном случае задан перечисляемый тип для обозначения трех геомet рических фигур: квадрата, треугольника и окружности. Далее вводится о&ь единение: х, Y - координаты привязки этих фигур на некоторой плоскости Side (сторона) определяет квадрат, sidel, Side2, Angle (угол) определяю* треугольник, Radius - окружность. Начиная с ключевого слова case, запц, сывается вариантная часть. Память выделяется одна. Трактовать ее можно! данном случае так: в памяти находится или одна величина Side, или тря величины Sidel, Side2, Angle, или одна величина Radius. Когда и ка* трактовать память, выбирает программист.
Вариантная часть может быть только одна, и располагается она в конце записи. Синтаксически Pig есть параметр выбора (указывать его необяза. тельно). Чаще всего вариантную часть записывают так:
Case Figure of
Square: (Side: integer); Triangle: (Sidel,Side2,Angle: integer); Circle: (Radius: integer);.
Как замечено выше, память под вариантную часть выделяется одна и та же. В данном случае для Triangle требуется записать три величины типа integer, больше, чем для других фигур. Поэтому под вариантную часть будет выделено 12 байт памяти (по 4 байта на каждую величину).
Далее выберем две переменные и запишем данные в эти переменные:
Var MySquare: G; MyCircle: G;
…………………………
MySquare.Side:= 5; MyCircle.Radius: = 10;
Как можно заметить, отличий в записи информации в вариантные поля от обычных полей на этом уровне не существует. Если попытаться в примере выше прочитать значение MySquare. Side, то оно будет равно 10, так как последняя запись в общую память была именно такой (MyCircle.Radius: - 10;).