Бегун.Рекомендую - партнеру
Здесь может быть ваша реклама
|

 Глава 10. Интерфейсы

Глава 10. Интерфейсы

В этой главе мы рассмотрим, что такое интерфейс и где он применяется. Кроме того, вы узнаете, что такое графический интерфейс пользователя, и познакомитесь с методами создания SDI- и MDI- приложений.

Понятие интерфейса
Ключевое слово Kylix interface позволяет вам создавать и использовать интерфейсы в ваших приложениях. Интерфейсы расширяют модель наследования в CLX, позволяя одному классу принадлежать нескольким интерфейсам, а также нескольким классам - наследникам различных базовых классов - использовать один интерфейс. Интерфейсы полезны в тех случаях, когда наборы операций, таких как потоки, используются большим количеством объектов.
Таким образом, интерфейсы - это средства для обеспечения взаимодействия между разными объектами.
Интерфейсы похожи на классы, которые содержат в себе только абстрактные методы и четкие определения их функциональности. Определение метода интерфейса включает в себя параметры и типы параметров, возвращаемый тип, а также ожидаемое поведение. Методы интерфейса семантически или логически связаны с отражением цели интерфейса. Существует соглашение об интерфейсах, гласящее, что каждый интерфейс должен быть назван в соответствии с задачей, которую он предназначен выполнять. Например, интерфейс IMalloc - предназначен для распределения, освобождения и управления памятью. Аналогично, интерфейс IPersist может использоваться как базовый интерфейс для потомков, каждый из которых определяет специфичные прототипы методов для загрузки и сохранения состояния объектов в память, поток или в файл. В листинге 10.1 приведен простой пример объявления интерфейса.

Листинг 10.1. Объявление интерфейса
type
IEdit = interface
procedure Copy; stdcall;
Iprocedure Cut; stdcall;
procedure Paste; stdcall;
function Undo: Boolean; stdcall;

Примечание
Тем читателям, которые имеют слабое представление о создании компонентов и новых классов, советуем прочитать пятую часть книги, посвященную созданию собственных компонентов и модификации уже существующих.

Неьзя создать экземпляр интерфейса при помощи интерфейса. Для получения экземпляра интерфейса вам нужно объявить его в классе, содержащим данный интерфейс. Таким образом, нужно определить класс, который держит необходимый интерфейс в списке своих родителей (листинг 10.2).

Листинг 10.2. Объявление класса, содержащего интерфейс
TEditor = class (TInterfacedObject, lEdit)
procedure Copy; stdcall;
procedure Cut; stdcall;
rocedure Paste; stdcall;
function Undo: Boolean; stdcall;
end;

Как уже было отмечено выше, использование интерфейсов позволяет нескольким классам общаться с помощью общего интерфейса. При этом не обязательно наличие одного базового класса-предка. Следует помнить, что интерфейс - это тип с управляемым временем жизни, т. е. он автоматически при инициализации принимает значение nil, обладает счетчиком ссылок тематически уничтожается при выходе за пределы своей области видимости.

Интерфейс IUnknown
По аналогии с наследованием классов, предком которых является базовый ее TObject, все интерфейсы являются прямыми или косвенными наследниками интерфейса lunknown. Этот базовый интерфейс описан в модуле следующим образом (листинг 10.3).

