Е. К. Пугачев Объектно-ориентированное программирование Под общей редакцией Ивановой Г. С. Рекомендовано Министерством общего и профессионального образования Российской Федерации в качестве учебник

Вид материалаУчебник

Содержание


4.3.Технология разработки приложений Windows в средах Delphi и С++Builder
WM_CHAR. В зависимости от того, какая именно кнопка мыши была нажата, этот метод может вызывать: обработчик события OnKeyPress
Пример 4.69.
Unit MainUnit
InPutEdit, OutPutEdit: TEdit
Var MainForm: TMainForm
End; {обработчик события «нажатие клавиши Enter при вводе значения»} Procedure TMainForm.InPutEditKeyPress(Sender: TObject
MessageDlg('Значение содержит недопустимые символы.', mtError, [mbOk], 0)
Procedure TMainForm.NextButtonClick(Sender: TObject)
Program Example1
Пример 4.70. Приложение «Возведение чисел в квадрат» (вариант 2)
MessageDlg("Строка содержит недопустимые символы."
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
Подобный материал:
1   ...   23   24   25   26   27   28   29   30   ...   39
^

4.3.Технология разработки приложений Windows в средах Delphi и С++Builder


Идея событийного управления является самостоятельной и непосредственно не связана с ООП, то есть существуют программы, работающие по событийному принципу и написанные с использованием API вне рамок объектного подхода. Однако совмещение обеих технологий позволяет существенно упростить процесс программирования.

В настоящее время существует несколько сред программирования «под Windows», использующих объектно-ориентированный подход и включающих мощные библиотеки объектов. В качестве примеров можно назвать среды разработки Visual C++, Delphi, C++Builder, которые позволяют сравнительно легко создавать сложнейшие приложения Windows. Эти пакеты автоматизируют многие операции создания приложения, предлагая разработчику большое количество различных шаблонов и заготовок, начиная от заготовки будущего приложения.

Примечание. Visual C++ является наиболее универсальным из названных трех пакетов, но и, соответственно, самым сложным. Он использует развитую объектную модель C++ и имеет более мощную по сравнению с Delphi и C++Builder библиотеку объектов. Интерфейс и средства Visual C++ ориентированы на профессиональные разработки высокого уровня и далее в настоящем курсе рассматриваться не будут.

Delphi и C++Builder используют идентичные среды и одну и ту же библиотеку объектов VCL (Visual Component Library - библиотека визуальных компонент). Практически эти среды различаются только языком разработки: Delphi использует язык на основе Object Pascal, а C++Builder, как указано в названии, С++. Используемые объектные модели также во многом похожи.

Любое приложение, созданное в этих средах, состоит как минимум из трех объектов: объекта-приложения, объекта-формы (окна) и объекта-экрана. В большинстве случаев разработчик использует те варианты объекта-приложения и объекта-экрана, которые ему предоставляются средой. Основное внимание в процессе разработки сосредотачивается на создании объектов-форм и соответствующих оконных функций. При этом широко используются стандартные классы библиотеки VCL.

Все окна приложения строятся на базе класса формы TForm. В терминах библиотеки VCL форма - это окно, которое может содержать другие визуальные (т.е. имеющие графический образ на экране - кнопки, метки, строчный редактор и т.д.) и невизуальные компоненты. Соответствующие компонентам объекты в качестве объектных полей включаются в класс, порождаемый от TForm (рис. 4.15).

При входе в среду разработчику предлагается заготовка будущего приложения, которая состоит из заготовки формы и заготовки оконной функции. Заготовка оконной функции высвечивается в окне текста программы (рис. 4.9).



Рис. 4.60. Вид экрана при входе в Delphi.

Имеется и заготовка проекта, предусматривающая создание и инициализацию объекта приложения (класс TAplication), ответственного за создание главного окна приложения и цикл обработки сообщений. Заготовка формы (объект класса TForm1, наследуемого от TForm) уже «умеет» выполнять некоторые стандартные действия окна приложения, т.е. содержит методы обработки некоторых сообщений, например, закрытие приложения при нажатии на кнопку «Завершить приложение».

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

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

Так класс TForm включает метод обработки сообщения ^ WM_CHAR. В зависимости от того, какая именно кнопка мыши была нажата, этот метод может вызывать:
  1. обработчик события OnKeyPress - при нажатии любой клавиши, которой соответствует код ASCII (в основном - алфавитно-цифровая часть клавиатуры);
  2. обработчики событий OnKeyDown и OnKeyUp - соответственно, при нажатии и отпускании любой клавиши, включая и те, которым соответствует код ASCII (рис. 4.10).



Рис. 4.61. Подключение обработчиков событий при обработке сообщения.

Таким образом, в Delphi и C++Builder обработка сообщений заменена обработкой событий, при этом программист в большинстве случаев избавляется от необходимости расшифровки сообщений системы.

Перечень событий, предусмотренных для визуальных компонент, можно посмотреть в Инспекторе Объектов, поместив нужный компонент из меню компонент на форму, выделив его щелчком мыши и переключившись в Инспекторе Объектов на страницу Events (события). Так, например, для класса TForm предусмотрена возможность подключения обработчиков следующих событий:

а) при изменении состояния формы:
  1. OnCreate - в начальной стадии создания формы - используется при необходимости задания параметров (цвет или размер);
  2. OnActivate - при получении формой фокуса ввода (окно становится активным и ему адресуется весь ввод с клавиатуры);
  3. OnShow - когда форма (окно) становится видимой;
  4. OnPaint - при необходимости нарисовать или перерисовать форму;
  5. OnResize - при изменении размеров формы на экране;
  6. OnDeactivate - при потере формой фокуса ввода (окно становится неактивным);
  7. OnHide - при удалении формы с экрана (окно становится невидимым);
  8. OnCloseQuery - при попытке закрыть форму - обычно используется для создания запроса-подтверждения необходимости закрытия окна;
  9. OnClose - при закрытии формы;
  10. OnDestroy - при уничтожении формы;

б) от клавиатуры и мыши:
  1. OnKeyPressed - при нажатии клавиш, которым соответствует код ASCII;
  2. OnKeyDoun, OnKeyUp - при нажатии и отпускании любых клавиш, включая те, которым соответствует код ASCII;
  3. OnClick, OnDblClick - при обычном и двойном нажатии клавиш мыши соответственно;
  4. OnMouseMove - при перемещении мыши (многократно);
  5. OnMouseDown, OnMouseUp - при нажатии и отпускании клавиш мыши;

