Пример работы с оператором with
Листинг 3.3 Пример работы с оператором with
type TDate = record // Объявляем новый тип - запись с тремя полями
Day: Integer; // Поле День Month: Integer; // Поле Месяц
Year: Integer; // Поле Год end;
var OrderDate: TDate; // Объявляем запись OrderDate begin with OrderDate do // Далее оперируем с записью OrderDate
if Month =12 then begin Month := 1;
Year := Year + 1;
end
else
Month := Month + 1; end;
Таким образом, при обращении к полям записи нам не нужно указывать имя самой записи.
Кроме обращения к полям записи, при помощи оператора доступа можно повысить удобство работы с объектами Kylix, которые мы рассмотрим во второй части книги.
Пример использования оператора case
Листинг 3.4. Пример использования оператора case
case I of // В зависимости от значения переменной I
1..5: С := 'До пяти'; // Если оно от 1 до 5, то переменная С='До пяти' 6..9: С := 'Выше пяти'; // Если оно от б до 9, то переменная С='Выше
// пяти' 0, 10..99: С := 'Вне области допустимых значений'; // Если оно равно 0
// или от 10 до 99, то С='Вне области допустимых значений' else
С := ''; // Иначе, если ни одно из условий не выполняется,
//С равно пустой строке end;
Таким образом, мы с помощью одного оператора case охватили множество значений. Более того, код программы читается довольно легко. Посмотрим, что было бы, если бы для той же самой задачи мы использовали оператор условия (листинг 3.5).
Пример использования оператора условия
Листинг 3.5. Пример использования оператора условия
if I in [1..5] then С := 'До пяти' else if I in [6..10] then С := 'Выше пяти'
else if (I = 0) or (I in [10..99]) then С := 'Вне области допустимых значений' else
С := ";
На листинге 3.5 получилась довольно тяжело читаемая конструкция.
Операторы цикла
Иногда необходимо, чтобы какая-либо часть программы выполнялась несколько раз. Для этого во всех языках программирования, в том числе и в языке Object Pascal, используются циклы.
Цикл — это последовательность операторов, команд, которая выполняется более одного раза, т. е. повторяется. Такие операторы и команды называют телом цикла.
В языке Object Pascal имеются три вида операторов цикла:
цикл с параметром; цикл с предусловием; цикл с постусловием. Каждый из этих видов циклов удобно применять в определенных случаях, хотя с помощью любого из них можно обходиться практически в любом случае.
В тело цикла допускается помещать оператор безусловного перехода goto. Кроме того, для досрочного прерывания выполнения цикла можно использовать специальную процедуру break. Вызов этой процедуры приводит к прекращению выполнения операторов тела цикла и переходу к выполнению операторов, расположенных сразу за циклом. Вы можете досрочно завершить выполнение данного повторения цикла при помощи вызова процедуры continue. Ее вызов приводит к передаче управления сразу в конец цикла, т. е. досрочному завершению данного повторения.
Операторы циклов допускают множественные вложения друг в друга. При вложении сначала выполняются внутренние операторы цикла, а затем — внешние. Далее мы приведем примеры вложений операторов цикла друг в друга.
Цикл с параметром
Цикл с параметром применяется в том случае, когда заранее известно, сколько раз он должен выполниться. Данный цикл выглядит следующим образом:
For параметр:=нач.значение to кон.значение do оператор;
или
For параметр:=нач.значение downto кон.значение do оператор;
Параметр цикла — это переменная порядкового типа, которая объявлена в разделе объявления переменных.
Начальное значение — это значение, которое принимает параметр цикла. Естественно, что данное значение должно быть того же типа, что и переменная параметра цикла.
Конечное значение — это значение, которое может принимать параметр цикла.
Оператор — это одиночный или составной оператор, который и представляет собой тело цикла.
Внимание
Тело цикла не должно изменять параметр цикла, т. к. это может привести к непредсказуемым последствиям. В частности, к бесконечному циклу (зацикливанию программы).
И первый и второй варианты написания цикла изменяют параметр цикла на единицу. В первом случае (for ... to) происходит увеличение параметра на единицу при каждом проходе цикла, во втором случае (for ... downto) — уменьшение параметра цикла на единицу.
Итак, цикл с параметром выполняется несколько раз, постепенно увеличивая или уменьшая значение параметра: до тех пор, пока это значение не достигнет конечного значения.
Примечание
Цикл не выполняется ни разу, если для первого варианта цикла начальное значение параметра больше конечного, а для второго варианта — конечное значение больше начального.
Приведем несколько примеров циклов с параметрами (листинг 3.6).
Примеры циклов с параметрами
Листинг 3.6. Примеры циклов с параметрами
for i:=l to 20 do // Начало цикла
begin // Начало составного оператора
s:=s+i; // Тело цикла
a:=a*i;
end; // Конец цикла. Значение i увеличивается на 1 for i:=l to 10 do // Начало внешнего цикла begin // Начало составного оператора
for j:=10 downto 1 do // Начало внутреннего цикла begin
s:=s+j; // Тело внутреннего цикла а:=s+а;
end; // Конец внутреннего цикла. i уменьшается на 1
a:=a*s; end; // Конец внешнего цикла. i увеличивается на 1
Цикл с предусловием
Цикл с предусловием применяется в том случае, если число повторений заранее неизвестно и если при некоторых условиях тело цикла может не выполняться совсем. Данный цикл выглядит следующим образом:
while условие do оператор;
Условие представляет собой логическое выражение, которое может быть ложным или истинным.
Оператор — это тело цикла. Он может быть простым или составным.
Данный Цикл выполняется в том случае, когда условие имеет значение True. Как только условие примет значение False, цикл выполняться не будет.
Переменные, входящие в условие цикла, могут быть произвольными (не обязательно порядковыми).
Пример оператора цикла с предусловием представлен ниже (листинг 3.7).
Пример цикла с предусловием
Листинг 3.7, Пример цикла с предусловием
while I >
0 do // Начало цикла
begin // Начало составного оператора
S : = S+I; // Тело цикла
I := I - 1; // Изменяем переменную i самостоятельно end; // Конец цикла. Переменная i не изменяется
Примечание
В отличие от цикла с параметром, при использовании других видов циклов следите за тем, чтобы условие цикла когда-нибудь изменилось. Для этого нужно изменять переменные, входящие в условие цикла в теле цикла.
Данный цикл не выполняется совсем, если при первоначальной проверке условия оно имеет значение False.
Цикл с постусловием
Цикл с постусловием используется в случае, когда желательно, чтобы тело цикла выполнилось хотя бы один раз, а общее количество повторений цикла заранее неизвестно.
Данный цикл имеет следующий вид:
repeat
оператор1;
...
операторN; until условие;
Операторы, расположенные между словами repeat и until, представляют собой тело цикла. Условие — это логическое выражение.
Операторы цикла выполняются, по крайней мере, один раз, а затем происходит проверка истинности условия. Если условие является ложным (False), то операторы цикла выполняются повторно. Цикл будет выполняться до тех пор, пока условие цикла не станет истинным (True).
Рассмотрим пример применения цикла с постусловием (листинг 3.8).
Пример цикла с постусловием
Листинг 3.8. Пример цикла с постусловием
repeat // Начало цикла
К : = I mod J; // Тело цикла I : = J;
J : = К; until J = 0; // Условие цикла
Описание функции Mах
Листинг 4.1. Описание функции Mах
function Max(A: array of Real; N: Integer): Real; var
X: Real;
I: Integer; begin
X := A[0]; for I := 1 to N - 1 do
if X < A[I] then X : = A[ I ];
Max := X; end;
Вызов данной функции может выглядеть так:
М : = Мах(В, 12) ;
При этом переменная м должна иметь тип Real, массив в — тоже Real, a вторым параметром должно быть целое число (в нашем примере 12). Таким образом, вызов данной функции при этих параметрах поместит в переменную м самое большое значение из всех, хранящихся в элементах одномерного 12-элементного массива B.
Описание процедуры NumString
Листинг 4.2. Описание процедуры NumString
procedure NumString(N: Integer; var S: string);
var
V: Integer; begin V := Abs(N) ;
S : = " ;
repeat
S := Chr(V mod 10 + Ord('0')) + S; V := V div 10;
until V = 0;
if N < 0 then S := '-' + S; end;
Для вызова данной процедуры можно в любом месте основной программы поступить следующим образом:
NumString(17, MyString);
В результате выполнения данного оператора, который называется оператором вызова процедуры, в строковую переменную с именем MyString будет помещено значение "17".
Описание свойств объекта
Листинг 5.1. Описание свойств объекта
type TMyObject = class // Объявление нового класса private
FInt: integer; // Объявление целочисленного поля FReal: real; // Объявление вещественного поля FChar: char; // Объявление поля символьного типа published
property Prop1: integer read FInt write FInt; // Объявление // свойства Prop1, с помощью которого можно читать значение поля // FInt и записывать данные в это же поле
property Prop2: real read FRea1; // Свойство Ргор2 предназначено // только для чтения значения поля FReal
property РrорЗ: char write FChar; // Свойство Рrор3 предназначено // только для записи данных в поле FChar end;
После такого объявления программист получает доступ к полям объекта через три свойства Prop1, Prop2 и Рrор3.
Листинг 7.1. Область видимости объекта Form1
procedure TForml.ButtonlClick (Sender: TObject);
begin
Color := clGray; // Задаем цвет формы Caption := 'Форма с одной кнопкой'; // Изменяем заголовок формы Button1.Caption := 'OK'; // Изменяем заголовок кнопки end;
Итак, на приведенном выше листинге изменим значения свойств формы Form1 без указания имени формы, т. к. данная часть программного кода является областью видимости для формы Form1. Метод Button1Click является частью объекта Form1.
Две строки
Color := clGray; // Задаем цвет формы
Caption := 'Форма с одной кнопкой'; // Изменяем заголовок формы
будут равносильны строкам
Form1.Color := clGray; // Задаем цвет формы
Form1.Caption := 'Форма с одной кнопкой'; // Изменяем заголовок формы
Последняя строка листинга 7.1 изменяет значение свойства другого компонента (Button1), поэтому нуждается в указании его имени.
Освобождение ресурсов графической подсистемы
Листинг 8.1. Освобождение ресурсов графической подсистемы
// загрузка картинки в Bitmap1
Bitmap1. LoadFromFile ('mypicture.bmp') ;
//копирование в Bitmap2 из Bitmap1
Bitmap2.Assign (Bitmap1);
// применение метода Dormant и освобождение ресурсов графической подсистемы
Bitmap2.Dormant;
Image1.Canvas.Draw (10, 10, Image2.Picture.Bitmap);
Таким образом, в координаты (10,10) канвы картинки Image1 будет занесен рисунок из канвы картинки Image2.Метод DrawFocusRect применяется для рисования прямоугольника с помощью булевой операции XOR. То есть повторное рисование такого же прямоугольника на том же месте удалит этот прямоугольник. Пример:
Image1.Canvas.DrawFocusRect (Rect (0,0,30,30);
Метод Ellipse применяется для рисования окружности или эллипса. Параметры — точки (X1, Y1) и (X2, Y2), определяющие прямоугольник, в который вписан эллипс.Метод Error вызывается при необходимости генерации исключения при работе с объектом типа TList. Вызов данного метода дает лучший результат по сравнению с командой Raise. Примером вызова этого метода может служить следующая строка:
List.Error ('Ошибка в элементе %u списка List', I);
Выполнение данной строки вызовет сообщение об ошибке в какой-либо строке списка.Метод Exchange предназначен для обмена местами двух элементов списка. Позиции этих двух элементов задаются параметрами Index1 и Index2.
Примечаниe
Не применяйте метод Exchange для отсортированных списков— это может нарушить упорядоченность списков.
Метод FillRect применяется для заполнения указанного прямоугольника канвы цветом, определенным значением свойства Brush. Например, приведенный ниже код заполняет всю область канвы компонента Image1 фоновым цветом, определенным свойством Brush:
with Image1.Canvas do
FillRect (Rect (0, 0, Width, Height) );
Метод FindNextControl применяется для определения следующего за указанным в параметре CurControl дочернего оконного компонента, соответствующего последовательности табуляции. Если в качестве параметра выступает не дочерний элемент данного оконного компонента, то метод возвращает первый в последовательности табуляции компонент. Второй параметр GoForward определяет направление поиска компонента. Если данный параметр имеет значение true, то ищется следующий компонент, иначе — предыдущий. Следующий параметр CheckTabStop — определяет,
будут ли при поиске учитываться компоненты, в которых свойство TabStop установлено в false. Если значение данного параметра равно true, то такие компоненты не учитываются, иначе — учитываются. Последний параметр CheckParent применяется для того, чтобы указывать, учитывать ли при поиске только те компоненты, которые являются прямыми потомками данного оконного компонента. Если данный параметр равен false, то просматриваются все компоненты, иначе — только прямые потомки.Метод First возвращает первый элемент списка типа TList.Метод FloodFill применяется для закрашивания замкнутой области канвы произвольной формы каким-либо цветом. В качестве параметров данного метода выступают: начальная точка закрашивания, цвет и стиль заполнения. Начальная точка закрашивания (X, Y) должна находиться внутри закрашиваемой области. Два других параметра применяются для задания границы этой области. Параметр color применяется для указания цвета, который является границей закрашивания. Параметр FillStyle может иметь два значения. Если он равен fsSurface, то происходит закрашивание именно той области, которая окрашена цветом color, а на других цветах закрашивание не происходит. Если же параметр FillStyle имеет значение fsBorder, то заполняется область, в которой могут присутствовать любые цвета, кроме color, который является цветом границы закрашивания.Метод Focused применяется для определения, является ли в настоящий момент времени данный оконный компонент активным. Данный метод возвращает значение true, если фокус принадлежит данному оконному компоненту, иначе — false.Метод FrameRect применяется для рисования на канве прямоугольной рамки. Данный метод использует установки текущей кисти (Brush). Толщина рамки равна одному пикселу. Внутренняя часть рамки не заполняется никаким цветом. В качестве примера приведем код, который рисует на канве компонента Image1 красную прямоугольную рамку:
with Image1.Canvas do begin Brush.Color := clRed; FrameRect ( Rect (10,10,150,100) );
end; Метод Free применяется для вызова деструктора объекта. Данный метод проверяет, не была ли уже ранее высвобождена память, предназначенная для данного объекта, после чего вызывает метод Destroy.Метод GetTabOrderList предназначен для построения списка типа TList дочерних оконных компонентов, расположенных в последовательности табуляции. Свойство TabStop во внимание не принимается. В список входят как прямые, так и косвенные потомки данного оконного компонента.Метод HandleAllocated предназначен для проверки наличия дескриптора окна у данного компонента. В случае, если дескриптор, окна есть, метод возвращает значение true. Данный метод удобно применять, если нет необходимости создавать дескриптор окна компоненту, у которого его нет. Непосредственная проверка свойства Handle компонента приводит к созданию дескриптора окна.Метод HandleNeeded применяется для создания дескриптора окна для компонента, у которого его не было. При работе настоящий метод вызывает сначала метод CreateHandle у родительского компонента, а затем создает дескриптор для данного компонента.Метод Hide применяется для того, чтобы сделать компонент невидимым. Вызов данного метода эквивалентен команде
Component.Visible := false;
Если данный компонент является оконным и содержит в себе другие компоненты, то эти компоненты также становятся невидимыми.
Примечание
Обратите внимание на тот факт, что хотя компонент является невидимым, все его свойства и методы являются доступными.
Метод Insert предназначен для вставки нового элемента списка в заданную позицию. Единственный параметр данного метода Index показывает, в какую именно позицию будет вставлен новый элемент списка. При вставке нового элемента все последующие элементы сдвигаются (их индексы увеличиваются на единицу). В случае, если происходит попытка вставить новый элемент в отсортированный список, генерируется исключение EListError. Тогда лучше использовать метод Add.Метод Invalidate используется для полной перерисовки компонента. Применяется, когда с компонентом произошли какие-либо визуальные изменения.
Метод Last возвращает значение, равное последнему указателю списка типа Tlist и значению Count -1.
Метод LineTo применяется для рисования на канве объекта прямой линии. Начало линии совпадает с текущим значением координат пера (PenPos) и заканчивается в точке с координатами (X, Y), за исключением самой точки, которые передаются в качестве параметров метода.
Метод LoadFromClipboardFormat применяется для загрузки изображения в графический компонент из буфера обмена.
Метод LoadFromFile предназначен для загрузки изображения в графический компонент из файла, задаваемого параметром FileName. Если данный графический файл по каким-либо причинам не может быть загружен (несоответствие типов, незарегистрированный графический формат файла), то генерируется исключение EInvalidGraphic.
Метод LoadFromStream позволяет загружать графическое изображение из потока, задаваемого параметром Stream. Данный метод может использоваться при загрузке, например, графических полей в наборе данных из объекта типа TBlobStream.
Метод Lock применяется для блокировки канвы компонента и запрета рисования на ней из других потоков многопоточного приложения. Обратный результат достигается при помощи метода unlock. При многократном вызове метода Lock будет увеличиваться свойство LockCount, в котором фиксируется количество блокировок. Канва будет недоступной из других потоков, пока не снимется последняя блокировка. Если вы не хотите использовать многократную блокировку, можно воспользоваться методом TryLock. После блокирования канвы общая производительность приложения может существенно снизиться.
Метод Mask применяется для преобразования цветного изображения в черно-белую маску. В результате замены цвет TransparentColor переходит в белый, а все остальные цвета — в черный.
Метод Move предназначен для перемещения элемента списка, находящегося в позиции, задаваемой параметром CurIndex, в позицию, задаваемую параметром NewIndex.
Метод MoveToприменяется для изменения текущей позиции пера (PenPos) в заданную параметрами (X, Y). При перемещении пера на канве ничего не рисуется. Данный метод аналогичен прямой установке координат пера в свойстве PenPos.
Метод OpenBit предназначен для возврата индекса первого элемента массива типа TBits, имеющего значение false.
Метод Pack предназначен для удаления из списка типа TList всех элементов, значение которых равно nil. После удаления происходит переиндексация всех элементов списка.
Метод Pie рисует замкнутый сегмент окружности или эллипса. Параметры данного метода аналогичны параметрам метода Arc. В результате выполнения данного метода может получиться рисунок, похожий на Рисунок 8.15.
Метод Polygon рисует на канве многоугольник по заданному множеству точек, определенных массивом Points, причем первая точка соединяется с последней, после чего многоугольник закрашивается цветом, определенным свойством кисти Brush.
Например:
Image1.Canvas.Polygon ( [ Point (10, 10), Point (30,10),
Point (130, 30), Point (240, 120) ] );
Вышеприведенный код рисует на канве компонента Image1 закрашенный четырехугольник, координаты которого заданы непосредственно.
Обработка события OnDragOver
Листинг 8.2.Обработка события OnDragOver
procedure TForm1.ListBox2DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
begin
Accept := Source is TListBox; end;
В данном обработчике мы указываем, что на компонент ListBox2 можно перетаскивать компоненты типа TListBox. Затем в обработчике события OnDragDrop запишем следующий код (листинг 8.3).
Код обработки OnDragOver
Листинг 8.3. Код обработки OnDragOver
procedure TForm1.ListBox2DragDrop(Sender, Source: TObject; X, Y: Integer);
begin
ListBox2. Items .Add (ListBox1. Items[ListBox1. ItemIndex]);
end;
Таким образом, мы добавляем выбранную строку компонента ListBox1 в компонент ListBox2.
Все! Можно запускать приложение при помощи клавиши <F9>
. Попробуйте перетащить любую строку из первого списка, во второй.
Oбработчик события OnEndDrag
Листинг 8.4.Oбработчик события OnEndDrag
procedure TForm1.Component1EndDrag (Sender,
Target: TObject; X, Y: Integer);
begin
If Target = Nil then ShowMessage ('Перенесение объекта '+
(Sender as TControl).Name + ' завершалось неудачно') else
ShowMessage((Sender as TControl).Name + ' перенесен в '
+ (Target as TControl).Name);
end;
Добавим код, записанный в листинге 8.3, в вышеописанное приложение. При этом код нужно поместить в обработчике события OnEndDrag для первого списка (ListBox1). В результате, при каждом успешном перетаскивании строки из первого списка во второй будет выдаваться окно-сообщение (Рисунок 8.18), а при неудачном — окно-сообщение, изображенное на рис, 8.19.
Синтаксис конструкции try except try
Листинг 9.1. Синтаксис конструкции try...except try
// здесь находятся операторы защищенного кода
except
on Exception1 do // операторы, выполняемые в случае
// возникновения ошибки 1
on Exception2 do // операторы, выполняемые в случае // возникновения ошибки 2
. . . else
// операторы, выполняемые в случае возникновения ошибки, не являющейся ни ошибкой 1
//ни ошибкой 2 end;
Таким образом, вы размещаете "опасный" участок кода после слова try, и если при выполнении этого кода произойдет исключительная ситуация, оно прекратится и начнут выполняться команды, расположенные после слова except.
В разделе except могут находиться или только операторы обработки исключений, которые начинаются со слова-приставки on, или только произвольные операторы, не являющиеся операторами обработки исключений. В вышеприведенном листинге представлена ситуация, когда в разделе except находятся только операторы обработки исключений. Если в блоке операторов, расположенных после слова try, произошла ошибка Exception1, то будут выполнены только те команды, которые расположены после слов on Exception1 do. Далее объект исключения уничтожается и программа продолжает выполнять операторы, расположенные после слова end; рассматриваемой конструкции.
Раздел после слова else является необязательным и может отсутствовать. Он предназначен для обработки любых других исключений, не предусмотренных в разделе except. Если же раздел else отсутствует, но в защищенном коде произошла исключительная ситуация, не предусмотренная ни одним обработчиком исключений on Exception do, то произойдет стандартная (определенная операционной системой) обработка данной исключительной ситуации с появлением соответствующего информационного окна с сообщением об ошибке.
Рассмотрим оператор обработки исключений более подробно. Как видно из листинга 9.1, данный оператор может присутствовать внутри раздела except или принимать одну из двух форм:
on <класс исключения>
do <оператор>
;
или
on <имя>
: <класс исключения>
do // операторы, в которых можно использовать свойства исключения
В листинге 9.1 мы привели только первую форму представления оператора. Но, так как исключение является объектом, то было бы иногда очень удобно обратиться к его свойствам. Однако для того, чтобы обращаться к свойствам какого-либо объекта, необходимо знать его имя. Вторая форма оператора обработки исключений применяется именно тогда, когда нам нужно обратиться к свойствам возникшего исключения. Для этого исключению присваивается временное имя <имя>
и к его свойствам можно обращаться через точку:
<имя>
.<свойство>
В листинге 9.2 приведена та же конструкция, что и в листинге 9.1, только в блоке except нет операторов обработки исключений. Таким образом, при возникновении любой исключительной ситуации в защищенном блоке будут выполняться операторы, расположенные после слова except.
Конструкция try except без операторов обработки исключений
Листинг 9.2. Конструкция try...except без операторов обработки исключений
try
// здесь находятся операторы защищенного кода
except
Operator1; // операторы, выполняемые в случае
Operator2; // возникновения любой исключительной ситуации, Operator3; // возникшей в защищенной области
...
end;
Приведем небольшие примеры использования защищенных блоков программы. В листинге 9.3 представлен пример обработки исключительной ситуации деления на ноль.
Обработка деления на ноль
Листинг 9.3.Обработка деления на ноль
try
а:=8;
b:=0;
с:=а/b; except
on EZeroDivide do MessageBox{'Внимание! Деление на ноль!') end;
При выполнении данного кода будет сгенерирована исключительная ситуация, принадлежащая к классу EZeroDivide (деление целых чисел на ноль). Данная исключительная ситуация обработается в секции except и приложение выдаст на экран окно с сообщением Внимание! Деление на ноль! (Рисунок 9.1).
Использование временного имени объекта ислючения
Листинг 9.4. Использование временного имени объекта ислючения
try
ScrollBar1.Max:=ScrollBar.Min-1; except
on E: EInvalidOperation do
MessageDlg('Произошло исключение: '+Е.Message, mtlnformation, [mbOK],0)
end;
В защищенном блоке кода программы будет осуществлена недопустимая для объекта ScrollBox1 операция присвоения максимального значения списка меньшего, чем минимальное значение. Возникнет исключение класса EInvalidOperation. Таким образом, мы присваиваем объекту исключения, принадлежащего к классу EinvalidOperation, временное имя Е, после чего можем обращаться к свойствам объекта исключения Е. Мы самостоятельно выводим в окне сообщения текст ошибки Е.Message, который выдается по умолчанию (в том случае, если бы нашего обработчика исключения не было). Результат работы кода листинга 9.4. представлен на Рисунок 9.2.
Регенерация исключения
Листинг 9.5.Регенерация исключения
try
{ операторы } except
on <класс исключения>
do begin
{операторы обработки исключения} raise; // Регенерация исключения end; end;
После выполнения операторов обработки исключения, написанных программистом, выполняется команда raise, которая снова принудительно вызывает это исключение, после чего управление передается стандартному обработчику исключений.
В случае, если исключение успешно проходит через все блоки try в коде приложения, вызывается метод HandleException. Он показывает диалоговое окно ошибки. Вы можете вызвать этот метод так, как показано в листинге 9.6.
Вызов метода HandleException
Листинг 9.6.Вызов метода HandleException
try { операторы } except
Application,HandleException(Self);
end;
Теперь рассмотрим конструкцию, предназначенную для защиты ресурсов приложения.
Конструкция try ... finally служит для защиты кода, записанного в разделе finally от исключительных ситуаций, которые в силу каких-либо причин могут происходить в разделе try. Синтаксис этой конструкции представлен в листинге 9.7.
Конструкция try finally
Листинг 9.7.Конструкция try...finally
try
{операторы, способные создать исключительную ситуацию}; finally
{защищенные операторы, выполняемые в любом случае}; end;
Таким образом, операторы, которые размещены после ключевого слова finally, будут выполняться в любом случае, независимо от того, была сгенерирована исключительная ситуация или нет.
Если в разделе try была сгенерирована исключительная ситуация, то управление немедленно передается разделу finally. Если исключительной ситуации в разделе try не было, блок finally все равно будет выполняться. Даже если в разделе finally произойдет ошибка, выполнение операторов этого раздела будет продолжено до конца без выдачи сведений об ошибке.
В конструкции try . . . finally не происходит обработки исключений, она используется в основном для освобождения ресурсов памяти. Таким образом, в данной конструкции нуждаются операции с файлами, памятью, ресурсами операционной системы и объектами.
Код обработки исключения можно разбить на блоки try . . . except . . . end и try . . . finally . . . end. Эти блоки могут быть вложенными (Рисунок 9.3).
Генерация молчаливого исключения
Листинг 9.8. Генерация молчаливого исключения
procedure TForm1.Button1Click(Sender: TObject);
var
I: Integer; begin for I := 1 to 10 do {цикл 10 paз} begin
ListBox1.Items.Add(IntToStr(I));
{добавляем номер в список} if I = 7 then Abort; {прерываем добавление номеров в список после
добавления седьмого номера} end; end;
Запустим программу. В результате работы программы, после нажатия кнопки Button1, в список будет добавлено семь строк с номерами от 1 до 7 (Рисунок 9.5).
Если нажать кнопку несколько раз, то в список будут добавлены новые строки с номерами от 1 до 7 после имеющихся (Рисунок 9.6).
Объявление интерфейса
Листинг 10.1.Объявление интерфейса
type
IEdit = interface
procedure Copy; stdcall; procedure Cut; stdcall; procedure Paste; stdcall; function Undo: Boolean; stdcall; end;
Примечание
Тем читателям, которые имеют слабое представление о создании компонентов и новых классов, советуем прочитать пятую часть книги, посвященную созданию собственных компонентов и модификации уже существующих.
Нельзя создать экземпляр интерфейса при помощи интерфейса. Для получения экземпляра интерфейса вам нужно объявить его в классе, содержащем данный интерфейс. Таким образом, нужно определить класс, который содержит необходимый интерфейс в списке своих родителей (листинг 10.2).
Объявление класса содержащего интерфейс
Листинг 10.2.Объявление класса, содержащего интерфейс
TEditor = class(TInterfacedObject, IEdit)
procedure Copy; stdcall;
procedure Cut; stdcall; procedure Paste; stdcall;
function Undo: Boolean; stdcall; end;
Как уже было отмечено выше, использование интерфейсов позволяет нескольким классам общаться с помощью общего интерфейса. При этом не обязательно наличие одного базового класса-предка. Следует помнить, что интерфейс — это тип с управляемым временем жизни, т. е. он автоматически при инициализации принимает значение nil, обладает счетчиком ссылок и автоматически уничтожается при выходе за пределы своей области видимости.
Описание базового интерфейса IUnknown
Листинг 10.3.Описание базового интерфейса IUnknown
type
IUnknown = interface
[ '{ 00000000-0000-0000-C000-000000000046} ' ]
function QueryInterface(const IID: TGUID; out Obj): Integer; stdcall;
function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; end;
Синтаксис описания интерфейса похож на описание класса. Главное отличие заключается в том, что интерфейс может быть связан с глобальным уникальным идентификатором (Global Unique Identifier, GUID).
GUID — это 128-разрядное целое число, которое используется для уникальной идентификации интерфейсов. Так как в 128-ми разрядах можно закодировать большое количество чисел, GUID гарантирует глобальную уникальность идентификатора интерфейса. То есть, практически невозможно, чтобы на двух компьютерах GUID совпал. Алгоритм генерации GUID основан на аппаратной части компьютера (частота процессора, номер сетевой карты и т. д.). В результате работы алгоритма, который может быть реализован с помощью функции API CoCreateGUID( ), получается запись типа TGUID. Эту запись можно определить в виде строки следующего формата:
'{хххххххх-хххх-хххх-хххх-хххххххххххх}'
Для создания нового GUID в среде Kylix достаточно нажать комбинацию клавиш <Ctrl>
+<Shift>
+<G>
при работе редактора кода.
Итак, интерфейс IUnknown поддерживает три метода, которые наследуются всеми интерфейсами:
_AddRef ( ) — используется, когда получен указатель на данный интерфейс, и вы хотите использовать этот указатель. Метод _AddRef ( ) обязательно должен заканчиваться вызовом метода _Release ( ).
_Release ( ) — используется для завершения работы с интерфейсом.
Определение класса TInterfacedObject
Листинг 10.4. Определение класса TInterfacedObject
type
TInterfacedObject = class (TObject, IInterface) protected
FRefCount: Integer;
function QueryInterface(const IID: TGUID; out Obj) : HResult; stdcall;
function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; public
procedure AfterConstruction; override; procedure BeforeDestruction; override; class function NewInstance: TObject; override; property RefCount: Integer read FRefCount; end;
Как вы видите, данный класс в качестве родителей имеет класс TObject и интерфейс IInterface. Класс TInterfacedObject позволяет достаточно легко создавать классы, поддерживающие интерфейсы. Например,
type
TMyObjInterfaced = class(TInterfacedObject, IPaint)
end;
На вышеприведенном примере мы определяем новый класс TMyObjInterfaced, который является прямым потомком класса TInterfacedObject и поддерживает некий интерфейс IPaint.
Использование ключевого слова implements
Листинг 10.5. Использование ключевого слова implements
unit cadapt; type
IRGB8bit = interface
['{1d76360a-f4f5-lldl-87d4-00c04fbl7199}']
function Red: Byte;
function Green: Byte;
function Blue: Byte; end;
IColorRef = interface
['{ld76360b-f4f5-11dl-87d4-00c04fbl7199}']
function Color: Integer; end;
TRGB8ColorRefAdapter = class(TInterfacedQbject, IRGB8bit, IColorRef) private
FRGB8bit: IRGB8bit;
FPalRelative: Boolean; public
constructor Create(rgb: IRGB8bit);
property RGB8Intf: IRGB8bit read FRGB8bit implements IRGB8bit;
property PalRelative: Boolean read FPalRelative write FPalRelative; function Color: Integer; end; implementation
constructor TRGB8ColorRefAdapter.Create(rgb: IRGB8bit);
begin
FRGB8bit := rgb; end;
function TRGB8ColorRefAdapter.Color: Integer; begin
if FPalRelative then
Result := PaletteRGB(RGB8Intf.Red, RGB8Intf.Green, RGB8Intf.Blue) else Result := RGB(RGB8Intf,Red, RGB8Intf.Green, RGB8Intf.Blue);
end; end.
Код автоматически создаваемой для MDIприложения
Листинг 10.6.Код,автоматически создаваемой для MDI-приложения
unit clxmain;
interface
uses SysUtils, Classes, QForms, OImgList , QStdActns, QActnList , QDialogs, QMenus, QTypes, QComCtrls, QControls, QExtCtrls;
type
TMainForm - class(TForm) MainMenu1: TMainMenu; File1: TMenuItem; FileNewItem: TMenuItem; FileOpenItem; TMenuItem; FileCloseItem: TMenuItem; Window1: TMenuItem; Help1: TMenuItem; N1: TMenuItem; FileExitItem: TMenuItem; WindowCascadeItem: TMenuItem; WindowTileItem: TMenuItem; HelpAboutItem: TMenuItem; OpenDialog: TOpenDialog; FileSaveItem: TMenuItem; FileSaveAsItem: TMenuItem; Edit1: TMenuItem; CutItem: TMenuItem; CopyItem: TMenuItem; PasteItem: TMenuItem;
WindowMinimizeItem: TMenuItem; StatusBar: TStatusBar; ActionList1: TActionList; EditCut1: TEditCut; EditCopy1: TEditCopy; EditPaste1: TEditPaste; FileNew1: TAction; FileSave1: TAction; FileExit1: TAction; FileOpen1: TAction; FileSaveAs1: TAction; WindowCascade1: TWindowCascade; WindowMinimizeAll1: TWindowMiniraizeAll; HelpAbout1: TAction; FileClose1: TWindowClose; WindowTileItem2: TMenuItem; ToolBar2: TToolBar; ToolButton1: TToolButton; ToolButton2: TToolButton; ToolButton3: TToolButton; ToolButton4: TToolButton; ToolButton5: TToolButton; ToolButton6: TToolButton; ToolButton9: TToolButton; ToolButton7: TToolButton; ToolButton8: TToolButtun; ToolButton10: TToolButton; ToolButton11: TToolButton; WindowClose1: TWindowClose; WindowTile1: TWindowTile; ToolButton12: TToolButton; ImageList1: TImageList;
procedure FileNew1Execute(Sender: TObject);
procedure FileOpen1Execute(Sender: TObject);
procedure HelpAbout1Execute(Sender: TObject);
procedure FileExit1Execute(Sender: TObject);
private
{ Private declarations}
procedure CreateMDIChild(const Name: string);
public
{ Public declarations } end;
var
MainForm: TMainForm; implementation
{$R *.xfm}
uses clxchildwin, clxabout;
procedure TMainForm.CreateMDIChild(const Name: string);
var
Child: TMDIChild; begin { создание нового дочернего MDI-окна },
Child := TMDIChild.Create(Application);
Child.Caption := Name;
if FileExists(Name) then Child.Memo1.Lines.LoadFromFile(Name);
end;
procedure TMainForm.FileNew1Execute(Sender: TObject);
begin
CreateMDIChild('NONAME' + IntToStr(MDIChildCount + 1));
end;
procedure TMainForm.FileOpen1Execute(Sender: TObject);
begin
if OpenDialog.Execute then
CreateMDIChild(OpenDialog.FileName);
end;
procedure TMainForm.HelpAbout1Execute(Sender: TObject);
begin
AboutBox.ShowModal; end;
procedure TMainForm.FileExit1Execute (Sender: TObject);
begin
Close; end; end.
Заготовка для консольного приложения
Листинг 10.7. Заготовка для консольного приложения
program Project1;
{$APPTYPE CONSOLE} // Директива компилятора, означающая, что приложение // будет консольным
begin end.
Формы в консольных приложениях отсутствуют.
Консольные приложения пишутся на языке Object Pascal. Создание таких приложений практически не отличается от создания программ на языке Pascal под DOS.
Список сетевых услуг содержащийся в файле services
Листинг 11.1.Список сетевых услуг,содержащийся в файле services
# /etc/services:
# $Id: services,v 1.4 2000/05/15 15:54:48 chmouel Exp $
#
# Сетевые услуги Интернет
#
# номера портов как для TCP, так и для UDP; большинство портов используют
# оба эти протокола.
# Обновлено RFC 1700, ``Ассоциированные номера" (Октябрь 1994).
# Не все порты включены в список, только наиболее используемые.
tcpmux 1/tcp
echo 7/tcp
echo 7/udp
discard 9/tcp sink null
discard 9/udp sink null
systat 11/tcp users
daytime 13/tcp
daytime 13/udp
netstat 15/tcp
qotd 17/tcp quote
msp 18/tcp # протокол отправки сообщений
msp 18/udp # протокол отправки сообщений
chargen 19/tcp ttytst source
chargen 19/udp ttytst source
ftp-data 20/tcp
ftp 21/tcp
fsp 21/udp fspd
ssh 22/tcp # SSH удаленный протокол авторизации
ssh 22/udp # SSH удаленный протокол авторизации
telnet 23/tcp
# 24 - для частного использования smtp 25/tcp mail
# 26 - не назначен
time 37/tcp timserver
time 37/udp timserver
rlp 39/udp resource # расположение ресурсов
nameserver 42/tcp name # IEN 116
whois 43/tcp nicname
re-mail-ck 50/tcp # Удаленный протокол проверки почты
re-mail-ck 50/udp # Удаленный протокол проверки почты
domain 53/tcp nameserver # имя сервера домена
domain 53/udp nameserver
mtp 57/tcp
bootps 67/tcp # ВООТР-сервер
bootps 67/udp
bootpc 68/tcp # ВООТР-клиент
bootpc 68/udp
tftp 69/udp
gopher 70/tcp # Internet Gopher
gopher 70/udp
rje 77/tcp netrjs
finger 79/tcp
www 80/tcp http # WorldWideWeb HTTP
www 80/udp # HyperText Transfer Protocol
link 87/tcp ttylink
kerberos 88/tcp kerberos5 krb5 # Kerberos v5
kerberos 88/udp kerberos5 krb5 # Kerberos v5
supdup 95/tcp
# 100 - reserved
hostnames 101/tcp hostname
iso-tsap 102/tcp tsap # часть ISODE.
csnet-ns 105/tcp cso-ns
csnet-ns 105/udp cso-ns
# poppassd (Eudora) использует порты, которые уже были ассоциированы
# с другими услугами. Ниже приведен список poppassd.
# Это позволяет программам запрашивать данные услуги.
rtelnet 107/tcp # удаленный Telnet
rtelnet 107/udp
pop2 109/tcp pop-2 postoffice # POP версии 2
pop2 109/udp pop-2
рор3 110/tcp pop-3 # POP версии 3
рор3 110/udp pop-3
sunrpc 111/tcp portmapper # RPC 4.0 portmapper TCP
sunrpc 111/udp portmapper # RPC 4.0 portmapper UDP
auth 113/tcp authentication tap ident
sftp 115/tcp
uucp-path 117/tcp
nntp 119/tcp readnews untp # USENET News Transfer Protocol
ntp 123/tcp
ntp 123/udp # Network Time Protocol
netbios-ns 137/tcp # имя сервиса NETBIOS
netbios-ns 137/udp
netbios-dgm 138/tcp # NETBIOS Datagram-услуга
netbios-dgm 138/udp
netbios-ssn 139/tcp
netbios-ssn 139/udp
imap2 143/tcp imap # Interim Mail Access Proto v2
imap2 143/udp imap
snmp 161/udp # Simple Net Mgmt Proto
snmp-trap 162/udp snmptrap
cmip-man 163/tcp
cmip-man 163/udp
cmip-agent 164/tcp
amp-agent 164/udp
xdmcp 177/tcp # X Display Mgr. Control Proto
xdmcp 177/udp
nextstep 178/tcp NeXTStep NextStep # Окно NeXTStep
nextstep 178/udp NeXTStep NextStep # сервер
bgp 179/tcp # Border Gateway Proto.
bgp 179/udp
prospero 191/tcp # Cliff Neuman's Prospero
prospero 191/udp
irс 194/tcp # Internet Relay Chat
irc 194/udp
smux 199/tcp # SNMP Unix Multiplexer
smux 199/udp
at-rtmp 201/tcp # маршрутизация AppleTalk
at-rtmp 201/udp
at-nbp 202/tcp # привязка имен AppleTalk
at-nbp 202/udp
at-echo 204/tcp # эхо AppleTalk
at-echo 204/udp
at-zis 206/tcp # информация о часовом поясе AppleTalk
at-zis 206/udp
qmtp 209/tcp # The Quick Mail Transfer Protocol
qmtp 209/udp # The Quick Mail Transfer Protocol
z3950 210/tcp wais # база данных NISO Z39.50
z3950 210/udp wais
ipx 213/tcp # IPX
ipx 213/udp
imap3 220/tcp # Interactive Mail Access
imap3 220/udp # Protocol v3
rpc2portmap 369/tcp
rpc2portmap 369/udp # Coda portmapper
codaauth2 370/tcp
codaauth2 370/udp # сервер авторизации Coda
ulistserv 372/tcp # UNIX Listserv
ulistserv 372/udp
ldap 389/tcp # Lightweight Directory Access Protocol
ldap 389/udp # Lightweight Directory Access Protocol
https 443/tcp # MCom
https 443/udp # MCom
snpp 444/tcp # Simple Network Paging Protocol
snpp 444/udp # Simple Network Paging Protocol
saft 487/tcp ft Simple Asynchronous File Transfer
saft 487/udp # Simple Asynchronous File Transfer
npmp-local 610/tcp dqs313_qmaster # npmp-local / DQS
npmp-local 610/udp dqs313_qmaster # npmp-local / DQS
npmp-gui 611/tcp dqs313_execd # npmp-gui / DQS
npmp-gui 611/udp dqs313_execd ft npmp-gui / DQS
hmmp-ind 612/tcp dqs313_intercell# HMMP Indication / DQS
hmmp-ind 612/udp dqs313_intercell# HMMP Indication / DQS
#
# Особые сервисы UNIX
#
exec 512/tcp
biff 512/udp comsat
login 513/tcp
who 513/udp whod
shell 514/tcp and # без использования пароля
syslog 514/udp
printer 515/tcp spooler # линейный пул принтера
talk 517/tcp
ntalk 518/udp
route 520/udp router routed # RIP
timed 525/udp timeserver
tempo 526/tcp newdate
courier 530/tcp rpc
conference 531/tcp chat
netnews 532/tcp readnews
netwall 533/udp # для непредвиденных передач
uucp 540/tcp uucpd # uucp daemon
afpovertcp 548/tcp # AFP над TCP
afpovertcp 548/udp # AFP над TCP
remotefs 556/tcp rfs_server rfs # удаленная файловая система Brunhoff
klogin 543/tcp # Kerberized `rlogin' (v5)
kshell 544/tcp krcmd # Kerberized `rsh' (v5)
kerberos-adm 749/tcp. # Kerberos `kadmin' (v5)
#
webster 765/tcp # сетевой словарь
webster 765/udp
#
#
ingreslock 1524/tcp
ingreslock 1524/udp
prospero-np 1525/tcp # Prospero non-privileged
prospero-np 1525/udp
datametrics 1645/tcp old-radius # datametrics / старый радиус вхождения
datametrics 1645/udp old-radius # datametrics / старый радиус вхождения
sa-msg-port 1646/tcp old-radacct # sa-msg-port / старый radacct вхождения
sa-msg-port 1646/udp old-radacct # sa-msg-port / старый radacct вхождения
radius 1812/tcp # радиус
radius 1812/udp # радиус
radacct 1813/tcp # радиус учета
radacct 1813/udp # радиус учета
cvspserver 2401/tcp # CVS client/server operations
cvspserver 2401/udp # CVS client/server operations
venus 2430/tcp # codacon port
venus 2430/udp # Venus callback/wbc interface
venus-se 2431/tcp # tcp side effects
venus-se 2431/udp # udp sftp side effect
codasrv 2432/fccp # не используется
codasrv 2432/udp # порт сервера
codasrv-se 2433/tcp # tcp side effects
codasrv-se 2433/udp # udp sftp side effect
mysql 3306/tcp # MySQL
mysql 3306/udp # MySQL
rfe 5002/tcp # Radio Free Ethernet
rfe 5002/udp # Используется только UDP
cfengine 5308/tcp # CFengine
cfengine 5308/udp # CFengine
bbs 7000/tcp # BBS
#
#
kerberos4 750/udp kerberos-iv kdc # Kerberos (сервер) udp
kerberos4 750/tcp kerberos-iv kdc # Kerberos (сервер) tcp
kerberos_master 751/udp # Kerberos авторизация
kerberos_master 751/tcp # Kerberos авторизация
passwd_server 752/udp # Kerberos сервер passwd
krb_prop 754/tcp # Kerberos
krbupdate 760/tcp kreg # регистрация Kerberos
kpasswd 761/tcp kpwd # Kerberos "passwd"
kpop 1109/tcp # Kerberos
knetd 2053/tcp # Kerberos
zephyr-srv 2102/udp # сервер Zephyr
zephyr-clt 2103/udp # Zephyr serv-hm -соединение
zephyr-hm 2104/udp # Zephyr менеджер хоста
eklogin 2105/tcp # Kerberos зашифрованный rlogin
#
# Неофициальные, но необходимые (для NetBSD) услуги
#
supfilesrv 871/tcp # сервер SUP
supfiledbg 1127/tcp # отладчик SUP
#
# Услуги протокола Datagram Delivery
#
rtmp 1/ddp
nbp 2/ddp # Протокол связывания имен
echo 4/ddp # Эхо-протокол AppleTalk
zip 6/ddp # Протокол часового пояса
#
# Услуги, добавленные для Debian GNU/Linux
#
poppassd 106/tcp # Eudora
poppassd 106/udp # Eudora
mailq 174/udp
mailq 174/tcp
ssmtp 465/tcp # SMTP над SSL
gdomap 538/tcp # распределенные объекты GNUstep
gdomap 538/udp # распределенные объекты GNUstep
snews 563/tcp # NNTP над SSL
ssl-ldap 636/tcp # LDAP над SSL
omirr 808/tcp omirrd # Онлайн-зеркало
omirr 808/udp omirrd # Онлайн-зеркало
rsync 873/tcp # rsync
rsync 873/udp # rsync
swat 901/tcp # inetd
simap 993/tcp # IMAP над SSL
sрор3 995/tcp # POP-3 над SSL
socks 1080/tcp # socks-прокси сервер
socks 1080/udp # socks-прокси сервер
rmtcfg 1236/tcp # Удаленный сервер конфигурирования
xtel 1313/tcp # minitel
support 1529/tcp # GNATS
cfinger 2003/tcp # GNU Finger
ninstall 2150/tcp # услуга ninstall
ninstall 2150/udp # услуга ninstall
afbackup 2988/tcp # система Afbackup
afbackup 2988/udp # система Afbackup
icp 3130/tcp # Internet Cache Protocol (Squid)
icp 3130/udp # Internet Cache Protocol (Squid)
postgres 5432/tcp # POSTGRES
postgres 5432/udp # POSTGRES
fax 4557/tcp # FAX (старый)
hylafax 4559/tcp # HylaFAX (новый)
noclog 5354/tcp # noclogd с TCP (nocol)
noclog 5354/udp # noclogd с UDP (nocol)
hostmon 5355/tcp # hostmon использующий TCP (nocol)
hostmon 5355/udp # hostmon использующий TCP (nocol)
ircd 6667/tcp # Internet Relay Chat
ircd 6667/udp # Internet Relay Chat
webcache 8080/tcp # WWW услуга кэширования
webcache 8080/udp # WWW услуга кэширования
tproxy 8081/tcp # Transparent Proxy
tproxy 8081/udp # Transparent Proxy
mandelspawn 9359/udp mandelbrot # сеть mandelbrot
amanda 10080/udp # Услуга сохранения amanda
kamanda 10081/tcp # Услуга сохранения amanda (Kerberos)
kamanda 10081/udp # Услуга сохранения amanda (Kerberos)
amandaidx 10082/tcp # Услуга сохранения amanda
amidxtape 10083/tcp # Услуга сохранения amanda
isdnlog 20011/tcp # система входа isdn
isdnlog 20011/udp # система входа isdn
vboxd 20012/tcp
vboxd 20012/udp
jserver 22273/tcp
binkp 24554/tcp # Binkley
binkp 24554/udp # Binkley
asp 27374/tcp # Протокол поиска адреса
asp 27374/udp # Протокол поиска адреса
tfido 60177/tcp # Ifmail
tfido 60177/udp # Ifmail
fido 60179/tcp # Ifmail
fido 60179/udp # Ifmail
#
# Локальные услуги
#
linuxconf 98/tcp
Все соединения, использующие сокеты, делятся на три типа:
соединения-клиенты; соединения-слушатели; соединения-серверы. Как только соединение между клиентом и сервером устанавливается, сервер и клиент получают одинаковые возможности и реагируют на одинаковые типы событий. Рассмотрим по порядку эти типы соединений.
Соединение-клиент подключает сокет-клиент локального компьютера к сокету-серверу на удаленном компьютере. Соединение создает сокет-клиент. Сначала сокет-клиент должен определить сокет-сервер, с которым необходимо соединиться. После чего происходит поиск этого сокета и, если сокет найден, сокет-клиент посылает серверу запрос на соединение. Сокет-сервер может не установить соединение сразу же после получения запроса. Сервер запоминает запрос и отвечает на него, как только появляется возможность. Как только сокет-сервер устанавливает соединение, он отсылает сокету-клиенту свое полное описание, после чего клиент завершает соединение.
Соединение-сервер прослушивает запросы сокетов на установление соединения. В случае, если сокет-клиент запрашивает от сокета-сервера соединение, сокет-сервер отсылает клиенту свое полное описание.
Соединение-слушатель - это пассивное соединение сервера, которое принципиально отличается от двух других типов соединений и является односторонним. В этом случае соединение с сокетами -клиентами не устанавливается, а происходит прослушивание и запись запросов на соединение, отправляемых сокетами-клиентами.
Каждый сокет может рассматриваться как конечная точка сетевого соединения. Все сокеты имеют собственные адреса, которые определяют:
тип интерфейсов, которые понимает данный сокет;
номер порта, используемый сокетом для соединения.
Компоненты для создания сокетов располагаются на вкладке Internet палитры компонентов Kylix. Это компоненты TCPClient и TCPServer.
Компонент TCPClient позволяет превратить ваше приложение в TCP/IP-клиент. Сокет-клиент позволяет вам указать сокет-сервер, с которым будет производиться соединение с помощью свойства RemoteHost. Данное свойство может содержать как сетевое имя компьютера, так и его IP-адрес. В дополнение к данному свойству компонент TCPClient имеет свойство RemotePort, которое определяет номер порта сервера, к которому будет производиться подключение. Вы можете указать номер порта либо имя услуги.
После установки этих двух свойств вы можете активизировать ваше соединение с помощью вызова метода open компонента TCPClient. Данный метод вызывается во время выполнения приложения. Если вы хотите, чтобы соединение устанавливалось автоматически после запуска приложения, установите свойство Active компонента TCPClient в true во время разработки приложения.
Как только соединение установлено, ваше приложение может отправлять или принимать данные. Передача данных может осуществляться двумя способами: блоками и асинхронно.
Асинхронная передача данных — передача данных, не разбитых на отдельные блоки, Для такой передачи данных установите свойства BlockMode сокета-клиента и сокета- сервера в bmNonBlocking.
Передана данных блоками осуществляется быстрее, чем асинхронная. Данный способ передачи данных применяется в тех случаях, когда необходимо продолжать выполнение приложения во время передачи данных. Таким обра-зом, приложение создает дополнительный поток для чтения или передачи данных (о процессах и потоках см. главу 14). Для установки блочного режима передачи данных установите свойства BlockMode клиента и сервера bmBlocking.
Для завершения соединения достаточно произвести вызов метода Close для компонента TCPClient. Кроме того, соединение может быть завершено и со стороны сервера. Если это происходит, то генерируется событие OnDisconnect.
Компонент TCPServer позволяет превратить приложение в ТСР/IР-сервер. Перед тем как сокет-сервер сможет прослушивать запросы клиентов, вы должны указать номер порта, который будет прослушивать сервер. Это можно сделать с помощью свойства LocalPort. Для начала прослушивания запросов клиентов нужно вызвать метод open компонента TCPServer. Для автоматического включения прослушивания во время запуска приложения установите свойство Active компонента TCPServer в true. Если вы хотите, чтобы сокет-сервер автоматически устанавливал соединение с клиентом при получении от него запроса, установите свойство AutoAccept компонента TCPServer в True. Для завершения текущего соединения можно вызвать метод Close или установить свойство Active компонента TCPServer в false.
Если отключение произведено клиентом, то на сервере произойдет событие OnDisconnect.
Для передачи данных используйте функцию SendBuf. Данная функция описана следующим образом:
function SendBuf(var buff; bufsize: integer; flags: integer = 0): integer;
dynamic;
При вызове этой функции приложение отсылает буфер данных через сокет. Переменная buf — это переменная, содержащая отсылаемые данные, а bufsize - размер буфера данных.
Для приема данных используется функция ReceiveBuf:
function ReceiveBuf(var buf; bufsize: integer; flags: integer =0): integer; dynamic;
Код обработки события OnPaint
Листинг 13.1.Код обработки события OnPaint
procedure TForm1.FormPaint(Sender: TObject);
begin
messagedlg('Произошло обновление формы' ,mtInformation, [mbOK], 0);
end;
Теперь напишем код обработки события OnClick.
Код обработки события OnClick
Листинг 13.2.Код обработки события OnClick
procedure TForm1.Button1Click(Sender: TObject);
begin
Form1.Refresh; // Вызываем метод обновления формы end;
Запустим приложение на выполнение. Сразу после запуска произойдет событие первоначальной прорисовки формы. В результате появится окно сообщения об обновлении формы (рис 13.2).
Попробуйте изменить размеры формы в сторону увеличения или нажмите на кнопку Button1. В результате вы увидите то же самое информационное окно.
Таким образом, во время перерисовки компонента вы можете выполнить необходимые действия.
Установка значения цвета пера
Листинг 13.3. Установка значения цвета пера
procedure TForm1.Button1Click(Sender: TObject);
begin
Canvas.Pen.Color := PenColor.ForegroundColor; end;
Ширина пера
Ширина пера определяет толщину линий, которыми будут начерчены геометрические фигуры.
Примечание
Если вы создаете кросс-платформенное приложение, которое может функционировать как под Linux, так и под Windows 9x, и ширина пера более одного пиксела, то имейте в виду, что Windows будет всегда рисовать сплошные линии, независимо от значения свойства Style пера.
Для смены ширины пера достаточно присвоить необходимое числовое значение свойству Width пера (листинг 13.4).
Установка ширины пера
Листинг 13.4.Установка ширины пера
procedure TForm1.Button1Click(Sender: TObject);
begin
Canvas.Pen.Width := 5;
end;
Стиль пера
Свойство Style позволяет вам устанавливать различные стили начертания линий. Это могут быть сплошные линии, пунктирные, точечные и др.
В листинге 13.5 стиль пера меняет последовательно все возможные значения.
Смена стилей пера
Листинг 13.5. Смена стилей пера
procedure TForm1.Button1Click(Sender: TObject);
begin
with Canvas.Pen do begin Style = psSolid
Style = psDash Style = psDot Style = psDashDot Style = psDashDotDot Style = psClear; end; end;
Режим пера
Свойство пера Mode позволяет вам устанавливать различные режимы комбинирования цвета пера с цветом, расположенным на канве. Например, режим постоянного цвета пера, режим инверсии цвета пера или фона канвы пр.
Установка и определение позиции пера
Текущая позиция рисования, с которой начинается рисование линий, называется позицией пера. Как вы уже знаете, объект канвы хранит текущую позицию пера в свойстве PenPos. Позиция пера нужна только для рисования линий. Для рисования геометрических фигур и вывода текста на канву вы указываете необходимые координаты при вызове соответствующих методов. Для установки нужной позиции пера вызывайте метод MoveTo:
Image1.Canvas.MoveTo(0, 0);
Данный код установит перо в левый верхний угол канвы.
Примечание
Черчение линий с помощью метода LineTo также устанавливает текущую позицию, пера, равную конечной точке линии.
Установка цвета кисти
Листинг 13.6.Установка цвета кисти
procedure TForm1.Button1Click(Sender: TOtrject);
begin
Canvas.Brush.Color := clBlue; end;
Стиль кисти
Стиль кисти определяет, каким образом будет заполняться область на канве или геометрическая фигура. Это позволяет программисту комбинировать цвет кисти с уже имеющимися цветами канвы.
Для смены стиля кисти достаточно напрямую установить свойство Style в одно из следующих значений:
bsSolid, bsClear, bsHonzontal, bsVertical, bsFDiagonal, bsBDiagonal, bsCross, bsDiagCross, bsDense1, bsDense2, bsDense3, bsDense4, bsDense5, bsDense6 или bsDense7.
Пример, приведенный в листинге 13.7, показывает, как можно установить стиль кисти. Здесь происходит последовательная установка нескольких значений стиля кисти.
Установка стииля кисти
Листинг 13.7. Установка стииля кисти
procedure TForm1.Button1Click(Sender: TObject);
begin
with Canvas.Brush do begin
Style = bsSolid Style = bsClear Style = bsHorizontal Style = bsVertical Style = bsFDiagonal Style = bsBDiagonal Style = bsCross Style = bsDiagCross; end; end;
Установка значения свойства Bitmap
Свойство Bitmap кисти позволяет указать графический образ, который будет использоваться для заполнения областей и геометрических фигур, расположенных на канве.
Нижеприведенный пример (листинг 13.8) показывает, как можно загрузить графический образ из файла и присвоить его свойству Bitmap кисти канвы формы Form1.
Загрузка графического образа из файла
Листинг 13.8.Загрузка графического образа из файла
var
Bitmap: TBitmap; begin
Bitmap := TBitmap.Create; try
Bitmap.LoadFromFile('MyBitmap.bmp');
Form1.Canvas.Brush.Bitmap := Bitmap; Form1.Canvas.FillRect(Rect(0,0,100,100));
finally
Form1.Canvas.Brush.Bitmap := nil;
Bitmap.Free; end; end;
Примечание
Кисть не является владельцем графического образа, который присвоен свойству Bitmap кисти. Вы должны самостоятельно уничтожать объект графического образа после использования.
Пример рисования прямых линий procedure TForm1 FormPaint(Sender TObject);
begin
Листинг 13.9. Пример рисования прямых линий procedure TForm1.FormPaint(Sender: TObject);
begin
with Canvas do begin
MoveTo(0, 0);
LineTo(ClientWidth, ClientHeight);
MoveTo(0, ClientHeight);
LineTo(ClientWidth, 0), end; end;
Результат выполнения примера изображен на Рисунок 13.3.
Построение ломанной линии
Листинг 13.10.Построение ломанной линии
with Canvas do begin
MoveTo(0, 0);
LineTo(12, 14);
LineTo(50, 30);
LineTo(130, 120);
LineTo(2l0,132);
end;
Примечание
Если вы рисуете ломаные линии, то используйте метод Polyline, т. к. он выполняется значительно быстрее, чем вызов нескольких методов LineTo.
Рисование геометрических фигур
Для рисования эллипсов, окружностей или прямоугольников вы можете использовать методы Ellipse или Rectangle соответственно.
Приведем пример (листинг 13.11), в котором рисуется прямоугольник, занимающий левую верхнюю четвертую часть формы, а затем в этот прямоугольник вписывается эллипс (Рисунок 13.5).
Прямоугольник со вписанным эллипсом
Листинг 13.11.Прямоугольник со вписанным эллипсом
procedure TForm1.FormPaint(Sender: TObject);
begin
Canvas.Rectangle(0, 0, ClientWidth div 2, ClientHeight div 2);
Canvas.Ellipse(0, 0, ClientWidth div 2, ClientHeight div 2);
end;
Для того чтобы нарисовать на канве прямоугольник со скругленными углами, вы можете воспользоваться методом RoundRect.
Первые четыре параметра определяют координаты главной диагонали прямоугольника, остальные два показывают, как скругляются его углы.
Прямоугольник со скругленными углами procedure TForm1 FormPaint{Sender TObject);
begin
Листинг 13.12.Прямоугольник со скругленными углами procedure TForm1.FormPaint{Sender: TObject);
begin
Canvas.RoundRect(0, 0, ClientWidth div 2, ClientHeight div 2, 10, 10);
end;
Объявление типа и переменных
Листинг 13.13.Объявление типа и переменных
type
TDrawingTool = (dtLine, dtRectangle, dtEllipse, dtRoundRect);
TForm1 = class(TForm)
. . . { объявление методов }
public
Drawing: Boolean;
Origin, MovePt: TPoint;
DrawingTool: TDrawingTool; { переменная, которая будет содержать текущий
инструмент }
end;
Расположим на панели инструментов четыре кнопки SpeedButton, каждая из которых будет означать линию, прямоугольник, эллипс или прямоугольник со скругленными углами. Теперь нужно для каждой кнопки написать обработчик события OnClick, в котором необходимо присвоить соответствующее значение переменной DrawingTool (листинг 13.14).
Обработчики нажатия кнопок
Листинг 13.14. Обработчики нажатия кнопок
procedure TForm1.LineButtonClick{Sender: TObject);
{ Кнопка линии } begin
DrawingTool := dtLine; end;
procedure TForm1.RectangleButtonClick(Sender: TObject);
{ Кнопка
прямоугольника } begin
DrawingTool := dtRectangle; end; procedure TForm1.EllipseButtonClick (Sender: TObject);
{ Кнопка эллипса } begin
DrawingTool := dtEllipse; end;
procedure TForm1.RoundedRectButtonClick(Sender: TObject}; { Кнопка
прямоугольника со скругленными углами } begin
DrawingTool := dtKoundRect; end;
Теперь нам осталось написать лишь обработчики событий движения мыши (OnMouseMove) и отпускания левой кнопки мыши (OnMouseUр). Эти обработчики представлены в листингах 13.15 и 13.16.
Обработчик события OnMouseup
Листинг 13.15.Обработчик события OnMouseup
procedure TForm1. FormMouseUp (Sender: TObject; Button TMouseButton; Shift: TShiftState; X ,Y: Integer);
begin
case DrawingTool of dtLine: begin
Canvas.MoveTo(Origin.X, Origin. Y);
Canvas.LineTo(X, Y) end;
dtRectangle: Canvas.Rectangle{Origin.X, Origin.Y, X, Y);
dtEllipse: Canvas.Ellipse(Origin.X, Origin.Y, X, Y);
dtRoundRect: Canvas.RoundRect(Origin.X, Origin.Y, X, Y, (Origin.X - X} div 2, (Origin.Y - Y) div 2);
end;
Drawing := False; end;
Обработчик события OnMouseMove
Листинг 13.16.Обработчик события OnMouseMove
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
if Drawing then
begin
Canvas.Pen.Mode := pmNotXor; case DrawingTool of dtLine: begin
Canvas.MoveTo(Origin.X, Origin.Y);
Canvas.LineTo(MovePt.X, MovePt.Y);
Canvas.MoveTo(Origin.X, Origin.Y);
Canvas.LineTo(X, Y);
end; dtRectangle: begin
Canvas.Rectangle(Origin.X, Origin.Y, MovePt.X, MovePt.Y);
Canvas.Rectangle(Origin.X, Origin.Y, X, Y);
end;
dtEllipse: begin
Canvas.Ellipse(Origin.X, Origin.Y, X, Y);
Canvas.Ellipse(Origin.X, Origin.Y, X, Y);
end;
dtRoundRect: begin
Canvas.RoundRect(Origin.X, Origin.Y, X, Y, (Origin.X - X) div 2, (Origin.Y - Y) div 2);
Canvas.RoundRect(Origin.X, Origin.Y, X, Y,
(Origin.X - X) div 2, (Origin.Y - Y) div 2);
end; end;
MovePt := Point(X, Y);
end; Canvas.Pen.Mode := pmCopy; end;
Создание объекта Bitmap
Листинг 13.17.Создание объекта Bitmap
procedure TForm1.FormCreate(Sender: TObject);
var Bitmap: TBitmap; {временная переменная для хранения графического образа}
begin
Bitmap := TBitmap.Create;{ создаем графический объект }
Bitmap.Width := 200; { устанавливаем начальную ширину }
Bitmap.Height := 200; { и начальную высоту объекта Bitmap }
Image.Picture.Graphic := Bitmap; { присваиваем созданный графический
объект компоненту Image } Bitmap.Free; { Нам больше не нужен графический объект, поэтому
уничтожаем его } end;
Если вы записали вышеприведенный код в обработчике события OnCreate формы Form1 и запустили приложение, то вы сможете увидеть в клиентской части формы белый квадрат, представляющий собой как бы заготовку для изображения. Если вы уменьшите окно таким образом, чтобы изображение не помещалось в нем, автоматически появятся полосы прокрутки.
В данной заготовке можно осуществлять любые графические операции. Для этого следует воспользоваться канвой компонента Image.
Для работы с линиями объекта Bitmap имеется свойство ScanLine, которое позволяет получать информацию о цветах пикселов одной линии в виде массива RGB.
Пример, приведенный в листинге 13.18, показывает, как можно использовать свойство ScanLine для одновременного получения пикселов одной линии.
Прямая работа с Bitmap
Листинг 13.18.Прямая работа с Bitmap
procedure TForm1.Button1Click(Sender: TObject);
// Данный пример показывает, как можно рисовать напрямую в Bitmap
var
х,y : integer; Bitmap : TBitmap; P : PByteArray; begin
Bitmap := TBitmap.create; try
if OpenDialog1.Execute then begin
Bitmap.LoadFromFile(OpenDialog1.FileName);
for y := 0 to Bitmap.height -1 do begin
P : = Bitmap. ScanLine [y];
for x := 0 to Bitmap.width -1 do
Р[х] := y; end; end;
canvas.draw(0,0,Bitmap);
finally Bitmap.free; end; end;
Сохранение графики в файл
Листинг 13.20.Сохранение графики в файл
var Form1: TForm1 ;
CurrentFile:String; implementation
{$R *.XFM}
procedure TForm1.Save1Click(Sender: TObject);
begin
if CurrentFile <>
'' then
Image1.Picture.SaveToFile(CurrentFile) { файл уже существует } else SaveAslClick(Sender);
{ иначе нужно ввести имя файла } end;
procedure TForm1.SaveAslClick(Sender: TObject);
begin
if SaveDialog1.Execute then { Получить имя файла } begin
CurrentFile := SaveDialog1.FileName; { сохранить файл с именем,
заданным пользователем }
Save1Click(Sender);
{ вызов метода сохранения файла } end;
end;
Копирование графики в буфер обмена
Листинг 13.21.Копирование графики в буфер обмена
procedure TForm1.Copy1Click{Sender: TObject);
begin
Clipboard.Assign(Image.Picture) end.
Вырезание графики в буфер обмена
Вырезание графики в буфер обмена похоже на копирование. Отличие заключается в том, что после копирования картинка, содержащаяся в источнике, уничтожается.
Для реализации данной операции нужно выполнить два последовательных шага:
1. Скопировать данные в буфер обмена.
2. Уничтожить оригинальные данные.
В листинге 13.22 показано, как можно осуществить операцию вырезания картинки в буфер обмена. Сначала изображение копируется в буфер обмена, затем место, откуда взято изображение, закрашивается белым цветом с помощью установки режима копирования cmWhiteness.
Вырезание графики в буфер обмена
Листинг 13.22. Вырезание графики в буфер обмена
procedure TForm1.Cut1Click(Sender: TObject);
var
ARect: TRect; begin
Copy1Click{Sender);
{ копирование картинки в буфер обмена }
with Image.Canvas do begin
CopyMode := cmWhiteness;{установить режим копирования в белый цвет} ARect := Rect(0, 0, Image.Width, Image.Height);
{получение квадрата копирования}
CopyRect(ARect, Image.Canvas, AReCt);
{ наложение белого прямоугольника } CopyMode := cmSrcCopy; { восстановление нормального режимакопирования } end; end;
Вставка графики из буфера обмена
Если в буфере обмена содержится какая-либо графическая информация, вы можете вставить ее в любой графический компонент Kylix, включая канву формы.
Для вставки графики из буфера обмена нужно выполнить следующие шаги:
1. Вызвать метод Provides объекта Clipboard для того, чтобы убедиться, что буфер обмена содержит графическую информацию. Метод Provides представляет собой функцию, которая возвращает булевы значения. Если возвращаемое значение True, то буфер обмена содержит данные именно такого типа, которые указаны в параметре метода Provides.
2. Указать объект, в который будет произведено копирование с помощью метода Assign.
Нижеприведенный код (листинг 13.23) показывает, как можно копировать картинку из буфера обмена в компонент Image с помощью пункта меню Edit/Paste.
Копирование графики
Листинг 13.23.Копирование графики из буфера обмена procedure TForm1.PasteButtonClick(Sender: TObject);
var
Bitmap: TBitmap; begin
if Clipboard.Provides(SDelphiBitmap) then { в буфере обмена
изображение? ) begin
Image1.Picture.Bitmap.Assign(Clipboard);
end; end;
Изображение, находящееся в буфере обмена, может быть скопировано из любого приложения.
Установка позиции пера в координатах указаннных пользователем
Листинг 13.26. Установка позиции пера в координатах, указаннных пользователем
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Canvas.MoveTo (X, Y);
{ установка позиции пера } end;
Обработка событии OnMouseUp
Событие OnMouseUp происходит всякий раз, когда пользователь отпускает на-жатую кнопку мыши. Комбинация данного события с событием OnMouseDown позволит вам, например, рисовать линии. Когда пользователь нажал кнопку мыши, установить начальную точку линии, а когда отпустил — конечную.
Для обработки события OnMouseUp нужно, как и для обработки OnMouseDown, создать программу-обработчик.
Приведем пример (листинг 13.27), который рисует линию из точки, в которой произошло нажатие кнопки мыши, в точку, в которой пользователь отпустил кнопку мыши (Рисунок 13.8).
Пример рисования линии
Листинг 13.27. Пример рисования линии
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Canvas.MoveTo(X, Y) ; { установка позиции пера } end;
procedure TForm1. FormMouseUp (Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Canvas.LineTo(X, Y);
{ рисуем линию из координат PenPos в (X, Y) } end;
Пользователь не будет видеть линию, пока не отпустит кнопку мыши.
Пример обработки
Листинг 13.28.Пример обработки события OnMouseMove procedure TForm1.FormMouseMove(Sender: ТОbject;Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Canvas.LineTo(X, Y);
{ рисует линию в текущую позицию } end;
Листинг игровой программы "Крестикинолики"
Листинг 13.29.Листинг игровой программы "Крестики-нолики"
unit Unit1;
interface
uses
SysUtils, Types, Classes, Variants, QGraphics, QControlS, QForms, QDialogs,
QStdCtrls;
type
TForm1 = class (TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
f:boolean; // Флаг, указывающий, что ставится: крестик
// или нолик
implementation {$R *.xfm}
procedure TForm1.Button1Click(Sender; TObject); var
i:integer; begin
// Рисуем прямоугольную область, закрашенную белым цветом Canvas.FillRect(rect(10,10,210,210)); i:=10; //Рисуем горизонтальные линии клеточек сетки 10x10 while i<=210 do begin
Canvas.MoveTo(10, i);
Canvas.LineTo(210,1);
i:=i+20; end; i:=10;
// Рисуем вертикальные линии клеточек сетки 10x10 while i<=210 do begin
Canvas.MoveTo(i,10); Canvas.LineTo(i, 210) ;
i :=i+20; end; end;
procedure TForm1.Button2Click{Sender: TObject); begin
Form1.Close; // Закрытие приложения end;
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
Var
x1,y1:integer; begin
// Проверяем, в какой области формы щелкнул мышкой пользователь // Если в области сетки, то
if (х>10) and (x<210) and (у>10) and (y<210) then begin
// Вычисляем координаты левого верхнего угла клеточки, // внутри которой щелкнул пользователь x1:=trunc((х-10)/20)*20+10; y1:=trunc( (у-10) /20) *20+10; // Проверяем, что ставить: крестик или нолик f:=not(f); if f=true then begin // Если нолик, то
canvas.Pen.Color:=clRed; canvas.Pen.Width:=2; canvas.Ellipse(x1,y1,x1+20,y1+20); end else begin // Иначе - крестик
canvas.Pen.Color:=clBlue; canvas.Pen.Width:=2; canvas.MoveTo(x1,y1); canvas. LineTo (x1+20,y1+20); canvas.MoveTo(x1+20,y1); canvas.LineTo(x1, y1+20) ; end; end;
end;
end.
Теперь запустим программу. Нажмите кнопку Начать игру, и программа нарисует белый прямоугольник и сетку 10x10 (Рисунок 13.11).
Загрузка графики из файла
Листинг 13.29.Загрузка графики из файла
procedure TForm1.Open1Click (Sender: TObject);
var
CurrentFile: String; begin
if CpenDialogl.Execute then
begin
CurrentFile := OpenDialog1.FileName; Image1.Picture.LoadFromFile (CurrentFile);
end; end;
Для успешной работы данного примера вам необходимо разместить на форме Form1 компонент OpenDialog1, который вы найдете на вкладке Dialogs палитры компонентов Kylix, а также меню Menu1 с пунктом Open, и записать в обработчике события OnClick для данного пункта меню этот код.
Сохранение графического образа в файл
Для сохранения графического образа в файл вызовите метод SaveToFile. Данный метод требует, чтобы вы передали в качестве параметра имя файла, в который будет произведено сохранение графического образа.
Нижеприведенный пример (листинг 13.20) содержит две процедуры для двух пунктов меню Save и SaveAs. Если вызывается пункт меню Save, то производится проверка, был ли уже создан файл для данного графического образа, если он был создан, то образ сохраняется. Если такой файл не был создан, вызывается метод SaveAs, который открывает окно SaveDialog1 и запрашивает имя файла для данного графического образа, после чего управление передается методу Save.
Таким образом, для успешной работы данного примера вам необходимо расположить на форме Form1 меню с двумя пунктами Save и SaveAs и компонент SaveDialog с вкладки Dialogs палитры компонентов Kylix. Кроме того, разместите на форме компонент Image1 для хранения графического образа, после чего запишите в обработчик событий нажатия пунктов меню код, приведенный в листинге 13.20.