Листинг 10.3. Описание базового интерфейса lunkhown :
type
lUnknown = interface
['{ 00000000-0000-0000-С000-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 coCreatecuiDO, получается запись типа TGUID. Эту запись можно определить в виде строки следующего формата:

'{хххххххх-хххх-хххх-хххх-хххххххххххх}'

Для создания нового GUID в среде Kylix достаточно нажать комбинацию клавиш <Ctii>+<Shift>+<G> при работе редактора кода.
Итак, интерфейс lunknown поддерживает три метода, которые наследуются всеми интерфейсами:

Queryinterfасе () - используется для создания запроса, поддерживается ли данный интерфейс, и если поддерживается, то метод возвращает указатель на него. Предположим, что имеется некоторый объект object, который поддерживает несколько интерфейсов: interfacel, interface2 и др. Для получения указателя на интерфейс interface2 объекта object
Вам Нужно вызвать метод Interface2.QueryInterface() .

_AddRef о - используется, когда получен указатель на данный интерфейс, и вы хотите использовать этот указатель. Метод _AddRef о обязательно должен заканчиваться вызовом метода _Reiease {) .

_Release о - используется для завершения работы с интерфейсом.

Класс TlnterfacedObject
В CLX Kylix определен класс TlnterfacedObject, который служит базовым эм для объектов интерфейса. Данный класс определен в модуле Kylix System (листинг 10.4).

Листинг 10.4. Определение класса TlnterfacedObject
type
TinterfacedObject = class(TObject, Ilnterface)
protected
FRefCount: Integer;
function Querylnterface(const IID: TGUID; out Obj): HResult;
stadcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
public
procedure AfterConstruction; override;
procedure BeforeDestruction; override;
class function Newlnstance: TObject; override;
property RefCount: Integer read FRefCount;
end;

Как вы видите, данный класс в качестве родителей имеет класс TObject и интерфейс IInterface. Класс TlnterfacedObject позволяет достаточно легко задавать классы, поддерживающие интерфейсы. Например,

type
TMyObjInterfaced = class(TlnterfacedObject, IPaint)
...
end;

На вышеприведенном примере мы определяем новый класс TMyObjInterfaced, который является прямым потомком класса terfacedobject и поддерживает некий интерфейс IPaint.

Использование оператора as
Объекты, поддерживающие интерфейсы, могут использовать оператор as динамического присоединения интерфейса. Например,

procedurePaintObjects(P: TlnterfacedObject)
var
X: IPaint;
begin
X := Р as IPaint;
{операторы}
end;

В данном примере переменная Р имеет тип Tinterfacedobject. Данная переменная может быть назначена переменной х, как ссылка на интерфейс IPaint. Для данного назначения компилятор генерирует код для вызова метода Queryinterface, относящегося к интерфейсу lUnknown переменной р. Такое назначение возможно, даже если Р не поддерживает данный интерфейс. То есть компилятор не выдаст ошибку при таком назначении.
Во время выполнения вышеприведенного примера либо успешно происходит присваивание

Х:= Р as IPaint;

либо генерируется исключительная ситуация.
При использовании оператора as вы должны выполнять следующие требования:
при объявлении интерфейса явно объявляйте в качестве предка интерфейс lunknown, т. к. только в этом случае вы сможете воспользоваться оператором as;
если вы используете оператор as для интерфейса, данный интерфейс должен иметь свой IID. Напомним, что для создания нового IID достаточно, находясь в редакторе кода, нажать комбинацию клавиш <Ctrl>+ +<Shift>+<G>.

Использование ключевого слова implements
Многие классы CLX Kylix имеют в качестве некоторых своих свойств объекты. Кроме того, вы можете применять в качестве свойств класса интерфейсы. В том случае, когда свойство имеет тип интерфейса, вы можете использовать ключевое слово implements для определения методов, которые данный интерфейс передает объекту. По умолчанию ключевое слово implements передает все методы интерфейса. Тем не менее, вы можете самостоятельно определить список тех методов интерфейса, которые передаются объекту.
В листинге 10.5 представлен пример использования ключевого слова implements при создании объекта адаптера цвета, предназначенного для преобразования восьмибитного значения цвета RGB. 10. Интерфейсы

Листинг 10.5. Использование ключевого слова implements
unit cadapt;
ty ре
IRGB8bit = interface
[' {1d76360a-f4f5-11d1-87d4-00c04fb17199}']
function Red: Byte;
function Green: Byte;
function Blue: Byte;
end;
IColorRef = interface ;
['{1d76360b-f4f5-11d1-87d4-00c04fb17199}']
function Color: Integer;
end;
TRGB8ColorRefAdapter = class(TInterfacedObject, IRGB8bit, IColorRef)
private
FRGB8bit: IRGB8bit;
FPalRelative: Boolean;
public
constructor Create(rgb: IRGB8bit);
property RGBSIntf: IRGBSbit read FRGB8bit implements IRGBSbit;
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.

Графический интерфейс пользователя. Создание SDI- и MDI-приложений
Kylix позволяет создавать приложения двух моделей пользовательского интерфейса:
одиночный интерфейс документа (Single document interface, SDI);
многооконный интерфейс документа (Multiple document interface, MDI).
В MDI-приложении в главном родительском окне может располагаться более чем одно дочернее окно или документ. Такая форма наиболее часто используется в приложениях электронных таблиц или текстовых процессорах. В SDI-пршюжении, напротив, может содержаться только один документ или может быть активным всего одно окно. Для того чтобы приложение имело вид SDI,
необходимо установить свойство FormStyle для формы приложения в fsNormal.

Примечание
По умолчанию свойство FormStyle у формы нового приложения устанавливается в fsNormal.

Для создания нового SDI-приложения выполните следующие шаги:
1. Выберите в главном меню Kylix пункт File/New. Появится диалоговое окно New Items (рис. 10.1).



Рис. 10.1. Диалоговое окно New Items

2. Щелкните на пиктограмме Application.
3. Нажмите кнопку ОК.
Для создания нового MDI-приложения выполните следующие шаги:
1. Выберите в главном меню Kylix пункт File/New для вызова диалогового окна New Items.
2. Выберите в диалоговом окне вкладку Projects и щелкните на пиктограмме MDI Application (рис. 10.2).
3. Нажмите кнопку ОК.

Рис. 10.2. Вкладка Projects

В MDI-приложении главная форма содержит несколько дочерних форм, рсоторые могут размещаться внутри главной, но не могут выходить за ее пределы. Для определения, какая форма будет главной, а какая дочерней, установите свойство Formstyle каждой из форм в следующие значения:

fsMDiForm - для главной формы;
fsMDichild - для дочерних форм.

При создании MDI-приложения Kylix делает большую часть работы за программиста. Если вы выполнили вышеперечисленные шаги для создания MDI-приложения, то можете видеть, что Kylix уже создал главную форму (рис. 10.3).


Рис. 10.3. Главная форма MDI-приложения

Более того, данная форма имеет необходимые компоненты для работы со многими дочерними окнами, а также главное меню для работы с файлами и окнами. Кроме того, меню содержит пункт Edit для работы с текстом. Таким образом, Kylix уже сделал для нас простейший многооконный текстовый редактор. Естественно, вы можете самостоятельно расширить его функциональность либо удалить ненужные компоненты.

Рис. 10.4. Три расположенных рядом дочерних окна внутри главной формы

Запустите эту форму и попробуйте создать новые дочерние окна с помощью пункта меню File/New или нажатия на соответствующую пиктограмму панели инструментов. Вы можете создать несколько файлов и располагать их каскадом, рядом и другими способами, с помощью нажатия на соответствующие пиктограммы панели инструментов (рис. 10.4).
Для поддержания всей этой функциональности Kylix создал специальный код, который размещен в модуле clxmain (листинг 10.6).

Листинг 10.6. Код, автоматически создаваемый для MDI-приложения:
unit clxmain;
linterface

uses SysUtils, Classes, QForms, QlmgList, QStdActns, QActnList, QDialogs,
QMenus, QTypes, QComCtrls, QControls, QExtCtrls;

type
TMainForm = class(TForm)
MainMenu1: TMainMenu;
File1: TMenuItem;
FileNewItem: TMenuItem;
FileOpenltem: TMenuItem;
FileCloseltem: TMenuItem; Window1: TMenuItem;
Help1: TMenuItem;
N1: TMenuItem;
FileExitltem: TMenuItem;
WindowCascadeltem: TMenuItem;
WindowTileltem: TMenuItem;
HelpAboutltem: TMenuItem;
OpenDialog: TOpenDialog; FileSaveltem: TMenuItem;
FileSaveAsItem: TMenuItem;
Edit1: TMenuItem;
Cutltem: TMenuItem;
Copyltem: TMenuItem;
Pasteltem: TMenuItem;
WindowMinimizeltem: TMenuItem;
StatusBar: TStatusBar;
ActionList1: TActionList;
EditCut1: TEditCut;
EditCopy1: TEditCopy;
EditPaste1: TEditPaste;
FileNew1: TAction;
FileSave1: TAction;
FileExit1: TAction;
FileOpen1: TAction;
FileSaveAs1: TAction;
WindowCascade1: TWindowCascade;
WindowMinimizeAll1: TWindowMinimizeAll;
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: TToolButton;
ToolButton10: TToolButton;
ToolButton11: TToolButton;
WindowClose1: TWindowClose;
WindowTile1: TWindowTile;
ToolButton12: TToolButton;
ImageList1: TImageList;
procedure FileNewlExecute(Sender: TObject).;
procedure FileOpenlExecute(Sender: TObject);
procedure HelpAboutlExecute(Sender: TObject);
procedure FileExitlExecute(Sender: TObject);
private
{ Private declarations }
procedure CreateMDIChild(const Name: string);
public

{Public declarations }

end;

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.ShowModa1;
end;

procedure TMainForm.FileExit1Execute(Sender: TObject);
begin
Close;
end;
end.

Консольные приложения
Консольные приложения - это 32-разрядные приложения, которые могут работать без загруженного графического интерфейса Linux.
Для создания нового консольного приложения выберите пункт главного меню Kylix File/New и в появившемся диалоговом окне выберите пиктограмму Console Application (рис. 10.5).

Рис. 10.5. Пиктограмма Console Application

Kylix создаст файл проекта для консольного приложения и покажет окно редактора кода с текстом, приведенным в листинге 10.7.

Листинг 10.7. Заготовка для консольного приложения
program Project1;

{$APPTYPE CONSOLE} // Директива компилятора, означающая, что приложение
// будет консольным
begin

end.

Формы в консольных приложениях отсутствуют.
Консольные приложения пишутся на языке Object Pascal. Создание таких приложений практически не отличается от создания программ на языке Pascal под DOS.

 
MKPortal©2003-2008 mkportal.it
MultiBoard ©2007-2009 RusMKPortal