в) при перетаскивании объекта мышью:
  1. OnDragDrop - в момент опускания объекта на форму;
  2. OnDragOver - в процессе перетаскивания объекта над формой (многократно);

г) другие;
  1. OnHelp - при вызове подсказки;
  2. OnChange - при изменении содержимого компонент.

Список событий более простых компонент существенно короче, например, метка (класс TLabel) может реагировать на 9 событий:
  1. OnClick, OnDblClick, OnMouseDown, OnMouseUp - события мыши;
  2. OnDragDrop, OnDragOver, OnEndDrag, OnStartDrag - события при перетаскивании объекта мышью.

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

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

Таким образом, в Delphi и С++ Builder разработчику предоставляются средства визуального проектирования интерфейса и некоторые вспомогательные средства (в виде библиотеки объектов) разработки содержательной части задания.

Процесс создание приложений Windows в указанных средах включает те же этапы, что процесс разработки объектных программ для MS DOS, но выполнение этих этапов имеет некоторую специфику.

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

Существуют и особенности выполнения самих этапов разработки.

Рассмотрим два примера.

^ Пример 4.69. Приложение «Возведение чисел в квадрат»

Пусть необходимо разработать приложение, которое должно осуществлять последовательный ввод вещественных чисел (с проверкой правильности вводимых чисел) и возведение вводимых чисел в квадрат.

1. Анализ.

1) Разработку начинаем с анализа задачи с целью определения основных состояний интерфейса.

Для данной задачи можно использовать интерфейс с тремя состояниями:

а) исходное состояние, в котором приложение ожидает ввода числа, которое необходимо возвести в квадрат;

б) состояние вывода результата;

в) возможное состояние вывода сообщения об ошибочном вводе исходного числа.

2) Для каждого состояния продумываем внешнее представление (экранную форму), т.е. вид окна приложения в каждом случае (рис. 4.11).



Рис. 4.62. Экранные формы

3) Разрабатываем граф состояний интерфейса, отражающий возможные варианты смены состояний (рис. 4.12).



Рис. 4.63. Граф состояний интерфейса

4) Выполняем объектную декомпозицию интерфейсной и предметных частей приложения. Интерфейсная часть включает два объекта: главное окно приложения и окно сообщения об ошибке. Предметная часть очень проста и может быть реализована без выделения объектов (рис. 4.13).



