Компонент главного меню} File1: TMenuItem;
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; WindowArrangeItem: 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; WindowTileHorizontal1: TWindowTileHorizontal; WindowArrangeAll1: TWindowArrange; WindowMinimizeAll1: TWindowMinimizeAll; HelpAbout1: TAction; FileClose1: TWindowClose; WindowTileVertical1: TWindowTileVertical; 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; ImageList1: TImageList; procedure FileNew1Execute(Sender: TObject); procedure FileOpen1Execute(Sender: TObject); procedure HelpAbout1Execute(Sender: TObject); procedure FileExit1Execute(Sender: TObject); end; |
Листинг 25.1. |
Закрыть окно |
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;
WindowArrangeItem: 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;
WindowTileHorizontal1: TWindowTileHorizontal;
WindowArrangeAll1: TWindowArrange;
WindowMinimizeAll1: TWindowMinimizeAll;
HelpAbout1: TAction;
FileClose1: TWindowClose;
WindowTileVertical1: TWindowTileVertical;
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;
ImageList1: TImageList;
procedure FileNew1Execute(Sender: TObject);
procedure FileOpen1Execute(Sender: TObject);
procedure HelpAbout1Execute(Sender: TObject);
procedure FileExit1Execute(Sender: TObject);
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.CreateMDIChild(const Name: string); var Child: TMDIChild; begin { Класс TMDIChild определен в модуле CHILDWIN.PAS } Child := TMDIChild.Create(Application); {Создание окна} Child.Caption := Name; { Заголовком окна будет имя файла} if FileExists(Name) then // Дочернее окно содержит поле типа TMemo, в которое // выполняется загрузка текстового файла: Child.Memo1.Lines.LoadFromFile(Name); end; Для завершения приложения выполняется следующая процедура: procedure TMainForm.FileExit1Execute(Sender: TObject); begin Close; end; В модуле childwin.pas находится код дочерней формы: type TMDIChild = class(TForm) Memo1: TMemo; {Поле для отображения текста} procedure FormClose(Sender: TObject; var Action: TCloseAction); end; implementation procedure TMDIChild.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caFree; end; end. |
Листинг 25.2. |
Закрыть окно |
{Создать новый документ}
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.CreateMDIChild(const Name: string);
var
Child: TMDIChild;
begin
{ Класс TMDIChild определен в модуле CHILDWIN.PAS }
Child := TMDIChild.Create(Application); {Создание окна}
Child.Caption := Name; {Заголовком окна будет
имя файла}
if FileExists(Name) then
// Дочернее окно содержит поле типа TMemo, в которое
// выполняется загрузка текстового файла:
Child.Memo1.Lines.LoadFromFile(Name);
end;
Для завершения приложения выполняется следующая процедура:
procedure TMainForm.FileExit1Execute(Sender: TObject);
begin Close; end;
В модуле childwin.pas находится код дочерней формы:
type
TMDIChild = class(TForm)
Memo1: TMemo; {Поле для отображения текста}
procedure FormClose(Sender: TObject;
var Action: TCloseAction);
end;
implementation
procedure TMDIChild.FormClose(Sender: TObject;
var Action: TCloseAction);
begin Action := caFree; end;
end.
Window1 object StatusBar: TStatusBar AutoHint
object MainForm: TMainForm Caption = 'Приложение с MDI-интерфейсом' FormStyle = fsMDIForm Menu = MainMenu1 WindowMenu = Window1 object StatusBar: TStatusBar AutoHint = True Panels = <> SimplePanel = True end object ToolBar2: TToolBar Images = ImageList1 object ToolButton9: TToolButton Action = FileNew1 {Именованное действие, которое будет выполнено при щелчке на кнопке} end object ToolButton1: TToolButton Action = FileOpen1 end {Кнопки панели инструментов} ... end object MainMenu1: TMainMenu Images = ImageList1 object File1: TMenuItem Caption = '&File' object FileNewItem: TMenuItem Action = FileNew1 end object FileOpenItem: TMenuItem Action = FileOpen1 end object FileCloseItem: TMenuItem Action = FileClose1 end ... object FileExitItem: TMenuItem Action = FileExit1 end end object Edit1: TMenuItem ... end object Window1: TMenuItem ... end end object OpenDialog: TOpenDialog {Диалог Open} Filter = 'All files (*.*)|*.*' end object ActionList1: TActionList object FileNew1: TAction Category = 'File' Caption = '& New' OnExecute = FileNew1Execute end object FileOpen1: TAction Category = 'File' Caption = '&Open' OnExecute = FileOpen1Execute end ... end end |
Листинг 25.3. |
Закрыть окно |
object MainForm: TMainForm
Caption = 'Приложение с MDI-интерфейсом'
FormStyle = fsMDIForm
Menu = MainMenu1
WindowMenu = Window1
object StatusBar: TStatusBar
AutoHint = True
Panels = <>
SimplePanel = True
end
object ToolBar2: TToolBar
Images = ImageList1
object ToolButton9: TToolButton
Action = FileNew1 {Именованное действие,
которое будет выполнено при щелчке на кнопке}
end
object ToolButton1: TToolButton
Action = FileOpen1
end
{Кнопки панели инструментов}
...
end
object MainMenu1: TMainMenu
Images = ImageList1
object File1: TMenuItem
Caption = '&File'
object FileNewItem: TMenuItem
Action = FileNew1
end
object FileOpenItem: TMenuItem
Action = FileOpen1
end
object FileCloseItem: TMenuItem
Action = FileClose1
end
...
object FileExitItem: TMenuItem
Action = FileExit1
end
end
object Edit1: TMenuItem
...
end
object Window1: TMenuItem
...
end
end
object OpenDialog: TOpenDialog {Диалог Open}
Filter = 'All files (*.*)|*.*'
end
object ActionList1: TActionList
object FileNew1: TAction
Category = 'File'
Caption = '&
New'
OnExecute = FileNew1Execute
end
object FileOpen1: TAction
Category = 'File'
Caption = '&Open'
OnExecute = FileOpen1Execute
end
...
end
end
Главная форма приложения
По умолчанию при добавлении в проект новой формы для нее в главном файле приложения автоматически формируется строка кода для создания формы.
Например:
Application.CreateForm (TForm1, Form1);.
Для добавления в проект новой формы достаточно выполнить команду меню File|New Form.
Окно свойств проекта позволяет определить:
главную форму приложения - файл, выполняемый первым;список автоматически создаваемых форм;список доступных форм - чтобы их использовать, их надо будет создать.
Если приложение содержит много форм, то для автоматического создания всех форм может не хватить памяти. Более рационально создавать формы по мере необходимости.
Для создания формы используется метод Create.
Созданная форма может быть отображена:
как обычный диалог - вызовом метода Show;как модальный диалог - вызовом метода ShowModal.
Использование модальной формы
Выполнение модальной формы завершается сразу после вызова метода ShowModal, поэтому память из под нее следует освобождать в вызывающей форме вызовом метода Free.
Например:
Form2:=TForm2.Create(self) ; Form2.ShowModal; Form2.Free;
Результат выполнения модальной формы устанавливается свойством ModalResult командных кнопок. Для того чтобы проверить код ответа (какая кнопка была нажата), следует сравнить значение, возвращаемое методом ShowModal.
Например:
if Form2.ShowModal = mrOk then // Нажата кнопка Ок else Abort; // Завершение приложения
Для закрытия модального диалога не следует вызывать метод Close, достаточно использовать командные кнопки с установленным значением свойства ModalResult.
Использование немодальной формы
Время жизни обычного немодального диалога неопределенно и не завершается после вызова метода Show. Поэтому обычный диалог следует завершать в обработчике события OnClose.
Для вызова этого обработчика события можно вызвать метод Close или выполнить щелчок мышью по соответствующей кнопке в строке заголовка окна.
Если перед запуском диалога он был создан (не является автоматически создаваемым), то после его закрытия следует освободить занимаемую им память. Это выполняется в обработчике события OnClose вызовом метода Release.
Классы стандартных диалогов
Страница Dialogs палитры компонентов содержит ряд компонентов, предназначенных для реализации различных стандартных диалогов. Это диалоги для открытия файла, сохранения файла, выбора цвета или шрифта, открытия или сохранения графического файла.
Стандартный диалог открывается при вызове метода Execute. При выборе пользователем значения или щелчке пользователя на кнопке OK возвращается значение True. Если пользователь нажал кнопку Cancel или клавишу Escape, то выполнение стандартного диалога возвращает значение False. Для настройки появления и поведения диалога используется свойство Options. Чтобы закрыть диалог программно, следует вызвать метод CloseDialog.
В следующей таблице приведено описание стандартных диалогов, доступных посредством страницы Dialogs палитры компонентов.
TOpenDialog | Отображает стандартный диалог Open(имя выбранного файла указываетсяв свойстве FileName) |
TSaveDialog | Отображает стандартный диалог Save |
TOpenPictureDialog | Отображает стандартный модальный диалог для выбора и открытия графических файлов. Этот диалог идентичен диалогу Open, но имеет дополнительно панель для просмотра изображения |
TSavePictureDialog | Отображает стандартный диалог для сохранения графических файлов. Этот диалог имеет панель для просмотра изображения |
TFontDialog | Выводит стандартный диалог Font, используемый для определения шрифта, размера и стиля отображения данных |
СTColorDialog | Отображает стандартный диалог Color (выбранный цвет указывается в свойстве Color) |
TPrintDialog | Отображает стандартный диалог Print |
TPrinterSetupDialog | Отображает стандартный диалог Printer Setup |
TFindDialog | Отображает стандартный диалог Find |
TReplaceDialog | Отображает стандартный диалог Replace |
Следующий пример иллюстрирует использование стандартного диалога для выбора имени открываемого файла:
var F: TextFile; S: string; begin if OpenDialog1.Execute then // Показать диалог Open begin AssignFile(F, OpenDialog1.FileName); // Назначить // файловой переменной имя выбранного файла Reset(F); Readln(F, S); //Прочитать первую строку файла Edit1.Text := S; // Поместить строку в компонент TEdit CloseFile(F); // Закрыть файл end; end;
Проекты
Любое приложение в среде проектирования Delphi создается как некоторый проект. В зависимости от типа приложения, в проект входит различный набор файлов проекта. Но в любом случае составной частью проекта является файл проекта с расширением DPR. Каждая форма в проекте представляется двумя файлами: файл модуля с расширением PAS и файл описания формы с расширением DFM. Файл описания формы не может редактироваться непосредственно, данные в него заносятся средой проектирования. В каждый проект входит один главный файл приложения. Для диалоговых приложений этот файл начинается с ключевого слова program. Файл модуля для формы начинается ключевым словом unit.
Для создания нового приложения среда проектирования Delphi предоставляет большой набор шаблонов приложений, включающий приложение-диалог, SDI-приложение и MDI-приложение.
Основное отличие автоматически формируемого макета приложения на базе шаблона MDI-приложения от применения шаблона SDI-приложения заключается в поддержке одновременной работы с несколькими документами. Каждый новый документ открывается в создаваемом дочернем окне.
Дополнительно шаблон MDI-приложения содержит кнопки для изменения расположения окон, а в меню Windows добавляются имена всех открытых документов.
Создание DLL-библиотеки
DLL-библиотека позволяет объединить в единое целое повторно используемый код. Функции из DLL-библиотеки могут подключаться динамически во время выполнения, в отличие от функций из пакетов Delphi линкуемых статически на этапе компиляции приложения.
Для того чтобы создать DLL-библиотеку, следует использовать шаблон приложения DLL Wizard.
В отличие от обычного модуля, начинающегося с ключевого слова unit, модуль DLL-библиотеки начинается с ключевого слова library.
Секция uses модуля DLL-библиотеки требует подключения только двух пакетов: SysUtils и Classes.
Функции из DLL-библиотеки могут вызываться как из приложений, разработанных в Delphi, так и из приложений, написанных на других языках программирования, таких как C++.
Порядок выделения памяти под параметры и освобождения ее различен для разных языков программирования. Чтобы не возникла ошибка времени выполнения, объявление функции в DLL-библиотеке и ее объявление в приложении должны использовать одинаковый механизм передачи параметров.
При объявлении процедуры или функции может быть указан один из следующих механизмов передачи параметров:
registercdecl, stdcall,safecall.
Способ передачи параметров указывается через точку с запятой после описания функции.
Например: function F1(X, Y, Z: Real): Real; stdcall;
Различные способы передачи параметров определяют порядок их передачи (слева направо или справа налево), а также указывают, кто будет освобождать память стека (вызываемая или вызывающая процедура).
Для того чтобы функцию, описанную в DLL-библиотеке, можно было вызвать из другого приложения, эту функцию следует экспортировать. Список всех экспортируемых функций указывается в секции exports через запятую и завершается символом "точка с запятой".
Экспорт функций может выполняться тремя способами:
по имени функции, используемому в DLL-библиотеке;по имени функции, заданному как имя экспорта;по присвоенному функции индексу (указанному в секции exports).
Например:
library Project1; uses SysUtils, Classes; {$R *.res} function F1(X: Integer): Integer; stdcall; begin F1:=X*2; end; function F2(X: Integer): Integer; stdcall; begin F2:=X*X; end; exports F1 , {Функция будут доступна по имени F1} F2 index 2 ; {Функция будут доступна по индексу 2} end.
DLL-библиотека не является выполняемым модулем, поэтому для получения dll-файла достаточно произвести компиляцию проекта.
Создание MDI-приложения
При использовании шаблона MDI-приложения создается проект, состоящий из трех модулей (main.pas, childwin.pas, about.pas) и главного файла приложения.
Для главной формы приложения (main.pas) свойство FormStyle будет установлено равным fsMDIForm, а для дочерней формы (childwin.pas) - fsMDIChild.
Класс главной формы приложения определяется следующим кодом:
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; WindowArrangeItem: 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; WindowTileHorizontal1: TWindowTileHorizontal; WindowArrangeAll1: TWindowArrange; WindowMinimizeAll1: TWindowMinimizeAll; HelpAbout1: TAction; FileClose1: TWindowClose; WindowTileVertical1: TWindowTileVertical; 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; ImageList1: TImageList; procedure FileNew1Execute(Sender: TObject); procedure FileOpen1Execute(Sender: TObject); procedure HelpAbout1Execute(Sender: TObject); procedure FileExit1Execute(Sender: TObject); end;
Листинг 25.1.
В коде модуля main. pas должно быть указано использование двух других модулей приложения: uses ChildWin, About;.
Процедура создания нового документа или открытия существующего реализована следующим кодом:
{Создать новый документ} 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.CreateMDIChild(const Name: string); var Child: TMDIChild; begin { Класс TMDIChild определен в модуле CHILDWIN.PAS } Child := TMDIChild.Create(Application); {Создание окна} Child.Caption := Name; {Заголовком окна будет имя файла} if FileExists(Name) then // Дочернее окно содержит поле типа TMemo, в которое // выполняется загрузка текстового файла: Child.Memo1.Lines.LoadFromFile(Name); end; Для завершения приложения выполняется следующая процедура: procedure TMainForm.FileExit1Execute(Sender: TObject); begin Close; end; В модуле childwin.pas находится код дочерней формы: type TMDIChild = class(TForm) Memo1: TMemo; {Поле для отображения текста} procedure FormClose(Sender: TObject; var Action: TCloseAction); end; implementation procedure TMDIChild.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caFree; end; end.
Листинг 25.2.
Главная форма приложения описывается следующими свойствами (полужирным шрифтом и курсивом выделены свойства, значения которых не могут быть другими):
object MainForm: TMainForm Caption = 'Приложение с MDI-интерфейсом' FormStyle = fsMDIForm Menu = MainMenu1 WindowMenu = Window1 object StatusBar: TStatusBar AutoHint = True Panels = <> SimplePanel = True end object ToolBar2: TToolBar Images = ImageList1 object ToolButton9: TToolButton Action = FileNew1 {Именованное действие, которое будет выполнено при щелчке на кнопке} end object ToolButton1: TToolButton Action = FileOpen1 end {Кнопки панели инструментов} ...
end object MainMenu1: TMainMenu Images = ImageList1 object File1: TMenuItem Caption = '&File' object FileNewItem: TMenuItem Action = FileNew1 end object FileOpenItem: TMenuItem Action = FileOpen1 end object FileCloseItem: TMenuItem Action = FileClose1 end ... object FileExitItem: TMenuItem Action = FileExit1 end end object Edit1: TMenuItem ... end object Window1: TMenuItem ... end end object OpenDialog: TOpenDialog {Диалог Open} Filter = 'All files (*.*)|*.*' end object ActionList1: TActionList object FileNew1: TAction Category = 'File' Caption = '& New' OnExecute = FileNew1Execute end object FileOpen1: TAction Category = 'File' Caption = '&Open' OnExecute = FileOpen1Execute end ... end end
Листинг 25.3.
Дочерняя форма фактически является обычной формой, в которую помещен один объект типа TMemo (многострочное поле редактирования). Она описывается следующими свойствами:
object MDIChild: TMDIChild FormStyle = fsMDIChild Position = poDefault Visible = True OnClose = FormClose object Memo1: TMemo WordWrap = False end end
После того как макет приложения создан на базе шаблона MDI-приложения, его можно изменять, добавляя новые команды меню и компоненты типа TAction для реализации именованных действий. В проект можно добавлять новые формы и редактировать уже существующие.
Статическое и динамическое подключения DLL-библиотеки
DLL-библиотека может подключаться или статически, или динамически. При подключении DLL-библиотеки она загружается в память приложения.
При статическом подключении DLL-библиотека загружается один раз при запуске приложения.
На всем протяжении выполнения приложения имя функции, импортируемой из DLL-библиотеки, которая была подключена статически, указывает на одну и ту же функцию (точку входа в DLL) в одной и той же DLL.
В отличие от статического подключения DLL-библиотеки, выполняемого в момент загрузки приложения, динамическое подключение может быть выполнено в любой точке выполнения программы. После вызова функции из DLL-библиотеки ее можно отключить. При одновременном использовании нескольких DLL-библиотек это дает ощутимую экономию памяти.
Для динамического подключения DLL-библиотеки применяются функции Windows API. Windows API - это набор стандартных функций, используемый для реализации взаимодействия с операционной системой.
Все функции из статически подключаемой DLL-библиотеки, которые будут использоваться в приложении, первоначально должны быть объявлены как внешние.
При этом следует указать, если требуется, модификатор вызова. Если функция вызывается по индексу, то для нее следует задать имя, используемое в приложении и индекс функции в DLL-библиотеке.
Объявления внешних функций выполняется в секции implementation до использования этих функций.
Объявление внешней функции с ключевым словом external определяет, что будет применено статическое связывание.
Например:
function F1 (i: Integer): Integer; stdcall; external 'MyLib.dll';
При вызове функции из динамически подключаемой DLL-библиотеки, вместо определения имени функции как external, в случае статического связывания, следует определить новый тип, соответствующий типу вызываемой функции, и создать переменную данного типа.
Определение типа функции или процедуры описывается так:
Новый_тип =function(список_параметров):тип_функции; модификатор_доступа; или
Новый_тип=procedure(список_параметров); модификатор доступа;.
Следующий пример иллюстрирует вызов функции из динамически подключаемой DLL-библиотеки:
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button3: TButton; procedure Button3Click(Sender: TObject); end; TMyF1=function( i:Integer):Integer; stdcall; {Создание типа функции} var Form1: TForm1; MyF1 : TMyF1; {Объявление переменной типа функции} implementation {$R *.dfm} procedure TForm1.Button3Click(Sender: TObject); var h: Integer; begin h:=LoadLibrary('MyLib.dll'); // Динамическое подключение if h <> 0 then begin @MyF1:=GetProcAddress(h,'F1'); // Получение адреса функции if @MyF1 <> nil then ShowMessage(IntToStr(MyF1(20)); // Вызов Функции FreeLibrary(h); // Освобождение dll-библиотеки end; end; end.
Блоки прослушивания
В настоящее время в языке Java используется модель ожидаемых событий. В этой модели инициируются только те события, которые были объявлены объектами как ожидаемые.
Объект регистрирует блок прослушивания событий. Блок прослушивания - это интерфейс, который определяет набор методов-обработчиков событий, объявленных как ожидаемые события.
Регистрация блока прослушивания для компонента состоит в вызове метода, начинающегося с префикса add, за которым идет имя блока прослушивания. Имена блоков прослушивания оканчиваются суффиксом Listener.
Для одного компонента можно зарегистрировать только один блок прослушивания. Но один блок прослушивания может использоваться несколькими компонентами одновременно.
Для того, чтобы компонент мог обрабатывать поступающие для него события, следует:
при объявлении класса указать наследуемые этим классом интерфейсы, содержащие методы-обработчики событий;добавить блоки прослушивания для компонентов; все методы-обработчики, объявленные в наследуемом интерфейсе, реализовать в классе компонента.
Любой метод блока прослушивания имеет один параметр - объект, производный от класса EventObject.
В классе EventObject определен метод Object getSource(), возвращающий объект, который инициировал событие. Некоторые классы, производные от EventObject, имеют свои методы, которые определяют объект, инициировавший событие. Например, класс ComponentEvent определяет метод getComponent, возвращающий объект Component.
Блоки прослушивания пакета JDK
Пакет java.util содержит интерфейс EventListener, который наследуется всеми блоками прослушивания.
Для различных классов компонентов предназначаются разные интерфейсы блоков прослушивания.
В следующей таблице приведены некоторые интерфейсы блоков прослушивания, наследуемые от интерфейса EventListener.
Action | javax.swing | Расширяет интерфейс ActionListener, позволяя нескольким компонентам использовать одни и те же обработчики событий |
ActionListener | java.awt.event | Этот блок прослушивания регистрируется методом addActionListener. При возникно- вении события "действие" вызывается метод actionPerformed(ActionEvent e) компонента, зарегистрировавшего данный блок прослушивания. Интерфейс исполь- зуется для обработки событий меню, кнопок и т.п. |
AdjustmentListener | java.awt.event | Используется для получения регулируемых событий |
AncestorListener | javax.swing.event | Интерфейс поддерживает уведомления при изменении компонента класса JComponent или одного из его предков. Это касается перемещения компонента, перехода из видимого состояния в неви димое или обратно, выполнения метода setVisible(), а также при добавлении и удалении компонентов из иерархии |
CaretListener | javax.swing.event | Используется при изменении позиции ввода в текстовых компонентах. Этот интерфейс реализован классом javax.swing.text.JTextComponent.AccessibleJTextComponent |
CaretListener | javax.swing.event | Используется при изменении позиции ввода в текстовых компонентах. Этот интерфейс реализован классом javax.swing.text.JTextComponent.AccessibleJTextComponent |
CellEditorListener | javax.swing.event | Используется для отслеживания изме нений в редактируемой ячейке (CellEditor), касающихся завершения или отмены редактирования. Этот интерфейс реализован следующими классами: JTable, JTable.AccessibleJTable, BasicTreeUI.CellEditorHandler |
ChangeListener | javax.swing.event | Определяет объект, выполняющий прослушивание событий ChangeEvent. Интерфейс объявляет всего один метод: void stateChanged(ChangeEvent e). Этот интерфейс реализован несколькими классами, включая: JMenuItem.AccessibleJMenuItem, BasicButtonListener, JTabbedPane.AccessibleJTabbedPane. |
ContainerListener | java.awt.event | Интерфейс объявляет два метода: public void componentAdded(ContainerEvent e) и public void componentRemoved(ContainerEvent e), вызываемые при добавлении компонента в контейнер или при удалении из контейнера. Для этого интерфейса реализован класс-адаптер ContainerAdapter |
DocumentListener | javax.swing.event | Интерфейс используется при изменении текстового документа |
DragGestureListener | java.awt.dnd | Интерфейс используется при инициа- лизации процесса перетаскивания объекта |
DragSourceListener | java.awt.dnd | Интерфейс используется для реализации механизма перетаскивания и сброса- объектов (Drag & Drop). В этот интер- фейсе объявлены методы для отслежи- вания действий пользователя по пере- мещению объекта. Этот интерфейс реализован классом DragSourceContext |
DropTargetListener | java.awt.dnd | Интерфейс может быть использован для обработки событий, инициируемых в то время, когда объект находится над местом сброса |
FocusListener | java.awt.event | Интерфейс используется для обработки событий получения или потери фокуса компонентом. Блок прослушивания регистрируется методом addFocusListener. Для этого интерфейса реализован класс адаптер FocusAdapter |
ItemListener | java.awt.event | Интерфейс используется для обработки события выделения элемента и объяв- ляет только один метод public void itemStateChanged(ItemEvent e). Блок прослушивания регистрируется методом addItemListener |
KeyListener | java.awt.event | Интерфейс используется для обработки событий от клавиатуры. Блок прослу- шивания регистрируется методом addKeyListener. Для интерфейса реали- зован класс-адаптер KeyAdapter |
ListSelectionListener | javax.swing.event | Используется для обработки события, инициирующегося при изменении области выделения |
MenuDragMouseListener | javax.swing.event | Интерфейс объявляет четыре метода обработчика событий, инициируемых при перемещении и сбросе в области компонентов меню |
MenuKeyListener | javax.swing.event | Интерфейс используется для обработки событий, инициируемых для меню при вводе комбинаций клавиш |
MenuListener | javax.swing.event | Определяет блок прослушивания с обработчиками событий для меню |
MouseInputListener | javax.swing.event | Интерфейс наследует интерфейсам MouseMotionListener (методы: mouseDragged, mouseMoved) и MouseListener (методы: mouseClicked, mouseEntered, mouseExited, mousePressed, mouseReleased). Этот интерфейс используется для обработки любых событий, инициируемых действиями мыши |
MouseListener | java.awt.event | Интерфейс, используемый для обработки событий от щелчков мышью. Блок прослушивания регистрируется методом addMouseListener. Для интерфейса реализован класс-адаптер MouseAdapter |
MouseMotionListener | java.awt.event | Интерфейс, используемый для обработки событий от перемещения курсора мыши. Блок прослушивания регистри руется методом addMouseMotionListener. Для интерфейса реализован класс-адаптер MouseMotionAdapter. |
PopupMenuListener | javax.swing.event | Интерфейс определяет методы блока прослушивания для всплывающих меню (popup-меню). |
PropertyChangeListener | java.beans | Интерфейс определяет метод обработчик события, вызываемый при изменении свойства бина |
TableColumnModelListener | javax.swing.event | Интерфейс, используемый для прослу шивания событий, изменяющих TableColumnModel. К таким событиям относятся добавление, удаление, изменение размера и перемещение столбца таблицы. Этот интерфейс реализован классами JTable, JTable.AccessibleJTable и JTableHeader |
TableModelListener | javax.swing.event | Интерфейс, используемый для прослу шивания событий, которые изменяют TableModel |
TextListener | java.awt.event | Интерфейс объявляет метод void textValueChanged(TextEvent e), вызываемый при изменении значения текстовых компонентов, таких, как TextArea, TextField |
TreeExpansionListener | javax.swing.event | Интерфейс, используемый для прослу шивания событий распахивания или сворачивания дерева |
TreeModelListener | javax.swing.event | Интерфейс, используемый для прослу шивания событий, которые изменяют TreeModel |
TreeSelectionListener | javax.swing.event | Интерфейс объявляет метод, вызываемый при изменении выделенного элемента дерева |
WindowListener | java.awt.event | Интерфейс используется для обработки событий окна. Блок прослушивания регистрируется методом addWindowListener. Для интерфейса реализован класс-адаптер WindowAdapter |
Классы-адаптеры
Чтобы зарегистрировать блок прослушивания, нужно указать его в объявлении класса как наследуемый. В результате этого класс, наследующий данный интерфейс, должен содержать код реализации всех объявленных в интерфейсе методов. Если таких методов много, а нужен только один, то все равно приходится включать код реализации каждого объявленного в интерфейсе метода. Альтернативой такому подходу служит применение классов адаптеров.
Класс-адаптер для интерфейса блока прослушивания содержит "пустую" реализацию всех его методов. Таким образом, при создании класса, как производного от класса-адаптера, в качестве блока прослушивания можно указывать класс-адаптер и включать реализацию только необходимых методов.
На следующей схеме приведен пример обработки события "щелчок мышью" двумя способами: с применением интерфейса блока прослушивания и с применением адаптера блока прослушивания.
public class MyClass implements MouseListener { ... myObject.addMouseListener(this); ... /* Реализация всех методов интерфейса MouseListener */ public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mouseClicked(MouseEvent e) { ...// Код метода } } |
public class MyClass extends MouseAdapter { ... myObject.addMouseListener(this); ... /* Переопределение только одного метода адаптера MouseAdapter */ public void mouseClicked(MouseEvent e) } ...// Код переопределяемого метода } } |
Приведенный выше пример в практическом плане имеет один недостаток. При программировании классы приложений в большинстве случаев создаются как производные от классов Frame, Panel, JFrame, а классы апплетов - от класса Applet или JApplet. Но в языке Java реализовано только простое наследование, позволяющее иметь всего один наследуемый класс.
Поэтому, чтобы применять классы-адаптеры, можно использовать два способа реализации:
использование внутренних классов: public class MyClass extends Applet { ... // Создание объекта класса адаптера: myObject.addMouseListener(new MyClassAdapter()); ...
class MyClassAdapter extends MouseAdapter {//Объявление // внутреннего класса адаптера public void mouseClicked(MouseEvent e) { ... } // Реализация методов класса адаптера } }
использование анонимных внутренних классов:
public class MyClass extends Applet { ... // Создание объекта и реализация класса адаптера: myObject.addMouseListener(new MouseAdapter() { // Реализация переопределяемых методов класса адаптера public void mouseClicked(MouseEvent e) { } }); } }
Для того чтобы реализовать применение класса-адаптера с использованием вложенного класса, следует:
добавить блок прослушивания компонента и указать в качестве параметра код new имя_внутреннего_класса (например, addMouseListener(new MouseAdapter() ); добавить код с объявлением внутреннего класса, включающий реализацию требуемых методов обработчиков событий (например, class MyClassAdapter extends MouseAdapter { public void mouseClicked(MouseEvent e) { ѕ }}.)
Для того чтобы реализовать применение класса адаптера с использованием вложенного анонимного класса-адаптера, следует:
добавить блок прослушивания компонента и указать в качестве параметра код new имя_класса_адаптера { } (например, addMouseListener(new MyClassAdapter(){ }); вставить в фигурные скобки после имени класса адаптера код переопределяемых методов (например, { public void mouseClicked(MouseEvent e) { ѕ }}).
Использование анонимных вложенных классов значительно улучшает читаемость кода.
События действия
Событие действия - это семантические событие, зависящее от типа компонента. Так, для командной кнопки событием действия будет щелчок мышью или нажатие клавиши Enter в момент, когда кнопка имеет фокус. Для компонентов типа "список" событием действия является выбор элемента, для компонентов "меню" - выбор пункта меню, а для компонентов "текстовое поле" - нажатие клавиши Enter.
События действия определяются в интерфейсе ActionListener. Этот интерфейс задает единственный метод обработки события actionPerformed, вызываемый при возникновении для компонента сооответствующего его типу события действия.
Для того чтобы обрабатывать событие действия, можно выполнить следующее:
Создать класс, наследующий интерфейс ActionListener. Например:
public class MyFrame extends Frame implements ActionListener { }.
Зарегистрировать блок прослушивания события действия для компонента. Например:
myButton.addActionListener(this).
Переопределить метод actionPerformed: Например:
public void actionPerformed(ActionEvent e) { Toolkit.getDefaultToolkit().beep(); }.
Метод обработки события действия получает параметр типа ActionEvent.
Класс ActionEvent определен в иерархии классов Java следующим образом:
Класс ActionEvent определяет и наследует несколько полезных методов, включая следующие:
GetActionCommand - метод возвращает строку, ассоциируемую с данным событием действия. Если для объекта был ранее вызван метод setActionCommand, устанавливающий такую строку, то эта строка и будет возвращена. В противном случае, возвращаемое значение зависит от типа компонента/GetModifiers - возвращает число, определяющее, была ли нажата клавиша-модификатор при возникновении события действия. Для определения кода нажатой клавиши-модификатора можно использовать константы SHIFT_MASK, CTRL_MASK и ALT_MASK.Например, если при возникновении события действия была нажата клавиша Shift, то следующее выражение не будет равно нулю:
actionEvent.getModifiers() & ActionEvent. SHIFT_MASK.
getSource - метод возвращает объект, для которого было инициировано событие.
События окна
Методы - обработчики событий окна объявляются в интерфейсе WindowListener . Для данного интерфейса существует класс адаптер WindowAdapter .
Для того чтобы отслеживать все события окна, можно создать класс окна, наследуемый от интерфейса WindowListener.
Например:
public class MyWindowListener extends Frame implements WindowListener { public void windowClosing(WindowEvent e) { } public void windowClosed(WindowEvent e) { } public void windowOpened(WindowEvent e) { } public void windowIconified(WindowEvent e) { } public void windowDeiconified(WindowEvent e) { } public void windowActivated(WindowEvent e) { } public void windowDeactivated(WindowEvent e) { } }
Если надо отслеживать все события окна приложения или апплета, то блок прослушивания следует добавить для объекта this/.
Например:
addWindowListener(this);
Если надо отслеживать все события окна, создаваемого в процессе выполнения приложения или апплета, то сначала надо создать объект "окно", а затем добавить для него блок прослушивания.
Например:
myFrame = new Frame("Заголовок окна"); myFrame.addWindowListener(this);
Интерфейс WindowListene объявляет следующие методы, вызываемые для события WindowEvent:
WindowActivated - метод обработки события, вызываемый при активизации окна пользователем.WindowClosed - метод обработки события, вызываемый при закрытии окна вследствии вызова метода dispose(), который освобождает ресурсы экрана.WindowClosing - метод обработки события, вызываемый при закрытии окна пользователем с помощью системного меню.WindowDeactivated - метод обработки события, вызываемый при потери окном фокуса.windowDeiconified - метод обработки события, вызываемый при изменении состояния окна из свернутого в нормальное.windowIconified - метод обработки события, вызываемый при изменении состояния окна из нормального в свернутое.windowOpened- метод вызывается один раз при открытии окна.
События от клавиатуры
Методы обработчики событий от клавиатуры объявляются в интерфейсе KeyListener, для которого существует класс адаптер KeyAdapter.
Событие от клавиатуры происходит для компонента, имеющего фокус. События от клавиатуры являются низкоуровневыми событиями.
Интерфейс KeyListener объявляет следующие методы обработчики для события KeyEvent:
o void keyTyped(KeyEvent e); // Ввод символа o void keyPressed(KeyEvent e); // Нажатие клавиши o void keyReleased(KeyEvent e) // Отпускание клавиши
Для получения информации о коде нажатой клавиши следует использовать методы класса KeyEvent.
Класс KeyEvent определен в иерархии классов Java следующим образом:
При нажатии или отпускании клавиши метод getKeyCode возвращает значение кода нажатой клавиши.
Метод getKeyChar возвращает значение символа Unicode или CHAR_UNDEFINED.
При обработки события ввода (метод void keyTyped(KeyEvent e) ) можно получить значение введенного с клавиатуры символа в формате Unicode или CHAR_UNDEFINED.
Клавиатурные комбинации обрабатываются в методах:
void keyPressed(KeyEvent e) иvoid keyReleased(KeyEvent e)
Например, нажатие клавиш Shift+B можно отследить в методе keyPressed (событие KEY_PRESSED): при первом вызове метода будет возвращен код клавиши Shift - VK_SHIFT, а при втором вызове метода - код клавиши A - VK_B. И только затем произойдет вызов метода keyTyped.
На следующей схеме приведен алгоритм обработки событий от клавиатуры.
Shift+A | keyPressed | getKeyChar()
getKeyCode() getModifiers() | символ = ' '
код = 16 (Shift) модификатор = 1 | ||
keyPressed | getKeyChar()
getKeyCode() getModifiers() | символ ='B'
код = 66(B) модификатор = 1 | |||
keyTyped | getKeyChar()
getKeyCode() getModifiers() | символ ='B'
код = 0 модификатор = 0 | |||
keyReleased | getKeyChar()
getKeyCode() getModifiers() | символ ='A'
код = 66(B) модификатор = 0 | |||
keyReleased | getKeyChar()
getKeyCode() getModifiers() | символ = ' '
код = 16 (Shift) модификатор = 0 |
В классе KeyEvent определены виртуальные коды для всех клавиш клавиатуры. К таким кодам относятся:
Коды цифр: от VK_0 до VK_9 ( ASCII-коды цифр от '0' до '9' (0x30 - 0x39)).Коды букв: от VK_A до VK_Z (ASCII-коды букв от 'A' до 'Z' (0x41 - 0x5A)).Коды NUMPAD-клавиатуры: от VK_NUMPAD0 до VK_NUMPAD9.Коды управляющих и функциональных клавиш: от VK_F1 до VK_F24, VK_NUM_LOCK, VK_PRINTSCREEN, VK_INSERT, VK_HELP, VK_DELETE, VK_ENTER, VK_BACK_SPACE, VK_TAB, VK_CANCEL, VK_CAPS_LOCK, VK_ESCAPE, VK_SPACE, VK_PAUSE.Коды перемещения позиции: VK_PAGE_UP, VK_PAGE_DOWN, VK_END, VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN.Коды-модификаторы: VK_SHIFT, VK_ALT, VK_CONTROL.Коды символов: VK_DOLLAR, VK_COMMA, VK_MINUS, VK_PERIOD, VK_SLASH, VK_SEMICOLON, VK_EQUALS, VK_OPEN_BRACKET (открывающая скобка), VK_BACK_SLASH (обратный слэш), VK_CLOSE_BRACKET (закрывающая скобка).
Класс KeyEvent содержит следующий набор методов, предназначенных для определения кодов нажатых клавиш:
GetKeyChar - возвращает символ Unicode, соответствующий нажатой клавиши, с учетом регистра и языка клавиатуры.GetKeyCode - возвращает код нажатой клавиши.GetKeyModifiersText - возвращает строку, содержащую описание кода-модификатора (например, "Ctrl+Shift").GetKeyText - возвращает строку, содержащую описание кода (например, "F1", "PageUp" или "D").IsActionKey - определяет, была ли нажата клавиша action-ключа, такая, как PGUP, PGDN, F1, F2 и т.п.ParamString - возвращает строку параметров, определяющих данное событие.SetKeyChar - устанавливает значение, равное значению символа Unicode.SetKeyCode - устанавливает значение, равное значению кода клавиши.SetModifiers - устанавливает значение кода модификатора.SetSource- определяет источник события KeyEvent.
Наряду с описанными методами, можно использовать методы, наследуемые от класса java.awt.event.InputEvent, включая следующие:
boolean isAltDown() // Нажата клавиша Altboolean isShiftDown() // Нажата клавиша Shiftboolean isControlDown() // Нажата клавиша Ctrl
Типы событий
Событием в языке Java является объект. Все события можно разделить на две группы: события низкого уровня и семантические события.
К событиям низкого уровня относятся:
события от клавиатуры и мыши;события от окна Windows;события от компонента;события от контейнера;события от перемещения фокуса ввода.
Семантические события являются событиями верхнего уровня и зависят от инициировавшего их компонента. Одно и то же семантическое событие может быть инициировано разными компонентами в ответ на различные действия пользователя. Семантическое событие можно рассматривать как более сложное событие, состоящее из одного или нескольких событий низкого уровня. Примером может служить событие MenuEvent, инициируемое при выборе пункта меню.
public class Frame1 extends JPanel
import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Frame1 extends JPanel { JSplitPane jSplitPane1 = new JSplitPane(); // Класс // разделяемых панелей JScrollPane jScrollPane1 = new JScrollPane(); JScrollPane jScrollPane2 = new JScrollPane(); JTextPane jTextPane1 = new JTextPane(); JTextPane jTextPane2 = new JTextPane(); public Frame1() { try { jbInit(); } catch(Exception e) { } } public static void main(String s[]) { JFrame frame = new JFrame("Панели"); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setContentPane(new Frame1()); frame.pack(); frame.setVisible(true); } private void jbInit() throws Exception { // Определение ориентации разделяемых панелей jSplitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT); // Размещение левого и правого компонента // на разделяемой панели jSplitPane1.setLeftComponent(jScrollPane1); jSplitPane1.setRightComponent(jScrollPane2); // Отображение кнопок сворачивания и разворачивания // сторон разделяемой панели jSplitPane1.setOneTouchExpandable(true); // Задание размера панелей jScrollPane1.setPreferredSize(new Dimension(300, 60)); jScrollPane2.setPreferredSize(new Dimension(300, 60)); // Добавление разделяемой панели к окну формы this.add(jSplitPane1, null); // Добавление компонентов в контейнеры // типа JScrollPane jScrollPane1.getViewport().add(jTextPane1, null); jScrollPane2.getViewport().add(jTextPane2, null); } } |
Листинг 27.1. |
Закрыть окно |
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Frame1 extends JPanel {
JSplitPane jSplitPane1 = new JSplitPane(); // Класс
// разделяемых панелей
JScrollPane jScrollPane1 = new JScrollPane();
JScrollPane jScrollPane2 = new JScrollPane();
JTextPane jTextPane1 = new JTextPane();
JTextPane jTextPane2 = new JTextPane();
public Frame1() { try { jbInit(); }
catch(Exception e) { } }
public static void main(String s[]) {
JFrame frame = new JFrame("Панели");
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0); } });
frame.setContentPane(new Frame1());
frame.pack();
frame.setVisible(true);
}
private void jbInit() throws Exception {
// Определение ориентации разделяемых панелей
jSplitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT);
// Размещение левого и правого компонента
// на разделяемой панели
jSplitPane1.setLeftComponent(jScrollPane1);
jSplitPane1.setRightComponent(jScrollPane2);
// Отображение кнопок сворачивания и разворачивания
// сторон разделяемой панели
jSplitPane1.setOneTouchExpandable(true);
// Задание размера панелей
jScrollPane1.setPreferredSize(new Dimension(300, 60));
jScrollPane2.setPreferredSize(new Dimension(300, 60));
// Добавление разделяемой панели к окну формы
this.add(jSplitPane1, null);
// Добавление компонентов в контейнеры
// типа JScrollPane
jScrollPane1.getViewport().add(jTextPane1, null);
jScrollPane2.getViewport().add(jTextPane2, null);
}
}
public class MyApplet extends Applet
import java.applet.Applet; import java.awt.*; public class MyApplet extends Applet { Panel panel1 = new Panel(); GridLayout gridLayout1 = new GridLayout(); // Создание новой кнопки: Checkbox checkbox1 = new Checkbox(); Checkbox checkbox2 = new Checkbox(); GridLayout gridLayout2 = new GridLayout(); Panel panel2 = new Panel(); // Создание группы кнопок: CheckboxGroup checkboxGroup1 = new CheckboxGroup(); Checkbox checkbox4 = new Checkbox(); Checkbox checkbox5 = new Checkbox(); Checkbox checkbox6 = new Checkbox(); FlowLayout FlowLayout1 = new FlowLayout(); public MyApplet() { try { jbInit(); } catch(Exception e) { } } public static void main(String[] args) { MyApplet myApplet1 = new MyApplet(); } private void jbInit() throws Exception { setLayout(gridLayout2); panel1.setLayout(gridLayout1); checkbox1.setLabel("Флажок 1"); checkbox2.setLabel("Флажок 2"); checkbox2.setState(true); // Состояние флажка - // включен gridLayout2.setRows(2); panel2.setLayout(FlowLayout1); // Добавление в группу трех кнопок: checkbox4.setCheckboxGroup(checkboxGroup1); checkbox4.setLabel("Радиокнопка 1"); checkbox4.setState(true); // Состояние радиокнопки - // включена checkbox5.setCheckboxGroup(checkboxGroup1); checkbox5.setLabel("Радиокнопка 2"); checkbox6.setCheckboxGroup(checkboxGroup1); checkbox6.setLabel("Радиокнопка 3"); // Добавление кнопок в контейнеры - панели this.add(panel1, null); panel1.add(checkbox1, null); panel1.add(checkbox2, null); this.add(panel2, null); panel2.add(checkbox4, null); panel2.add(checkbox5, null); panel2.add(checkbox6, null); } } |
Листинг 27.2. |
Закрыть окно |
import java.applet.Applet;
import java.awt.*;
public class MyApplet extends Applet {
Panel panel1 = new Panel();
GridLayout gridLayout1 = new GridLayout();
// Создание новой кнопки:
Checkbox checkbox1 = new Checkbox();
Checkbox checkbox2 = new Checkbox();
GridLayout gridLayout2 = new GridLayout();
Panel panel2 = new Panel();
// Создание группы кнопок:
CheckboxGroup checkboxGroup1 = new CheckboxGroup();
Checkbox checkbox4 = new Checkbox();
Checkbox checkbox5 = new Checkbox();
Checkbox checkbox6 = new Checkbox();
FlowLayout FlowLayout1 = new FlowLayout();
public MyApplet() {
try { jbInit(); } catch(Exception e) { }
}
public static void main(String[] args) {
MyApplet myApplet1 = new MyApplet(); }
private void jbInit() throws Exception {
setLayout(gridLayout2);
panel1.setLayout(gridLayout1);
checkbox1.setLabel("Флажок 1");
checkbox2.setLabel("Флажок 2");
checkbox2.setState(true); // Состояние флажка -
// включен
gridLayout2.setRows(2);
panel2.setLayout(FlowLayout1);
// Добавление в группу трех кнопок:
checkbox4.setCheckboxGroup(checkboxGroup1);
checkbox4.setLabel("Радиокнопка 1");
checkbox4.setState(true); // Состояние радиокнопки -
// включена
checkbox5.setCheckboxGroup(checkboxGroup1);
checkbox5.setLabel("Радиокнопка 2");
checkbox6.setCheckboxGroup(checkboxGroup1);
checkbox6.setLabel("Радиокнопка 3");
// Добавление кнопок в контейнеры - панели
this.add(panel1, null);
panel1.add(checkbox1, null);
panel1.add(checkbox2, null);
this.add(panel2, null);
panel2.add(checkbox4, null);
panel2.add(checkbox5, null);
panel2.add(checkbox6, null);
}
}
к элементам списка через модель
String[] data = {"один", "два", "три"}; // Массив строк JList jList1 = new JList(data); // Создание списка, // содержащего массив строк // Доступ к элементам списка через модель for(int i = 0; i<jList1.getModel().getSize(); i++) { System.out.println(jList1.getModel().getElementAt(i)); } // Заполнение списка данными, представляемыми классом Vector JList jList1 = new JList(); Vector superClasses = new Vector(); Class rootClass = javax.swing.JList.class; // Создание объекта // типа Class for(Class cls = rootClass; cls != null; cls = cls.getSuperclass()) { // Получение всех подклассов superClasses.addElement(cls); } jList1.setListData(superClasses); // Заполнение компонента jList1 // списком всех его подклассов // Добавление элементов в список, хранимый в объекте типа Vector superClasses.addElement(new String("12345")); // Выделение элементов списка: jList1.setSelectedIndex(1); // Выделение второго элемента списка jList1.getSelectedValue(); // Возвращает строку, отображаемую //во втором элементе списка |
Листинг 27.3. |
Закрыть окно |
String[] data = {"один", "два", "три"}; // Массив строк
JList jList1 = new JList(data); // Создание списка,
// содержащего массив строк
// Доступ к элементам списка через модель
for(int i = 0; i
System.out.println(jList1.getModel().getElementAt(i)); }
// Заполнение списка данными, представляемыми классом Vector
JList jList1 = new JList();
Vector superClasses = new Vector();
Class rootClass = javax.swing.JList.class; // Создание объекта
// типа Class
for(Class cls = rootClass; cls != null;
cls = cls.getSuperclass())
{ // Получение всех подклассов
superClasses.addElement(cls); }
jList1.setListData(superClasses); // Заполнение компонента jList1
// списком всех его подклассов
// Добавление элементов в список, хранимый в объекте типа Vector
superClasses.addElement(new String("12345"));
// Выделение элементов списка:
jList1.setSelectedIndex(1); // Выделение второго элемента списка
jList1.getSelectedValue(); // Возвращает строку, отображаемую
//во втором элементе списка
Класс BorderLayout
Менеджер компоновки BorderLayout разбивает контейнер на пять областей и располагает добавляемые в контейнер объекты по краям (север, юг, запад, восток) и в центре.
Каждая область указывается соответствующей константой: NORTH, SOUTH, EAST, WEST и CENTER. Если в методе add отсутствует строка, указывающая расположение компонента, то по умолчанию используется значение CENTER.
На рис. 27.1. приведен внешний вид, реализуемый менеджером компоновки BorderLayout для пяти кнопок, которые расположены в контейнере - апплете.
Рис. 27.1. Менеджер компоновки BorderLayout
Следующий код иллюстрирует использование компоновки BorderLayout:
import java.applet.Applet; import java.awt.*; public class MyApplet extends Applet { public MyApplet() { try { jbInit();} catch(Exception e) { } } public static void main(String[] args) { MyApplet myApplet1 = new MyApplet(); } private void jbInit() throws Exception { setLayout(new BorderLayout()); add(new Button("North"), BorderLayout.NORTH); add(new Button("South"), BorderLayout.SOUTH); add(new Button("East"), BorderLayout.EAST); add(new Button("West"), BorderLayout.WEST); add(new Button("Center"), BorderLayout.CENTER); } }
Класс BorderLayout предоставляет ряд методов, включая следующие:
GetHgap - возвращает расстояние в пикселях между компонентами по горизонтали.SetHgap - устанавливает расстояние в пикселях между компонентами по горизонтали.GetVgap - возвращает расстояние в пикселях между компонентами по вертикали.SetVgap - устанавливает расстояние в пикселях между компонентами по вертикали.
Класс CardLayout
Класс CardLayout определяет менеджер компоновки для контейнера, который может содержать несколько страниц ("карт") и для которого одновременно может быть видна только одна карта.
Класс CardLayout предоставляет ряд методов, включая следующие:
GetHgap- определяет отступ по горизонтали.GetVgap - определяет отступ по вертикали.First - активизирует первую страницу контейнера.Last - активизирует последнюю страницу контейнера.Next - активизирует следующую страницу контейнера в циклическом порядке (после последней карты активизируется первая карта).Previous - активизирует предыдущую страницу контейнера в циклическом порядке.Show - активизирует компонент указанного контейнера.
Например:
// Для контейнера типа JPanel void jButton1_actionPerformed(ActionEvent e) { ((CardLayout)jPanel1.getLayout()).next(jPanel1); } // Для контейнера типа Panel void button1_actionPerformed(ActionEvent e) { cardLayout1.next(panel1); }
Класс FlowLayout
Менеджер компоновки FlowLayout размещает добавляемые в контейнер компоненты последовательно слева направо. Компоненты могут быть размещены в нескольких последовательных рядах.
На рис. 27.2 приведены два результата применения этой компоновки при изменении размеров контейнера.
Рис. 27.2. Применение компоновки FlowLayout
Класс FlowLayout предоставляет следующие константы, определяющие выравнивание компонентов:
CENTER - по центру.LEFT - по левому краю.RIGHT - по правому краю.
Класс FlowLayout предоставляет ряд методов, включая следующие:
SetAlignment - устанавливает выравнивание компонентов для данной компоновки. Параметр метода может принимать следующие значения: FlowLayout.LEFT, FlowLayout.RIGHT и FlowLayout.CENTER.GetHgap - определяет расстояние между компонентами по горизонтали.SetHgap - устанавливает расстояние между компонентами по горизонтали.GetVgap - определяет расстояние между компонентами по вертикали.SetVgap- устанавливает расстояние между компонентами по вертикали.
Класс GridBagLayout
Этот класс используется менеджером компоновки GridBagLayout и определяет требования к размещению компонентов.
Компоновка GridBagLayout позволяет размещать компоненты в ячейках таблицы. Но, в отличие от менеджера компоновки GridLayout, ячейки таблицы могут различаться как по ширине, так и по высоте. Размещаемые компоненты могут занимать несколько ячеек.
Область, занимаемая компонентом, называется областью отображения. Ее размеры определяются значениями переменных gridwidth и gridheight (количество ячеек по горизонтали и по вертикали) класса GridBagConstraints.
Отступами (insets) называется расстояние между областью отображения и действительной областью, занимаемой компонентом.
На рис. 27.4 приведен пример компоновки, в которой кнопка 3 занимает 9 ячеек, но размер кнопки меньше размера области отображения.
Рис. 27.4. Отступы, устанавливаемые объектом GridBagConstraints
Если область отображения отличается от размера компонента, то для определения требований к размещению используется переменная fill.
Если размер размещаемого компонента меньше размера области отображения, то для указания размещения компонента используется переменная anchor, которая может принимать одно из следующих значений:
GridBagConstraints.CENTER GridBagConstraints.NORTHGridBagConstraints.NORTHEASTGridBagConstraints.EASTGridBagConstraints.SOUTHEASTGridBagConstraints.SOUTHGridBagConstraints.SOUTHWESTGridBagConstraints.WESTGridBagConstraints.NORTHWEST.
Переменная fill класса GridBagConstraint определяет, следует ли изменять размер компонента, и может принимать следующие значения:
GridBagConstraint.NONE - размер компонента не изменять (значение, используемое по умолчанию); GridBagConstraint.HORIZONTAL - изменить размер по горизонтали, но не изменять его высоту; GridBagConstraint.VERTICAL - изменить размер по вертикали, но не изменять его ширину; GridBagConstraint.BOTH - увеличить размеры компонента до размера области отображения.
Переменные gridheight и gridwidthкласса GridBagConstraint определяют число ячеек в столбце или строке соответственно. При этом константа GridBagConstraints.REMAINDER указывает, что компонент будет последним в столбце (строке), а константа GridBagConstraints.RELATIVE указывает, что компонент будет ближайшим к последнему.
Конструктор GridBagConstraints(int gridx, int gridy, int gridwidth, int gridheight, double weightx, double weighty, int anchor, int fill, Insets insets, int ipadx, int ipady) создает объект требований к размещению компонента, используемый менеджером компоновки, со всеми полями, имеющими заданные значения.
Класс GridLayout
Этот класс позволяет размещать компоненты в контейнере в виде таблицы. В каждой ячейке таблицы может быть размещен только один компонент.
Размер всех ячеек таблицы одинаков. Количество строк и столбцов таблицы определяется или в конструкторе, или вызовом методов setColumns и setRows. При этом, если эти значения не равны нулю, то количество столбцов является величиной вычисляемой и зависит от общего числа компонентов, добавленных на компоновку, и указанного числа строк. И только в том случае, если количество строк задано равным нулю, заданное количество столбцов будет учитываться менеджером компоновки.
На рис. 27.3 приведены примеры использования компоновки GridLayout.
Рис. 27.3. Пример компоновки GridLayout
Для компоновки GridLayout следует определять или количество строк, или количество столбцов.
Например:
this.setLayout(gridLayout1); gridLayout1.setRows(3);
Кнопки
Кнопки могут располагаться в контейнере как отдельно, так и в группе.
Пакет java.awt содержит следующие классы кнопок и групп:
Button - командная кнопка.Checkbox - флажок или радиокнопка (переключатель).CheckboxGroup - группа кнопок.
Пакет облегченных swing-компонентов также предоставляет несколько классов кнопок и групп, включая следующие классы:
JButton - кнопка.JRadioButton - радиокнопка.JToggleButton - кнопка-переключатель.JCheckBox - флажокButtonGroup - группа кнопок.
На кнопках из пакета javax.swing помимо метки может также отображаться и пиктограмма.
Класс Button позволяет создавать объекты "командные кнопки". При нажатии на кнопку JVM инициирует событие действия actionPerformed. Наряду с данным семантическим событием, инициируется ряд простых событий, таких как mouseClicked.
Класс Button предоставляет ряд методов, включая следующие:
AddActionListener - регистрирует блок прослушивания для события действия от командной кнопки;GetActionCommand - возвращает имя команды, инициировавшей событие действия, или метку кнопки, если имя команды равно null (значение по умолчанию);GetLabel - возвращает метку командной кнопки или null для непомеченной командной кнопки;SetLabel - изменяет метку командной кнопки.
Класс Checkbox позволяет создавать компоненты кнопки двух типов, называемые флажками и радиокнопками. Такой компонент может иметь два состояния: включено (true) и выключено (false). Каждый щелчок на компоненте изменяет его состояние на обратное.
Несколько переключателей могут быть объединены в группу, используя компонент CheckboxGroup, являющийся контейнером. Такая группа называется группой радиокнопок. Только один компонент группы может одновременно иметь состояние "включен".
Для обработки событий от кнопки используется интерфейс ItemListener. Этот интерфейс определяет всего один обработчик события - метод itemStateChanged (ItemEvent e).
Класс ItemEvent содержит метод getStateChange, позволяющий определить состояние кнопки. Метод может возвращать одно из двух возможных значений:
ItemEvent.SELECTED;ItemEvent.DESELECTED.
Например:
// Определение состояния кнопки void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { // Кнопка находится во включенном состоянии } }
Для добавления кнопки в группу для нее следует вызвать метод setCheckboxGroup, указав в качестве параметра объект типа CheckboxGroup.
Следующий листинг иллюстрирует создание флажков и группы радиокнопок:
import java.applet.Applet; import java.awt.*; public class MyApplet extends Applet { Panel panel1 = new Panel(); GridLayout gridLayout1 = new GridLayout(); // Создание новой кнопки: Checkbox checkbox1 = new Checkbox(); Checkbox checkbox2 = new Checkbox();
GridLayout gridLayout2 = new GridLayout(); Panel panel2 = new Panel(); // Создание группы кнопок: CheckboxGroup checkboxGroup1 = new CheckboxGroup(); Checkbox checkbox4 = new Checkbox(); Checkbox checkbox5 = new Checkbox(); Checkbox checkbox6 = new Checkbox(); FlowLayout FlowLayout1 = new FlowLayout(); public MyApplet() { try { jbInit(); } catch(Exception e) { } } public static void main(String[] args) { MyApplet myApplet1 = new MyApplet(); } private void jbInit() throws Exception { setLayout(gridLayout2); panel1.setLayout(gridLayout1); checkbox1.setLabel("Флажок 1"); checkbox2.setLabel("Флажок 2"); checkbox2.setState(true); // Состояние флажка - // включен gridLayout2.setRows(2); panel2.setLayout(FlowLayout1); // Добавление в группу трех кнопок: checkbox4.setCheckboxGroup(checkboxGroup1); checkbox4.setLabel("Радиокнопка 1"); checkbox4.setState(true); // Состояние радиокнопки - // включена checkbox5.setCheckboxGroup(checkboxGroup1); checkbox5.setLabel("Радиокнопка 2"); checkbox6.setCheckboxGroup(checkboxGroup1); checkbox6.setLabel("Радиокнопка 3"); // Добавление кнопок в контейнеры - панели this.add(panel1, null); panel1.add(checkbox1, null); panel1.add(checkbox2, null); this.add(panel2, null); panel2.add(checkbox4, null); panel2.add(checkbox5, null); panel2.add(checkbox6, null); } }
Листинг 27.2.
Классы кнопок пакета javax. swing наследуются от класса AbstractButton. Этот класс предоставляет ряд общих методов, включая следующие:
doClick - выполнение щелчка мыши на кнопке программным способом;getText- возвращает метку кнопки;setText - устанавливает метку кнопки;isSelected - определяет состояние кнопки и возвращает true, если переключаемая кнопка находится в состоянии "включена";setSelected - устанавливает состояние кнопки;setMargin - устанавливает отступы между рамкой кнопки и меткой;setIcon - определяет пиктограмму, используемую по умолчанию. Эта пиктограмма используется для состояния кнопки "нажатая" или "недоступная" в том случае, если для этих состояний не указана иная пиктограмма;setPressedIcon- определяет пиктограмму для нажатого ("pressed") состояния кнопки;setSelectedIcon - устанавливает пиктограмму для выделенного ("selected") состояния кнопки;setRolloverIcon - устанавливает пиктограмму для нажатого ("rollover") состояния кнопки (одновременно могут быть нажаты несколько кнопок);setDisabledIcon- устанавливает пиктограмму для недоступного состояния кнопки.
Например:
ImageIcon ImageIcon1= new ImageIcon("myicon.gif"); jButton1.setDisabledIcon(ImageIcon1);
setDisabledSelectedIcon - устанавливает пиктограмму недоступного для выделения состояния кнопки;setVerticalAlignment - определяет выравнивание по вертикали для пиктограммы и метки, которое может указываться следующими значениями:SwingConstants.CENTER (по умолчанию); SwingConstants.TOP;- SwingConstants.BOTTOM;
setHorizontalAlignment - определяет выравнивание по горизонтали для пиктограммы и метки, которое может указываться следующими значениями:SwingConstants.RIGHT (по умолчанию);SwingConstants.LEFT; SwingConstants.CENTER;SwingConstants.LEADING;SwingConstants.TRAILING;setVerticalTextPosition - определяет позицию текста по вертикали относительно пиктограммы, которая может указываться следующими значениями: SwingConstants.CENTER (по умолчанию);SwingConstants.TOP;SwingConstants.BOTTOM;setHorizontalTextPosition - определяет позицию текста по горизонтали относительно пиктограммы, которая может указываться следующими значениями: SwingConstants.RIGHT (по умолчанию);SwingConstants.LEFT;SwingConstants.CENTER;SwingConstants.LEADING;SwingConstants.TRAILING.setActionCommand - задает команду действия для кнопки;getActionCommand - возвращает строку, которая содержит команду действия, установленную для данной кнопки;setMnemonic - определяет код символа, используемого как ключ-акселератор (ALT+данный символ).
Например:
jButton1.setMnemonic(KeyEvent.VK_A);
Для того чтобы определить в методе обработки события itemStateChanged(ItemEvent e), какой кнопкой было инициировано данное событие, следует использовать метод getItemSelectable.
Для того чтобы определить, является ли кнопка, инициировавшая событие, выделенной (находящейся в состоянии "включена" или "нажата"), следует использовать метод getStateChange.
Например:
if (e.getItemSelectable() == jCheckBox1 && e.getStateChange()==e.SELECTED) { }
Класс JToggleButton предназначен для создания кнопок, имеющих два состояния - "нажата" и "не нажата". Компонент JToggleButton может находится в зафиксированном нажатом состоянии (быть выделенным).
Этот класс является непосредственным суперклассом для классов JCheckbox и JRadioButton.
Для того чтобы установить состояние кнопки, следует использовать метод setSelected .
Например:
jToggleButton1.setSelected(true);
Кнопки JToggleButton могут быть объединены в группу. Такую группу следует предварительно создать, используя компонент типа javax.swing.ButtonGroup. Только одна из кнопок группы может одновременно иметь нажатое состояние.
Панели
Java-приложение создается как иерархия вложенных компонентов. Наверху этой иерархии могут находится компоненты классов Frame, JFrame, Applet или JApplet.
Классы панелей используются как контейнеры для размещения других компонентов, в числе которых могут быть и сами панели. Пакет оконного интерфейса java.awt содержит один класс панели - Panel. Для добавления компонентов на панель класса Panel следует выполнить метод add, квалифицировав его именем панели.
Пакет облегченных swing-компонентов предоставляет несколько классов панелей, включая следующие классы:
JRootPaneJPanelJTabbedPaneJScrollPaneJSplitPaneJOptionPaneJToolbar.
При использовании менеджеров компоновки с панелями из пакета java.swing для получения ссылки на панель следует использовать метод getLayout.
Например:
((CardLayout)jPanel1.getLayout()).next(jPanel1);
Пакет javax.swing содержит интерфейс RootPaneContainer, реализуемый классами JApplet, JFrame, JInternalFrame, JWindow и JDialog.
При добавлении компонентов в контейнер, использующий интерфейс RootPaneContainer , метод add надо квалифицировать следующим образом:
frame.getContentPane().add(child).
Класс JRootPane используется всеми панелями пакета javax.swing. Он позволяет размещать содержимое панели на нескольких уровнях. JRootPane представояет четыре уровня:
ContentPane - используется для отображения компонентов.MenuBar - необязательный уровень, на котором можно размещать компоненты меню.LayeredPane - используется для управления contentPane и menuBar.GlassPane - самый ближайший к пользователю уровень. По умолчанию он невидим. glassPane, как правило, используется для отображения графики или каких-либо всплывающих компонентов. Компоненты этого уровня перекрывают компоненты, расположенные на более "низких" уровнях.
Уровень contentPane должен быть родительским для размещения любого компонента. Для доступа к данному уровню используется метод getContentPane().
Уровень glassPane является самым верхним. Для доступа к данному уровню применяется метод getGlassPane().
Чтобы в приложении можно было использовать уровень glassPane, для него следует вызвать метод setGlassPane().
Например:
panel1.getContentPane().add(button1);
Компонент JTabbedPane реализует набор страниц, переключаемых по щелчку пользователя на вкладках. Вкладки добавляются методами addTab и insertTab. Вкладки нумеруются, начиная с 0.
Если количество вкладок равно нулю, то индекс текущей вкладки равен -1.
На рис. 27.5 показан внешний вид окна, содержащего панель вкладок класса JTabbedPane.
Рис. 27.5. Окно с компонентом JTabbedPane
Класс javax.swing.JScrollPane реализует компонент "прокручиваемая область".
Панель JScrollPane состоит из:
области просмотра ( viewport) типа JViewport. Для добавления рамки вокруг области просмотра следует использовать метод setViewportBorder, а для добавления рамки вокруг всей прокручиваемой области - метод setBorder.;вертикальной и горизонтальной области прокрутки типа JScrollBar (необязательная область);области заголовков строк и области заголовкоd столбцов (необязательная область). Эти области реализуются как объекты типа JViewport, для которых вызваны методы setRowHeaderView и setColumnHeaderView;четырех угловых областей. По умолчанию угловые области не содерджaт компонентов. Для того чтобы разместить в угловой области компонент, следует использовать метод setCorner.
Чтобы изменить свойство области просмотра, ее следует получить, вызвав метод getViewport. Например, для задания цвета фона нужно записать:
scrollPane.getViewport().setBackground(Color.red).
На рис. 27.6 показано расположение основных частей прокручиваемой области JScrollPane.
Рис. 27.6. Окно с компонентом JTabbedPane
Контейнером для разделяемых панелей служит компонент JSplitPane. Разделяемые плавающие панели имеют одну общую сторону - по вертикали или по горизонтали.
Следующий пример иллюстрирует создание окна, в котором применяются разделяемые панели:
import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Frame1 extends JPanel { JSplitPane jSplitPane1 = new JSplitPane(); // Класс // разделяемых панелей JScrollPane jScrollPane1 = new JScrollPane(); JScrollPane jScrollPane2 = new JScrollPane(); JTextPane jTextPane1 = new JTextPane(); JTextPane jTextPane2 = new JTextPane(); public Frame1() { try { jbInit(); } catch(Exception e) { } } public static void main(String s[]) { JFrame frame = new JFrame("Панели"); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setContentPane(new Frame1()); frame.pack(); frame.setVisible(true); } private void jbInit() throws Exception { // Определение ориентации разделяемых панелей jSplitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT); // Размещение левого и правого компонента // на разделяемой панели jSplitPane1.setLeftComponent(jScrollPane1); jSplitPane1.setRightComponent(jScrollPane2); // Отображение кнопок сворачивания и разворачивания // сторон разделяемой панели jSplitPane1.setOneTouchExpandable(true); // Задание размера панелей jScrollPane1.setPreferredSize(new Dimension(300, 60)); jScrollPane2.setPreferredSize(new Dimension(300, 60)); // Добавление разделяемой панели к окну формы this.add(jSplitPane1, null); // Добавление компонентов в контейнеры // типа JScrollPane jScrollPane1.getViewport().add(jTextPane1, null); jScrollPane2.getViewport().add(jTextPane2, null); } }
Листинг 27.1.
Применение компоновок
При проектировании интерфейса пользователя с использованием языка Java компоненты размещаются в контейнерах. Самым простым примером контейнера может служить окно формы (класс Frame). В общем случае любой класс, наследуемый от класса контейнера java.awt.Container, является контейнером.
В языке Java для "плавающего" размещения компонентов, зависящего от размеров окна и размеров самих компонентов, введены классы компоновок.
Компоновка определяет порядок расположения компонентов на экране. Перед отображением объектов-контейнеров, содержащих другие компоненты, вызывается менеджер компоновки. Он располагает компоненты на экране в соответствующем порядке. Используемый менеджер компоновки указывается вызовом метода setLayout. Если менеджер компоновки не указан явно, то выбирается тот, что используется по умолчанию для данного класса контейнера.
Для того чтобы отключить использование менеджеров компоновки и перейти к явному указанию координат, следует вызвать метод setLayuot(null).
Пакеты java.awt и javax.swing предоставляют следующие классы менеджеров компоновки:
java.awt.FlowLayout - создает последовательное размещение объектов с указанным выравниванием и заданными между этими объектами интервалами.java.awt.GridLayout - создает табличное размещение объектов с заданным числом строк и столбцов, объекты располагаются последовательно слева направо.java.awt.GridBagLayout - создает гибкое табличное размещение объектов, позволяя размещать один компонент в нескольких ячейках.java.awt.BorderLayout - создает размещение объектов по краю контейнера (вверху, внизу, слева, справа и в центре).java.awt.CardLayout - создает компоновку контейнера, отображая одновременно только один компонент. Как правило, в качестве компонент для данного менеджера компоновки выступают панели.javax.swing.ScrollPaneLayout - позволяет размещать компоненты на девяти различных областях; является компоновкой по умолчанию для класса ScrollPane.javax.swing.ViewportLayout - является компоновкой по умолчанию для класса Jviewport.javax.swing.BoxLayout - является компоновкой по умолчанию для класса Box.javax.swing.OverlayLayout - позволяет размещать компоненты один над другим.
Для использования конкретного менеджера компоновки следует создать объект данного класса и установить созданную компоновку для данного контейнера, а затем добавить в контейнер другие компоненты.
Например:
GridBagLayout gridBagLayout1 = new GridBagLayout(); this.setLayout(gridBagLayout1); Button button1 = new Button(); button1.setLabel("Кнопка 1"); this.add(button1, new GridBagConstraints(0, 0, 3, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 315, 0));
Метод setLayout следует квалифицировать именем контейнера, для которого устанавливается компоновка. Для класса контейнера, в котором выполняется данный метод, можно использовать ссылку this. В случае предварительного создания объекта "менеджер компоновки", его следует указать как параметр метода setLayout. В противном случае в качестве параметра метода setLayout следует указать оператор создания анонимного объекта "менеджер компоновки".
Например:
this.setLayout(gridLayout1); // или this.setLayout(new GridLayout());
При использовании панели типа Panel методы объекта "менеджер компоновки" вызываются стандартным образом имя_объекта_менеджер_компоновки.имя_метода.
Например:
cardLayout1.show(Panel1,"Panel0");.
При использовании панели типа JPanel методы объекта "менеджер компоновки" вызываются с использованием метода getLayout.
Например:
((CardLayout)jPanel2.getLayout()).show(jPanel2,"jPanel0");
Списки
Списки позволяют отображать группу элементов в один столбец, предоставляя пользователю возможность выбора элемента.
Библиотека JDK содержит ряд классов списков, включая следующие:
java.awt.List - список.java.awt.Choice - ниспадающий список.javax.swing.JList - список.javax.swing.JComboBox - ниспадающий список.
При выделении элемента в списке или в ниспадающем списке (или отмене выделения) инициируется событие itemStateChanged. В метод обработки этого события передается объект типа ItemEvent. Используя свойство SELECTED для объекта типа ItemEvent, можно определить, выделен ли элемент списка. Интерфейс ItemListener описывает метод обработки события itemStateChanged.
При двойном щелчке мышью на элементе списка (или нажатии клавиши Enter при выделенном элементе списка) для компонента типа List, JList или JComboBox инициируется событие actionPerformed. В метод обработки этого события передается объект типа ActionEvent. Интерфейс ActionListener описывает метод обработки события actionPerformed.
Заполнение списков можно выполнять в обработчике события фрейма windowOpened. Добавление элементов в список List и Choice выполняется методом add.
Например:
List list1 = new List(4, false); // Создание списка // с 4 видимыми строками и с запретом множественного выбора list1.add("Строка 1"); // Добавление элементов в список list1.add("Строка 2"); list1.add("Строка 3"); list1.add("Строка 4"); list1.add("Строка 5"); list1.add("Строка 6"); add(list1); // Добавление списка в текущий контейнер
Список JList позволяет выделять один или несколько элементов. Содержание списка представляется моделью ListModel. Доступ к элементам списка реализуется с использованием модели. Для заполнения списка используется метод setListData.
Список JList непосредственно не поддерживает прокрутку списка. Реализовать скроллинг можно двумя способами:
Поместить список в контейнер типа JScrollPane. Например:
JScrollPane scrollPane = new JScrollPane(jList1); Установить для объекта типа JScrollPane на уровне Viewport (getViewport) в качестве компонента области просмотра (setView) объект типа JList. Например:
JScrollPane scrollPane = new JScrollPane(); scrollPane.getViewport().(jList1);
Например:
String[] data = {"один", "два", "три"}; // Массив строк JList jList1 = new JList(data); // Создание списка, // содержащего массив строк // Доступ к элементам списка через модель for(int i = 0; i<jList1.getModel().getSize(); i++) { System.out.println(jList1.getModel().getElementAt(i)); } // Заполнение списка данными, представляемыми классом Vector JList jList1 = new JList(); Vector superClasses = new Vector(); Class rootClass = javax.swing.JList.class; // Создание объекта // типа Class for(Class cls = rootClass; cls != null; cls = cls.getSuperclass()) { // Получение всех подклассов superClasses.addElement(cls); } jList1.setListData(superClasses); // Заполнение компонента jList1 // списком всех его подклассов // Добавление элементов в список, хранимый в объекте типа Vector superClasses.addElement(new String("12345")); // Выделение элементов списка: jList1.setSelectedIndex(1); // Выделение второго элемента списка jList1.getSelectedValue(); // Возвращает строку, отображаемую //во втором элементе списка
Листинг 27.3.
Текстовые компоненты
Текстовые компоненты предназначаются для ввода и отображения строк.
Библиотека JDK предоставляет следующие классы текстовых компонентов:
java.awt.TextArea - текстовая область.java.awt.TextField - текстовое поле, называемое также полем ввода.javax.swing.JTextField - текстовое поле.javax.swing.JPasswordField - текстовое поле, предназначаемое для ввода пароля.javax.swing.JTextArea - текстовая область.javax.swing.JEditorPane - панель редактора, позволяющая отображать как текстовые, так и графические данные, а также применять различное форматирование текста.javax.swing.JTextPane - текстовая панель, позволяющая отображать содержимое с использованием различных шрифтов.
Все текстовые компоненты пакета java.awt наследуются от класса TextComponent.
Все текстовые компоненты пакета javax.swing наследуются от класса JTextComponent.
Для отображения текста, который может быть изменен только программным путем, служат компоненты .Label из пакета java.awt и JLabel из пакета javax.swing.
Компонент JLabel также можно использовать и для отображения рисунков.
Большинство названий методов, предоставляемых классами TextComponent и JTextComponent для работы с текстом, совпадают. Так, для того чтобы получить строку, которая содержит весь текст, расположенный в текстовом компоненте, можно использовать метод getText, а для получения позиции ввода - метод getCaretPosition; для определения, можно ли редактировать текст, - метод isEditable, для выделения текста в указанном диапазоне - метод select, а для выделения всего текста - метод selectAll.
При каждом изменении значения текстового компонента, включая ввод каждого символа, происходит событие textValueChanged. При нажатии на клавишу Enter для текстового поля инициируется событие actionPerformed. Но при перемещении фокуса ввода событие actionPerformed не происходит.
для ввода и редактирования одной строки текста. Этот класс предоставляет ряд методов, включая следующие:
AddActionListener - регистрирует блок прослушивания для обработки события действия компонента "текстовое поле".EchoCharIsSet - возвращает значение true в том случае, если ввод в данное текстовое поле отображается некоторым эхо-символом, скрывающим действительное значение поля.GetColumns - возвращает размер данного текстового поля (количество символов).GetEchoChar - возвращает эхо-символ для данного текстового поля.SetEchoCharacter - устанавливает значение эхо-символа для данного текстового поля.
Любой вводимый пользователем символ будет экранирован данным эхо-символом.SetColumns - устанавливает размер текстового поля в символах.SetText - определяет новое значение текстового поля.
Хотя компоненты пакета javax.swing и называются облегченными, но они предоставляют значительно большие возможности, чем традиционные текстовые компоненты пакета java.awt.
Управление текстом, отображаемым в текстовом компоненте, определяется интерфейсом Document. Этот интерфейс предназначен для определения методов работы с текстом. Интерфейс Documentреализован классом AbstractDocument.
Текст в компоненте типа JTextComponent представляется ассоциируемой с ним текстовой моделью, определяющей как содержание, так и стиль.
Фактически, текстовый компонент предоставляет доступ к:
модели, реализуемой на основе интерфейса Document и представляющей собой содержание документа;области просмотра текстового компонента;набору команд редактирования, предусмотренного для текстового компонента;таблице ключей акселераторов, связанных с таблицей именованных действий.
Класс DefaultEditorKit и StyledEditorKit описывают набор именованных действий, которые можно использовать для создания на основе текстового компонента редактора текста.
В классе DefaultEditorKit определен набор предоставляемых текстовому компоненту действий, таких как перемещение курсора, выделение или вставка текста.
Например, для создания пункта меню, выполняющего форматирование выделенного диапазона текста, и изменения размера шрифта на 14p, следует записать:
menu.add(new StyledEditorKit.FontSizeAction ( "Имя пункта меню", 14));
Константы класса DefaultEditorKit описывают набор именованных действий, включая следующие:
BackwardAction - перемещение позиции ввода на одну позицию назад.BeepAction - подача звукового сигнала.BeginAction - перемещение позиции ввода на начало документа.BeginParagraphAction - перемещение позиции ввода в начало абзаца.BeginLineAction - перемещение позиции ввода в начало строки.BeginWordAction - перемещение позиции ввода на начало текущего слова.CutAction - вырезание выделенного диапазона текста и помещение его в буфер обмена.CopyAction - копирование выделенного диапазона текста в буфер обмена.DeleteNextCharAction - удаление следующего символа.DownAction- перемещение позиции ввода на один ряд вниз.DeletePrevCharAction - удаление предыдущего символа.EndAction - перемещение позиции ввода в конец документа.EndLineAction - перемещение позиции ввода в конец строки.EndParagraphAction - перемещение позиции ввода в конец абзаца.EndWordAction - перемещение позиции ввода на конец текущего слова.ForwardAction - перемещение позиции ввода на один символ вперед.InsertBreakAction - вставка в документ символа конца абзаца.InsertTabAction - вставка символа табуляции.NextWordAction - перемещение позиции ввода на начало следующего слова.PageDownAction - перемещение позиции ввода на одну страницу вниз.PageUpAction - перемещение позиции ввода на одну страницу вверх.PasteAction - вставка содержимого буфера обмена вместо выделенного диапазона текста или перед текущей позицией ввода.PreviousWordAction - перемещение позиции ввода на начало предыдущего слова.ReadOnlyAction - перевод редактора в режим "только чтение".SelectAllAction - выделение всего документа.SelectionBackwardAction - расширение области выделения на одну позицию назад (влево).SelectionBeginAction - расширение области выделения до начала документа.SelectionBeginLineAction- расширение области выделения до начала текущей строки.SelectionBeginParagraphAction - расширение области выделения до начала текущего абзаца.SelectionBeginWordAction - расширение области выделения до начала текущего слова.SelectionDownAction - расширение области выделения на одну позицию вниз.SelectionEndAction - расширение области выделения до конца документа.SelectionEndLineAction - расширение области выделения до конца строки.SelectionEndParagraphAction- расширение области выделения до конца абзаца.SelectionEndWordAction - расширение области выделения до конца текущего слова.SelectionForwardAction - расширение области выделения на один символ вперед (вправо).SelectionNextWordAction - расширение области выделения до начала следующего слова.SelectionPreviousWordAction - расширение области выделения до начала предыдущего слова.SelectionUpAction - расширение области выделения на одну позицию вверх.SelectLineAction - выделение строки, в которой расположена позиция ввода.SelectParagraphAction - выделение абзаца, в котором расположена позиция ввода.SelectWordAction - выделение слова, в котором расположена позиция ввода.UpAction - перемещение позиции ввода на одну позицию вниз.WritableAction - перевод редактора в режим редактирования текста.
Для того чтобы добавить в документ строку в отформатированном виде, можно использовать метод insertS класса DefaultStyledDocument. Этот класс является подклассом класса AbstractDocumentи реализует интерфейсы Document и StyledDocument.
Интерфейс StyledDocument определяет методы для работы со стилем документа. Так, для назначения диапазону текста набора атрибутов стиля можно использовать метод setCharacter-Attributes, а для определения используемого стиля или шрифра - методы getStyle и getFont.
Атрибуты стиля определяются интерфейсом AttributeSet. Этот интерфейс реализован классом SimpleAttributeSet.
Для создания набора атрибутов стиля следует создать переменную типа SimpleAttributeSet и установить атрибуты стиля, используя методы класса
Например:
SimpleAttributeSet attrSt = new SimpleAttributeSet(); StyleConstants.setBold(attrSt, true); StyleConstants.setFontSize(attrSt, 12); StyleConstants.setForeground(attrSt, Color.red);
При добавлении строки в текстовый документ вызовом метода insertString класса Default-StyledDocument один из параметров ссылается на набор аттрибутов.
Фактически набор атрибутов стиля накладывается на диапазон текста. Если текстовый компонент содержит текст с различным форматированием, то на каждый отдельный диапазон текста должен быть "наложен" свой набор атрибутов стиля.
Для создания таблицы ключей акселераторов, используемых для текстового компонента, следует:
Создать объект класса Keymap для компонента класса JTextPane.
Например:
JTextPane textPane; .... Keymap keymap = textPane.addKeymap("MyKeymap", textPane.getKeymap());
Создать объект класса Action и установить для него действие, описанное в классе DefaultEditorKit.
Например:
Action action = getActionByName(DefaultEditorKit.downAction); Создать объект класса KeyStroke и установить для него значение ключа акселератора.
Например:
KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_N, Event.CTRL_MASK);
Установить связь между созданным действием и ключем акселератором.
Например:
keymap.addActionForKeyStroke(key, action);
Класс StyleConstants предоставляет набор методов, позволяющих определять или устанавливать значения для атрибутов форматирования.
Набор атрибутов форматирования может быть создан как объект одного из следующих классов:
SimpleAttributeSet .AttributeSet .MutableAttributeSet .
Например:
...SimpleAttributeSet[] attrs = new SimpleAttributeSet[stringForPane.length +1]; // Создание набора атрибутов: attrs[0] = new SimpleAttributeSet(); StyleConstants.setFontFamily(attrs[0], "SansSerif"); // Установка значения атрибута StyleConstants.setFontSize(attrs[0], 12); attrs[1] = new SimpleAttributeSet(attrs[0]); StyleConstants.setFontSize(attrs[1], 14); StyleConstants.setBold(attrs[1], true); // Добавление строки в документ с заданным набором // атрибутов (defaultStyleDocument1 переменная // класса, наследуемого от DefaultStyleDocument) defaultStyleDocument1.insertString( defaultStyleDocument1.length, string1, attrs[1]);
CGI и ISAPI приложения
Данные, отображаемые web-браузером, представляют собой HTML-страницу.
По HTTP-запросу web-браузер посылает на web-сервер информацию, содержащую URL-адрес документа, тип запроса и значения параметров. URL-адрес может указывать как простую HTML-страницу и приложение, выполняемое на web-сервере. Такое приложение иногда называется серверным приложением.
К серверным приложениям относятся CGI-приложения и ISAPI-приложения.
В отличии от CGI-приложений, выполняемых в отдельном процессе, ISAPI-приложения реализуются как DLL-библиотеки.
Результатом выполнения CGI или ISAPI-приложения чаще всего является динамически сформированная HTML-страница.
только на тот случай, если
// Заголовочный файл MyISAPI_1.h #pragma once #include "resource.h" class CMyISAPI_1Extension : public CHttpServer { public: CMyISAPI_1Extension(); // Конструктор ~CMyISAPI_1Extension(); public: virtual BOOL GetExtensionVersion(HSE_VERSION_INFO* pVer); virtual BOOL TerminateExtension(DWORD dwFlags); void Default(CHttpServerContext* pCtxt); DECLARE_PARSE_MAP() }; // Файл реализации MyISAPI_1.cpp #include "stdafx.h" #include "MyISAPI_1.h" CWinApp theApp; // Объект "приложение" BEGIN_PARSE_MAP(CMyISAPI_1Extension, CHttpServer) // Таблица // обработки команды // TODO: место для определения ON_PARSE_COMMAND() и // ON_PARSE_COMMAND_PARAMS() ON_PARSE_COMMAND(Default, CMyISAPI_1Extension, ITS_EMPTY) DEFAULT_PARSE_COMMAND(Default, CMyISAPI_1Extension) END_PARSE_MAP(CMyISAPI_1Extension) CMyISAPI_1Extension theExtension; // Только один объект //ISAPI-расширение класса, // наследуемого от CHttpServer CMyISAPI_1Extension::CMyISAPI_1Extension(){ } // Конструктор CMyISAPI_1Extension::~CMyISAPI_1Extension() { } BOOL CMyISAPI_1Extension::GetExtensionVersion(HSE_VERSION_INFO* pVer) { // Вызов метода базового класса CHttpServer::GetExtensionVersion(pVer); // Загрузка строки описания TCHAR sz[HSE_MAX_EXT_DLL_NAME_LEN+1]; ISAPIVERIFY(::LoadString(AfxGetResourceHandle(), // Макро - если IDS_SERVER, sz, HSE_MAX_EXT_DLL_NAME_LEN)); // 0,то завершение _tcscpy(pVer->lpszExtensionDesc, sz); return TRUE; } BOOL CMyISAPI_1Extension::TerminateExtension(DWORD dwFlags) { // Метод класса CHttpServer - позволяет выполнить завершение // потоков и работы ISAPI-расширения return TRUE; } // CMyISAPI_1Extension : методы обработчики // Код формируемой HTML-страницы записывается методом Default // в поток вывода void CMyISAPI_1Extension::Default(CHttpServerContext* pCtxt) { StartContent(pCtxt); // Начало HTML-страницы WriteTitle(pCtxt); // Формирование значения тега TITLE // _T - для Unocode конвертируется в L *pCtxt << _T(" HTML-page from "); // Первая строка //HTML-страницы *pCtxt << _T("ISAPI-application "); // Формирование строки HTML-документа для отображения формы *pCtxt << _T("<FORM> <INPUT TYPE='text' SISE=30 </FORM>"); EndContent(pCtxt); // Завершение HTML-страницы } // Следующие строки вставляются мастером // ISAPI Extension Wizard // только на тот случай, если ISAPI-расширение не будет // использовать MFC-бибиотеку. // В противном случае эти строки можно удалить /**** static HINSTANCE g_hInstance; HINSTANCE AFXISAPI AfxGetResourceHandle() { return g_hInstance;} BOOL WINAPI DllMain(HINSTANCE hInst, ULONG ulReason, // Точка LPVOID lpReserved) // входа в DLL-модуль { if (ulReason == DLL_PROCESS_ATTACH) { g_hInstance = hInst; } return TRUE; } ****/ |
Листинг 28.1. |
Закрыть окно |
// Заголовочный файл MyISAPI_1.h
#pragma once
#include "resource.h"
class CMyISAPI_1Extension : public CHttpServer
{
public:
CMyISAPI_1Extension(); // Конструктор
~CMyISAPI_1Extension();
public:
virtual BOOL GetExtensionVersion(HSE_VERSION_INFO* pVer);
virtual BOOL TerminateExtension(DWORD dwFlags);
void Default(CHttpServerContext* pCtxt);
DECLARE_PARSE_MAP()
};
// Файл реализации MyISAPI_1.cpp
#include "stdafx.h"
#include "MyISAPI_1.h"
CWinApp theApp; // Объект "приложение"
BEGIN_PARSE_MAP(CMyISAPI_1Extension, CHttpServer) // Таблица
// обработки команды
// TODO: место для определения ON_PARSE_COMMAND() и
// ON_PARSE_COMMAND_PARAMS()
ON_PARSE_COMMAND(Default, CMyISAPI_1Extension, ITS_EMPTY)
DEFAULT_PARSE_COMMAND(Default, CMyISAPI_1Extension)
END_PARSE_MAP(CMyISAPI_1Extension)
CMyISAPI_1Extension theExtension; // Только один объект
//ISAPI-расширение класса,
// наследуемого от CHttpServer
CMyISAPI_1Extension::CMyISAPI_1Extension(){ } // Конструктор
CMyISAPI_1Extension::~CMyISAPI_1Extension() { }
BOOL CMyISAPI_1Extension::GetExtensionVersion(HSE_VERSION_INFO* pVer)
{ // Вызов метода базового класса
CHttpServer::GetExtensionVersion(pVer);
// Загрузка строки описания
TCHAR sz[HSE_MAX_EXT_DLL_NAME_LEN+1];
ISAPIVERIFY(::LoadString(AfxGetResourceHandle(), // Макро - если
IDS_SERVER, sz, HSE_MAX_EXT_DLL_NAME_LEN)); // 0,то завершение
_tcscpy(pVer->lpszExtensionDesc, sz);
return TRUE;
}
BOOL CMyISAPI_1Extension::TerminateExtension(DWORD dwFlags)
{ // Метод класса CHttpServer - позволяет выполнить завершение
// потоков и работы ISAPI-расширения
return TRUE;
}
// CMyISAPI_1Extension : методы обработчики
// Код формируемой HTML- страницы записывается методом Default
// в поток вывода
void CMyISAPI_1Extension::Default(CHttpServerContext* pCtxt)
{
StartContent(pCtxt); // Начало HTML-страницы
WriteTitle(pCtxt); // Формирование значения тега TITLE
// _T - для Unocode конвертируется в L
указатель на строку, значение типа
BEGIN_PARSE_MAP(CDerivedClass, CHttpServer) DEFAULT_PARSE_COMMAND(Myfunc, CDerivedClass) // Для запроса типа // http://LOCALSERVER/MyISAPI_1.dll?Myfunc&string1&135 ON_PARSE_COMMAND(Myfunc, // Имя функции CDerivedClass, // Имя класса ITS_PSTR ITS_I2) // Список из двух параметров: // указатель на строку, значение типа short ON_PARSE_COMMAND_PARAMS("string integer=42") // Для запроса с тремя параметрами ON_PARSE_COMMAND(Myfunc2, CDerivedClass, ITS_PSTR ITS_I2 ITS_PSTR) ON_PARSE_COMMAND_PARAMS("string integer string2='Default value'") DEFAULT_PARSE_COMMAND(Myfunc3, CDerivedClass) ON_PARSE_COMMAND(Myfunc3, CDerivedClass, ITS_RAW) // Различное число параметров END_PARSE_MAP(CDerivedClass) // Функции, выполняемые для обработки команд void Myfunc(CHttpServerContext* pCtxt, LPTSTR pszName, int nNumber) { } // Первый параметр стандартен для всех функций, // обрабатывающих команды, тип второго и третьего // параметра был указан в макросе ON_PARSE_COMMAND void Myfunc2(CHttpServerContext* pCtxt, LPTSTR pszName, int nNumber, LPTSTR pszTitle) { } void CDerivedClass::Myfunc3( // Используется тип параметров // ITS_RAW CHttpServerContext* pCtxt, void* pVoid, // pVoid - указатель на передаваемые данные DWORD dwBytes) // dwBytes - количество переданных байтов данных { } |
Листинг 28.2. |
Закрыть окно |
BEGIN_PARSE_MAP(CDerivedClass, CHttpServer)
DEFAULT_PARSE_COMMAND(Myfunc, CDerivedClass)
// Для запроса типа
// http://LOCALSERVER/MyISAPI_1.dll?Myfunc&string1&135
ON_PARSE_COMMAND(Myfunc, // Имя функции
CDerivedClass, // Имя класса
ITS_PSTR ITS_I2) // Список из двух параметров:
// указатель на строку, значение типа short
ON_PARSE_COMMAND_PARAMS("string integer=42")
// Для запроса с тремя параметрами
ON_PARSE_COMMAND(Myfunc2,
CDerivedClass,
ITS_PSTR ITS_I2 ITS_PSTR)
ON_PARSE_COMMAND_PARAMS("string integer string2='Default value'")
DEFAULT_PARSE_COMMAND(Myfunc3, CDerivedClass)
ON_PARSE_COMMAND(Myfunc3, CDerivedClass,
ITS_RAW) // Различное число параметров
END_PARSE_MAP(CDerivedClass)
// Функции, выполняемые для обработки команд
void Myfunc(CHttpServerContext* pCtxt, LPTSTR pszName, int nNumber)
{ } // Первый параметр стандартен для всех функций,
// обрабатывающих команды, тип второго и третьего
// параметра был указан в макросе ON_PARSE_COMMAND
void Myfunc2(CHttpServerContext* pCtxt, LPTSTR pszName,
int nNumber, LPTSTR pszTitle)
{ }
void CDerivedClass::Myfunc3( // Используется тип параметров
// ITS_RAW
CHttpServerContext* pCtxt,
void* pVoid, // pVoid - указатель на передаваемые данные
DWORD dwBytes) // dwBytes - количество переданных байтов данных
{ }
cs using System; using
// Default.aspx. cs using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } } // Default.aspx <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Untitled Page</title> <link rel=stylesheet type="text/css" href=StyleSheet.css /> </head> <script language="javascript" type="text/javascript"> // <!CDATA[ function Submit1_onclick() { alert("1234567"); } // ]]> </script> </head> <body> <form id="form1" runat="server"> <div title="Заголовок"> <input id="Text1" type="text" class="Cl1" value="12345" /> <input id="Checkbox1" checked="checked" style="width: 52px; height: 56px" title="Флажок1" type="checkbox" /> <input id="Button1" title="Кнопка 1" type="button" value="button" /> <input id="Submit1" type="submit" value="submit" onclick="return Submit1_onclick()" /> </div> </form> </body> </html> // StyleSheet.css - файл таблицы стилей body { font-size: 18pt; color: blue; } .Cl1 { font-size: 24pt; color: red; } |
Листинг 28.3. |
Закрыть окно |
// Default.aspx.cs
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class _Default : System.Web.UI.Page
{ protected void Page_Load(object sender, EventArgs e)
{ }
}
// Default.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
Untitled Page
//
function Submit1_onclick() {
alert("1234567");
}
// ]]>
// StyleSheet.css - файл таблицы стилей
body
{ font-size: 18pt;
color: blue;
}
.Cl1
{ font-size: 24pt;
color: red;
}
HTTP-запросы
НТТР-запрос формируется в соответствии с протоколом HTTP (HyperText Transfer Protocol). В HTTP-запросе указывается GET- или POST-метод передачи данных. При вводе URL-адреса в поле адреса web-браузера или выполнении формы (пользователь щелкнул по кнопке типа SUBMIT) формируется HTTP-запрос. Если форма содержала данные, то они будут добавлены в конец строки с URL-адресом (при использовании метода GET). Соответственно, такой способ накладывает ограничение на размер передаваемых параметров. Если при выполнении формы атрибут METOD установлен равным POST, то используется POST-метод, при котором сначала на сервер посылается строка POST-запроса и HTTP-заголовки запроса, а затем пустая строка и строка, содержащая передаваемые параметры.
ISAPI-приложение может использоваться как для формирования динамической HTML-страницы, так и для обработки параметров, получаемых от формы.
В строке адреса web-браузера может быть указан только непосредственно URL-адрес выполняемого серверного приложения. В этом случае для обработки такого запроса используется команда, определяемая макросом DEFAULT_PARSE_COMMAND.
Если после URL-адреса за вопросительным знаком следует идентификатор команды, то для обработки данного HTTP-запроса следует использовать функцию, сопоставленную данной команде макросом ON_PARSE_COMMAND.
Например, для обработки строки
http://LOCALHOST/MyISAPI_1.dll?Myfunc?string1&123
ISAPI-приложение будет вызывать функцию Myfunc и передавать ей в качестве параметров три значения: первым параметром всегда будет указатель на HTTP-контекст, а далее будут следовать параметры, указанные в HTTP-запросе. В данном примере это два параметра: string1 и 123. Между собой параметры разделяются символом &.
Применение Cookies
Cookies - это данные, сохраняемые на ПК клиента (web-браузера). Пользователь имеет возможность запретить сохранять Cookies на своем ПК. Если запись Cookies разрешена, то они записываются при каждом получении ответа от web -сервера и передаются обратно с каждым следующим HTTP-запросом.
Для задания Cookies следует в обработчике события действия ввести следующий код:
with Response.Cookies.Add do Name:='Cook1''; // Имя данных Value:='ValueCook1''; // Значение end;
Для запроса Cookies следует в обработчике события действия ввести следующий код:
s1:=Request.CookieFields.ValueFromIndex[0]; // Request.CookieFields.Count - число полей в Cookies
Разбор параметров
Для доступа к значению формы из GET-запроса используется метод QueryFields объекта типа TWebRequest.
Например:
var1:=Request.QueryFields.Values["Имя_поля"]; var1:=Request.QueryFields.ValueFromIndex[0];
Для доступа к значению формы из POST-запроса используется метод ContentFields объекта типа TWebRequest.
Например:
var1:=Request.ContentFields.Values["Имя_поля"]; var1:=Request.ContentFields.ValueFromIndex [0]
Для доступа к параметрам самого запроса используется метод GetFieldByName:
Например:
Request.GetFieldByName('URL'); Request.GetFieldByName('METOD'); // Эквивалентно // выполнению Request.Metod;
Разбор списка параметров
Для запросов типа http://LOCALSERVER/MyISAPI_2.dll?Myfunc&s1= 10&s2=35&c1=y можно использовать макрос с типом параметров ITS_ARGLIST :
ON_PARSE_COMMAND(Myfunc, CMyHttpServer, ITS_ARGLIST).
Далее для разбора такого списка параметров используется класс CHttpArgList.
Класс CHttpArgList представляет собой массив структур типа CHttpArg.
При этом данные доступны через объект CHttpArg.
Поле CHttpArg::m_pstrValue содержит значение параметра, а поле CHttpArg::m_pstrArg - имя параметра.
Например:
для строки http://localserver/my1.dll&Arg1=hockey&Arg2&Arg3=beer+nuts надо реализовать разбор параметров по следующей схеме.
Создание CGI-приложения
Если WEB-броузер посылает в качестве запроса URL-адрес CGI-приложения, то web-сервер запускает это приложение и передает ему параметры запроса через стандартный ввод. Сформированная в результате выполнения CGI-приложения HTML-страница возвращается WEB-серверу через стандартный вывод.
Для того, чтобы создать CGI-приложение, запускаемое на сервере, следует создать проект Web Server Application и в диалоге New Web Server Application (рис. 28.3) выбрать тип серверного приложения (например, CGI Stand-alone executable).
Рис. 28.3. Диалог New web Server Application
В результате будет создан проект, содержащий главный файл приложения и модуль Unit1:
{Главный файл приложения} program Project1; {$APPTYPE CONSOLE} uses WebBroker, CGIApp, Unit1 in 'Unit1.pas' {WebModule1: TWebModule}; {$R *.RES} begin Application.Initialize; Application.CreateForm(TWebModule1, WebModule1); Application.Run; end. {Модуль Unit1.pas} unit Unit1; interface uses SysUtils, Classes, HTTPApp; type TWebModule1 = class(TWebModule) private { Private declarations } public { Public declarations } end; var WebModule1: TWebModule1; implementation {$R *.DFM} end.
Для того чтобы создать код, формирующий HTML-страницу, следует создать объект типа TWebActionItem (например, WebActionItem1), а далее создать для данного объекта обработчик события действия OnAction.
При этом автоматически будет сформирован следующий код:
procedure TWebModule1.WebModule1WebActionItem1Action( Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); begin end;
Код HTML-страницы записывается в свойство Content объекта Response.
Например:
//1. Response.Content:='<I>Результат выполнения </I> '+ <P> <B> CGI-приложения </B></P>; // 2. var aPage : TStringList; i: integer; begin aPage:= TStringList.Create; aPage.Add('Method = ' +Request.Method + '<BR>'); aPage.Add('URL = ' + Request.URL+ '<BR>'); aPage.Add('User Agent = ' + Request.UserAgent+ '<BR>'); aPage.Add('Remote Address = ' + Request.RemoteAddr+ '<BR>'); aPage.Add('Remote Host = ' + request.RemoteHost+ '<BR>'); Response.Content := aPage.Text; aPage.Free;
После размещения созданного CGI-приложения в каталог WEB-сервера, предназначенный для исполняемых файлов, web -браузер может формировать запрос, указывая URL-адрес данного CGI-приложения.
Создание ISAPI-приложения
Для того чтобы создать ISAPI-приложение, иногда также называемое ISAPI-расширением, следует:
создать новый проект;в диалоге New Project выбрать шаблон создаваемого документа MFC ISAPI Extension Dll;перейти на страницу Object Setting мастера ISAPI Extension Wizard и установить флажок Generate a server extension object. В результате выполненных действий мастер ISAPI Extension Wizard сформирует шаблон ISAPI-приложения. В заголовочном файле StdAfx.h, который добавляется в шаблон любого приложения, использующего MFC-библиотеку, указана строка #include <afxisapi.h> - она выполняет подключение файла afxisapi.h, который объявляет следующие классы, поддерживающие работу с HTTP-запросами:
class ChtmlStream. class ChttpServerContext. class ChttpServer. class ChttpFilterContext. class ChttpFilter. class CHttpArgList.
ISAPI-приложение создается как DLL-библиотека. Класс, выполняющий обработку HTTP-запроса и формирующий динамическую HTML-страницу, наследуется от класса CHttpServer.
В следующем листинге приведен код заголовочного файла и файла реализации класса, наследуемого от CHttpServer. В автоматически сформированный код ISAPI-приложения внесены изменения, которые добавляют в создаваемую HTML-страницу две строки текста и форму, содержащую элемент управления.
Листинг:
// Заголовочный файл MyISAPI_1.h #pragma once #include "resource.h" class CMyISAPI_1Extension : public CHttpServer { public: CMyISAPI_1Extension(); // Конструктор ~CMyISAPI_1Extension(); public: virtual BOOL GetExtensionVersion(HSE_VERSION_INFO* pVer); virtual BOOL TerminateExtension(DWORD dwFlags); void Default(CHttpServerContext* pCtxt); DECLARE_PARSE_MAP() }; // Файл реализации MyISAPI_1.cpp #include "stdafx.h" #include "MyISAPI_1.h" CWinApp theApp; // Объект "приложение" BEGIN_PARSE_MAP(CMyISAPI_1Extension, CHttpServer) // Таблица // обработки команды // TODO: место для определения ON_PARSE_COMMAND() и // ON_PARSE_COMMAND_PARAMS() ON_PARSE_COMMAND(Default, CMyISAPI_1Extension, ITS_EMPTY) DEFAULT_PARSE_COMMAND(Default, CMyISAPI_1Extension) END_PARSE_MAP(CMyISAPI_1Extension) CMyISAPI_1Extension theExtension; // Только один объект //ISAPI-расширение класса, // наследуемого от CHttpServer CMyISAPI_1Extension::CMyISAPI_1Extension(){ } // Конструктор CMyISAPI_1Extension::~CMyISAPI_1Extension() { } BOOL CMyISAPI_1Extension::GetExtensionVersion(HSE_VERSION_INFO* pVer) { // Вызов метода базового класса CHttpServer::GetExtensionVersion(pVer); // Загрузка строки описания TCHAR sz[HSE_MAX_EXT_DLL_NAME_LEN+1]; ISAPIVERIFY(::LoadString(AfxGetResourceHandle(), // Макро - если IDS_SERVER, sz, HSE_MAX_EXT_DLL_NAME_LEN)); // 0,то завершение _tcscpy(pVer->lpszExtensionDesc, sz); return TRUE; } BOOL CMyISAPI_1Extension::TerminateExtension(DWORD dwFlags) { // Метод класса CHttpServer - позволяет выполнить завершение // потоков и работы ISAPI-расширения return TRUE; } // CMyISAPI_1Extension : методы обработчики // Код формируемой HTML-страницы записывается методом Default // в поток вывода void CMyISAPI_1Extension::Default(CHttpServerContext* pCtxt) { StartContent(pCtxt); // Начало HTML-страницы WriteTitle(pCtxt); // Формирование значения тега TITLE // _T - для Unocode конвертируется в L *pCtxt << _T(" HTML-page from "); // Первая строка //HTML-страницы *pCtxt << _T("ISAPI-application "); // Формирование строки HTML-документа для отображения формы *pCtxt << _T("<FORM> <INPUT TYPE='text' SISE=30 </FORM>"); EndContent(pCtxt); // Завершение HTML-страницы } // Следующие строки вставляются мастером // ISAPI Extension Wizard // только на тот случай, если ISAPI-расширение не будет // использовать MFC-бибиотеку. // В противном случае эти строки можно удалить /**** static HINSTANCE g_hInstance; HINSTANCE AFXISAPI AfxGetResourceHandle() { return g_hInstance;} BOOL WINAPI DllMain(HINSTANCE hInst, ULONG ulReason, // Точка LPVOID lpReserved) // входа в DLL-модуль { if (ulReason == DLL_PROCESS_ATTACH) { g_hInstance = hInst; } return TRUE; } ****/
Листинг 28.1.
Каждый запрос обрабатывается некоторой функцией. При вызове такой функции, в качестве параметра ей передается объект типа CHttpServerContext. Для каждой такой функции должен быть указан вход в таблице обработки команд.
Создание приложений, выполняемых на WEB-сервере, в среде проектирования DELPHI
Среда проектирования Delphi также позволяет создавать CGI и ISAPI приложения.
Создание Web-форм В VisualStudio .NET
Web-формы можно добавлять в следующие проекты .NET:
ASP.NET Web SiteASP.NET. Web ServiceEmpty Web SitePersonal Web Site Starter Kit
Расположить проект можно как в файловой системе, так и на web-сервере. Если выбрано расположение HTTP, то для локального сервера поле Location следует установить равным http//localhost/каталог_проекта.
При создании проекта типа ASP.NET Web Site мастер проекта формирует следующие файлы web -приложения:
Default.aspx - текст HTML-страницы:Default.aspx.cs - подключаемые пространства имен и метод Page_Load.
В проект можно добавлять ранее созданные таблицы стилей.
Таблицы стилей добавляются как новый элемент. При этом в проект добавляется файл с расширением css (например, StyleSheet.css).
Следующий код иллюстрирует ASP-файл, используемый для отображения формы с 4 элементами управления:
// Default.aspx.cs using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls;
public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } } // Default.aspx <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Untitled Page</title> <link rel=stylesheet type="text/css" href=StyleSheet.css /> </head> <script language="javascript" type="text/javascript"> // <!CDATA[
function Submit1_onclick() { alert("1234567"); }
// ]]> </script> </head> <body> <form id="form1" runat="server"> <div title="Заголовок"> <input id="Text1" type="text" class="Cl1" value="12345" /> <input id="Checkbox1" checked="checked" style="width: 52px; height: 56px" title="Флажок1" type="checkbox" /> <input id="Button1" title="Кнопка 1" type="button" value="button" /> <input id="Submit1" type="submit" value="submit" onclick="return Submit1_onclick()" /> </div> </form> </body> </html>
// StyleSheet.css - файл таблицы стилей body { font-size: 18pt; color: blue; } .Cl1 { font-size: 24pt; color: red; }
Листинг 28.3.
Таблица стилей содержит набор селекторов с описанием стиля для каждого селектора. Селектором может быть имя тега, имя класса (указываемое после символа "."), имя идентификатора (указываемое после символа "#").
Описание стиля для селектора указывается в виде списка, разделенного символами ";" и заключенного в фигурные скобки. Описание стиля состоит из пар "имя_атрибута: значение".
Подключение таблицы стилей выполняется в заголовке HTML-файла строкой <link rel=stylesheet type="text/css" href=StyleSheet.css />.
Строка <%@ Page Language="C#" AutoEventWireup="true" CodeFile= "Default.aspx.cs" Inherits="_Default" %> содержит тег Page, представляющий HTML-страницу. Атрибут CodeFile указывает файл кода класса, производного от любого класса, наследуемого от System.Web.UI.Page. Атрибут Language определяет язык, используемый при компиляции конструкций вида <% %> и <%= %>. В качестве языка может выступать любой язык программирования, поддерживаемый .NET Framework, включая Visual Basic, C# или Jscript. Для любой страницы может быть указан только один используемый язык.
Страницы ASP.NET состоят из двух частей:
визуальных элементов, включающих разметку, серверные элементы и статический текст;программных фрагментов, включающих обработку событий и другой выполнимый код.
Технология ASP.NET предоставляет две модели управления визуальными элементами и кодом:
модель простого файла (single-file page model), при которой на странице описываются визуальные элементы, разметка и выполняемый код;модель страницы с последующим кодом (code-behind page model), при которой на странице описываются визуальные элементы и разметка, а код размещается в отдельном файле (таком как Default.aspx.cs).
В следующей таблице приведен пример HTML-страницы, разработанной на базе этих двух моделей.
<%@ Page Language="C#" %> <script runat="server"> void Button1_Click(Object sender, EventArgs e) { Label1.Text = "Время: " + DateTime.Now.ToString(); } </script> <html> <head> <title>Single-File Page Model</title> </head> <body> <form runat="server"> <div> <asp:Label id="Label1" runat="server" Text="Label"> </asp:Label> <br /> <asp:Button id="Button1" runat="server" onclick="Button1_Click" Text="Button"> </asp:Button> </div> </form> </body> </html> | <%@ Page Language="C#" CodeFile="MyPage.aspx.cs" Inherits="MyPage" AutoEventWireup="true" %> <html> <head runat="server" > <title>Code-Behind Page Model</title> </head> <body> <form id="form1" runat="server"> <div> <asp:Label id="Label1" runat="server" Text="Label" > </asp:Label> <br /> <asp:Button id="Button1" runat="server" onclick="Button1_Click" Text="Button" > </asp:Button> </div> </form> </body> </html> |
// Файл MyPage.aspx.cs using System; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; public partial class MyPage : System.Web.UI.Page { protected void Button1_Click(object sender, EventArgs e) { Label1.Text = "Время: " + DateTime.Now.ToString(); } } |
При использовании модели страницы с последующим кодом в код класса автоматически добавляется метод Page_Load, выполняемый перед отображением страницы. Так, в этот метод можно вставить код, выполняющий инициализацию некоторых полей формы.
Этот же метод можно вставить и как скрипт в начало файла при использовании модели простого файла.
Например
// Форма: <form id="form1" runat="server"> <asp:Label id="Message1" runat="server"/> <asp:Button id="Button1" Text="abc" runat="server" /> </form> // Код метода: <%@ Page Language="C#" %> <script runat="server"> protected void Page_Load(object sender, EventArgs e) { StringBuilder sb = new StringBuilder(); if (Page.IsPostBack) // Страница отображается как // обратное сообщение клиенту sb.Append("Ответ<br>"); sb.Append("HOST: " + Page.Request.UserHostAddress + ".<br>"); Message1.Text = sb.ToString(); // Запись в элемент // управления типа Label // с ID равным Message1 } </script>
Таблица описания команд
Для таблицы описания команд в MFC-библиотеку включены пять следующих макросов:
BEGIN_PARSE_MAP - определяет начало таблицы описания команд и указывает класс функций членов и базовый класс.END_PARSE_MAP - определяет конец таблицы описания команд..ON_PARSE_COMMAND - идентифицирует команду и указывает соответствующую ей функцию.ON_PARSE_COMMAND_PARAMS - определяет список параметров обрабатываемой команды. Этот макрос должен следовать непосредственно за макросом ON_PARSE_COMMAND.DEFAULT_PARSE_COMMAND - определяет команду, используемую в том случае, если нет явного указания выполняемой команды.
Макрос ON_PARSE_COMMAND используется при определении команды для объекта класса CHttpServer (или наследуемого от него), поступающей от клиента, и имеет следующее описание:
ON_PARSE_COMMAND(FnName, mapClass, Args)
Параметры:
FnName - имя функции члена класса, а также и имя команды.
mapClass - имя класса указанной функции.
Args- указывает тип списка параметров и может принимать следующие значения
ITS_EMPTY - параметров нет;
ITS_PSTR - указатель на строку;
ITS_RAW - данные, предварительно не обрабатываемые. Используется в том случае, если список параметров HTTP-запроса может иметь различное число параметров;
ITS_I2 - значение типа short
ITS_I4 - значение типа long
ITS_R4 - значение типа float
ITS_R8 - значение типа double
ITS_I8 - значение типа 64-битовое integer
ITS_ARGLIST - указатель на объект типа CHttpArgList.
Например:
BEGIN_PARSE_MAP(CDerivedClass, CHttpServer) DEFAULT_PARSE_COMMAND(Myfunc, CDerivedClass) // Для запроса типа // http://LOCALSERVER/MyISAPI_1.dll?Myfunc&string1&135 ON_PARSE_COMMAND(Myfunc, // Имя функции CDerivedClass, // Имя класса ITS_PSTR ITS_I2) // Список из двух параметров: // указатель на строку, значение типа short ON_PARSE_COMMAND_PARAMS("string integer=42")
// Для запроса с тремя параметрами ON_PARSE_COMMAND(Myfunc2, CDerivedClass, ITS_PSTR ITS_I2 ITS_PSTR) ON_PARSE_COMMAND_PARAMS("string integer string2='Default value'") DEFAULT_PARSE_COMMAND(Myfunc3, CDerivedClass) ON_PARSE_COMMAND(Myfunc3, CDerivedClass, ITS_RAW) // Различное число параметров END_PARSE_MAP(CDerivedClass)
// Функции, выполняемые для обработки команд void Myfunc(CHttpServerContext* pCtxt, LPTSTR pszName, int nNumber) { } // Первый параметр стандартен для всех функций, // обрабатывающих команды, тип второго и третьего // параметра был указан в макросе ON_PARSE_COMMAND void Myfunc2(CHttpServerContext* pCtxt, LPTSTR pszName, int nNumber, LPTSTR pszTitle) { } void CDerivedClass::Myfunc3( // Используется тип параметров // ITS_RAW CHttpServerContext* pCtxt, void* pVoid, // pVoid - указатель на передаваемые данные DWORD dwBytes) // dwBytes - количество переданных байтов данных { }
Листинг 28.2.
Выполнение ISAPI-приложения
Для выполнения ISAPI-приложения соответствующую DLL-библиотеку следует поместить в каталог web-сервера. Таким сервером может быть Internet Information Server или любой другой web-сервер.
Для просмотра сведений о виртуальных каталогах web-сервера на панели инструментов следует выбрать пиктограмму Administrative Tools и открыть диалог для администрирования web -сервера.
Для IIS сервера следует выбрать пиктограмму Internet Information Services. Отображаемый далее диалог Internet Information Services (рис. 28.1) позволяет получать информацию и настраивать ISS сервер.
Рис. 28.1. Диалог Internet Information Services
Для того, чтобы получить информацию о расположении домашнего каталога ISS-сервера, следует на панели, расположенной слева, выделить элемент Default Web Site и выполнить команду контекстного меню Properties.
В диалоге Default Web Site Properties на странице Home Directory в поле Local Path указано расположение домашнего каталога. Для того чтобы из данного каталога можно было загружать как HTML-файлы, так и DLL-файлы, значение поля Executable Permissions должно быть установлено равным Script and Executables.
После размещения ISAPI-приложения в домашнем каталоге web-сервера, это приложение можно выполнить в web-броузере, указав соответствующий URL-адрес.
При выполнении приложения на локальном компьютере в качестве имени сервера указывается LOCALHOST.
Например: http://LOCALHOST/MyISAPI_1.dll.
При размещении ISAPI-приложения на web -сервере имя приложения можно изменить. На рис. 28.2 приведен результат выполнения в web-браузере описанного выше ISAPI-приложения.
Рис. 28.2. Выполнение ISAPI-приложения в web -браузере
При первом выполнения ISAPI-приложения сервер загружает данную DLL. При всех последующих вызовах обращение происходит к уже загруженной DLL.
Взаимодействие по протоколу TCP/IP
Протокол TCP/IP (Transmission Control Protocol/Internet Protocol) предназначен для установления соединения между двумя компьютерами в сети, обычно называемыми клиентом и сервером. Протокол TCP/IP определяет IP-адрес и номер порта.
IP-адрес задает имя компьютера в сети. IP-адрес указывается или как числовой идентификатор компьютера, или, при использовании сервера DNS, - как символьный псевдоним числового идентификатора.
Локальный компьютер всегда адресуется как 127.0.0.1 или localhost.
При работе в Интернете все используемые IP-адреса уникальны. Поэтому для задания своему ПК некоторого IP-адреса следует получить этот адрес у провайдера.
При работе только в локальной сети предприятия можно самостоятельно установить различные IP-адреса для каждого ПК. Например: 192.168.0.2; 192.168.0.3; 192.168.0.4 и т.д.
Номер порта - это значение, однозначно идентифицирующее некоторый логический порт приложения, через который можно получать и посылать данные.