Рис. 4.64. Объектная декомпозиция

2. Проектирование.

1) Логическое проектирование или разработка структуры классов выполняется с использованием среды разработки Delphi.

а) Вначале организуем новый проект и, используя визуальную технологию, создаем окно главной формы (рис. 4.14).



Рис. 4.65. Проектирование главного окна приложения.

При этом среда автоматически строит описание класса TForm1, наследуемого от библиотечного класса TForm и включает в него объектные поля визуальных компонент, руководствуясь эскизом экранной формы.

б) С помощью Инспектора Объектов настраиваем параметры формы и компонент следующим образом:

Form1:

Name:=MainForm;

Caption:='Возведение числа в квадрат';

Label1:

Name:='InputLabel';

Caption:='Введите значение';

Label2:

Name:=OutPutLabel;

Caption:='Квадрат значения равен:';

Edit1:

Name:=InputEdit;

Edit2:

Name:=OutPutEdit;

Enable:=false;

ReadOnly:=true;

Button1:

Name:=NextButton;

Caption:='Следующее';

Button2:

Name:=ExitButton;

Caption:='Выход';


Диаграмма класса TMainForm, построенного при визуальным проектировании, представлена на рис. 4.15.



Рис. 4.66. Диаграмма классов интерфейса приложения.

в) Исходя из возможных вариантов (списка событий задействованных компонент), определяем события, по которым будет происходить смена состояний интерфейса (рис. 4.16).



Рис. 4.67. Определение множества обрабатываемых событий

Параллельно определяем, какие основные операции должны быть выполнены при смене состояний интерфейса.

Обработчик события С1 – «активация формы» (OnFormActivate) должен выполнять настройку интерфейса в соответствии с экранной формой, изображенной на рис. 4.11 а (прятать метку результата и поле его вывода, запрещать нажатие кнопки Следующее, чистить поле ввода и устанавливать на него курсор).

Обработчик события С2 – «нажатие клавиши Enter при вводе значения» (OnKeyPressed для поля ввода) должен проверять правильность ввода. При правильном вводе далее он должен вычислять квадрат введенного значения и выводить результат в экранную форму, изображенную на рис. 4.11 б (соответственно, запрещая ввод значений, разрешая нажатие кнопки Следующее и показывая метку результата и результат). При неправильном вводе он должен выводить сообщение об ошибке, используя экранную форму, изображенную на рис. 4.11 в.

Обработчик события C3 – «нажатие кнопки Выход» (On Click для кнопки Выход) должен закрывать окно приложения.

Обработчик события С4 – «нажатие кнопки Следующее» (On Click для кнопки Следующее) должен вновь настраивать интерфейс в соответствии с экранной формой, изображенной на рис. 4.11 а.

На основании этой информации на следующем этапе разрабатываются алгоритмы соответствующих процедур - обработчиков указанных событий.

г) Решаем, что окно сообщения об ошибке отдельно проектировать не будем: для его отображения используем специальную функцию MessageDlg.

2) Физическое проектирование или разбивку программного продукта на модули среда Delphi выполнит автоматически, поместив класс формы в отдельном модуле.

3. Эволюция.

Используя шаблоны, предоставляемые средой, создаем обработчики событий, выбранных при разработке интерфейса:

^ Unit MainUnit;

Interface

Uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls;

Type TMainForm = class(TForm) {Класс «Главная форма»}

Bevel1: TBevel; {рамка}

NextButton, ExitButton: TButton; {кнопки Следующее и Выход}

InputLabel, OutPutLabel: TLabel; {метки ввода и вывода}

^ InPutEdit, OutPutEdit: TEdit; { редакторы ввода и вывода }

procedure FormActivate(Sender: TObject); {обработчик события «активация формы»}

procedure InPutEditKeyPress(Sender: TObject; var Key: Char); {обработчик события «нажатие клавиши Enter при вводе значения»}

procedure NextButtonClick(Sender: TObject); {обработчик события «нажатие кнопки Следующее»}

procedure ExitButtonClick(Sender: TObject); {обработчик события «нажатие кнопки Выход»}

end;

^ Var MainForm: TMainForm; {объявить объект класса TMainForm}

Implementation

{$R *.DFM}

{обработчик события «активация формы»}

Procedure TMainForm.FormActivate(Sender: TObject);

Begin

NextButton.Enabled:=false; {дезактивировать кнопку Следующее}

InPutEdit.ReadOnly:=false; {разрешить ввод в Редактор ввода}

InPutEdit.Clear; {очистить Редактор ввода}

InPutEdit.Enabled:=true; {активизировать Редактор ввода}

InPutEdit.SetFocus; {установить фокус ввода}

OutPutLabel.Visible:=false; {скрыть Редактор вывода}

OutPutEdit.Visible:=false; {скрыть Метку редактора вывода}

^ End;

{обработчик события «нажатие клавиши Enter при вводе значения»}

Procedure TMainForm.InPutEditKeyPress(Sender: TObject;

var Key: Char);

Var x:real;Code:integer;

Begin

if Key=#13 then { если нажата клавиша Enter, то}

begin

Key:=#0; {предотвратить звуковой сигнал при вводе символа перехода на следующую строку в однострочном редакторе}

Val(InPutEdit.Text,x,Code); {преобразовать введенную строку в число}

if Code=0 then {если преобразование прошло успешно, то}

begin

InputEdit.ReadOnly:=true; {запретить ввод в Редактор ввода}

InputEdit.Enabled:=false; {дезактивировать Редактор ввода}

OutPutLabel.Visible:=true; {показать Метку вывода}

OutPutEdit.Visible:=true; {показать Редактор вывода}

OutPutEdit.Text:=floattostr(sqr(x)); {вывести результат в

Редактор вывода}

NextButton.Enabled:=true; {активировать кнопку Следующее}

NextButton.SetFocus; {установить фокус на кнопку

Следующее}

end

else {иначе, если введено не число, то}

^ MessageDlg('Значение содержит недопустимые символы.', mtError, [mbOk], 0); {показать окно Сообщение об ошибке}

end

End;

{обработчик события «нажатие кнопки Следующее»}

^ Procedure TMainForm.NextButtonClick(Sender: TObject);

Begin

FormActivate(NextButton); {вернуться к исходным настройкам интерфейса}

End;

{обработчик события «нажатие кнопки Выход»}

Procedure TMainForm.ExitButtonClick(Sender: TObject);

Begin

Close; {закрыть окно приложения и завершить его}

End;

End.

Основная программа (проект) в процессе разработки с использованием среды Delphi создается автоматически и будет выглядеть следующим образом:

^ Program Example1;

Uses Forms, MainUnit in 'MainUnit.pas' {MainForm};

{$R *.RES}

Begin

Application.Initialize; {инициализация приложения}

Application.CreateForm(TMainForm, MainForm); {создание формы}

Application.Run; {запуск цикла обработки сообщений}

End.

В процессе компиляции программы будут участвовать следующие файлы:

*.dpr –

файл проекта программы – исходный текст на Pascal (создается автоматически);

*.pas ­–

файлы, содержащие исходные модули программы (в том числе модули форм);

*.dfm –

текстовые файлы описания форм

В результате – будет получен файл .exe программы и целый ряд вспомогательных файлов.

^ Пример 4.70. Приложение «Возведение чисел в квадрат» (вариант 2)

Если использовать для разработки той же программы среду C++ Builder, то первые два этапа будут выполняться идентично, хотя описание класса TMainForm будет автоматически создано на C++ в файле MainUnit.h:

#ifndef MainUnitH

#define MainUnitH

#include

#include

#include

#include

#include

class TMainForm : public TForm

{

__published: // компоненты управляемые средой (объекты VCL)

TLabel *InputLabel;

TLabel *OutPutLabel;

TBevel *Bevel1;

TEdit *InputEdit;

TEdit *OutPutEdit;

TButton *NextButton;

TButton *ExitButton;

void __fastcall FormActivate(TObject *Sender);

void __fastcall InputEditKeyPress(TObject *Sender, char &Key);

void __fastcall NextButtonClick(TObject *Sender);

void __fastcall ExitButtonClick(TObject *Sender);

private: // объявления пользователя

public: // объявления пользователя

__fastcall TMainForm(TComponent* Owner);

};

extern PACKAGE TMainForm *MainForm;

#endif

Затем на третьем этапе будут программироваться обработчики событий, в результате чего будет получен файлы MainUnit.cpp:

#include

#pragma hdrstop

#include

#include

#include "MianUnit.h"

#pragma package(smart_init)

#pragma resource "*.dfm"

TMainForm *MainForm;

__fastcall TMainForm::TMainForm(TComponent* Owner)

: TForm(Owner) { } // конструктор формы

// обработчик события «активация формы»

void __fastcall TMainForm::FormActivate(TObject *Sender)

{

NextButton->Enabled=false; // дезактивировать кнопку Следующее

InputEdit->ReadOnly=false; // разрешить ввод в Редактор ввода

InputEdit->Enabled=true; // активизировать Редактор ввода

InputEdit->Clear(); // очистить Редактор ввода

InputEdit->SetFocus(); // установить фокус на Редактор ввода

OutPutEdit->Visible=false; // скрыть Редактор вывода

OutPutLabel->Visible=false; // скрыть Метку редактора вывода

}

// обработчик события «нажатие клавиши Enter при вводе значения»

void __fastcall TMainForm::InputEditKeyPress(TObject *Sender,

char &Key)

{ float x;

if (Key=='\r') // если введен символ «конец строки», то

{Key='\0'; // предотвратить выдачу звукового сигнала

try // выполнить контролируя возникновение исключений

{x=StrToFloat(InputEdit->Text); // преобразовать в число

InputEdit->ReadOnly=true; // запретить ввод в Редактор ввода

InputEdit->Enabled=false; // дезактивировать Редактор ввода

OutPutLabel->Visible=true; // показать Метку вывода

OutPutEdit->Visible=true; // показать Редактор вывода

OutPutEdit->Text=FloatToStr(x*x); // вывести результат в Редактор

вывода

NextButton->Enabled=true; // активизировать кнопку Следующее

NextButton->SetFocus(); // установить фокус на кнопку Следующее

}

catch (EConvertError&) // перехватить исключение преобразования

{TMsgDlgButtons S1; // объявить объект класса «множество»

S1< занесения код кнопки OK во множество S1

^ MessageDlg("Строка содержит недопустимые символы.",

mtError, S1, 0); // вывести окно Сообщение об ошибке

}

}

}

// обработчик события «нажата кнопка Следующее»

void __fastcall TMainForm::NextButtonClick(TObject *Sender)

{ FormActivate(NextButton); // вернуться к исходным настройкам

}

// обработчик события «нажата кнопка Выход»

void __fastcall TMainForm::ExitButtonClick(TObject *Sender)

{ Close();} // завершить работу приложения

Файл проекта Example1.cpp С++Builder также создает автоматически:

#include

#pragma hdrstop

USERES("Example1.res"); // включить файл ресурсов

USEFORM("MainUnit.cpp", MainForm); // включить файл формы

^ WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)

/* основная программа «под Windows»*/

{ try // выполнить, контролируя возникновение исключений

{ Application->Initialize(); // инициализация объектов VCL

Application->CreateForm(__classid(TMainForm), &MainForm);

// создание главного окна приложения

Application->Run(); // запуск цикла обработки сообщений

}

catch (Exception &exception) // при возникновении исключений

{ Application->ShowException(&exception); // вывести сообщение

}

return 0;

}

Таким образом, программа будет компилироваться из файлов следующих типов:

.cpp -

файлы, содержащие исходные модулей программы (в том числе обработчики событий форм) и файл проекта программы – исходный текст на С++ (обычно создается автоматически);

.bpr -

текстовый файл, содержащий инструкции по компиляции и сборке проекта (make-файл, обычно создается автоматически);

.dfm -

текстовые файлы описания форм (генерируются средой);

.h -

заголовочные файлы, содержащие объявления классов;

.hpp -

заголовочные файлы, содержащие описание компонентов VCL.

В результате компиляции и компоновки системы также как в Delphi получается файл .exe и вспомогательные файлы:

.res -

двоичные файлы ресурсов;

.tds -

символьная таблица отладчика.

Вопросы к главе 4
  1. Перечислите основные различия между операционными системами MS DOS и группой Win32. Сформулируйте, как каждое из них влияет на разрабатываемое программное обеспечение.
  2. Что собой представляет приложение Win32? Назовите основные компоненты приложения.
  3. Определите понятия: «сообщение», «цикл обработки сообщений», «оконная функция», «обработчик сообщений». Поясните, каким образом происходит выполнение приложения в операционных системах Win32.
  4. Что такое визуальная среда программирования? Что связывает между собой среды Delphi и C++Builder? Что такое «событие»? Как связаны между собой сообщения и события?
  5. Назовите последовательность разработки программных систем в указанных средах?