Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Теллес М. - Borland C++ Builder. Библиотека программиста - 1998

.pdf
Скачиваний:
764
Добавлен:
13.08.2013
Размер:
4.35 Mб
Скачать

Borland C++ Builder (+CD). Библиотека программиста 21

значение которой показывает, нажата ли в данный момент кнопка мыши. Если пользователь нажимает левую кнопку мыши внутри клиентской области окна, система обработки событий вызовет метод OnMouseDown. Этот метод просто-напросто устанавливает значение флага в TRUE (истина) и передвигает текущую позицию рисования в поле формы (то есть в Canvas) в позицию мыши. В обработчике для события CBuilder очень доступно передает нам информацию о позиции мыши в тот момент, когда на ней была нажата кнопка.

Вас может заинтересовать вопрос а как CBuilder ассоциирует событие OnMouseDown с написанным нами методом OnMouseDown? Явно не по имени, поскольку обработчик может быть вызван по нашему желанию откуда угодно. Ни в приведенном выше коде, ни в коде заголовка вы не найдете ничего, что осуществляло бы ассоциирова ние. Это что магия Borland? Ответ кроется в файле Unit1.dfm, который содержит информацию о размещении и обработке формы для модуля Unit1. Если вы попробуете прочитать файл DFM (form definition file, файл описания формы), используя стандартный текстовый редактор или набрав его имя в командной строке, то увидите, что он состоит из странных управляющих символов, в которых нет (или очень мало) смысла. Как же посмотреть на то, что происходит там, внутри?

Взглянем на файл описания формы (DFM)

Для того чтобы просмотреть файл описания формы, вы должны открыть его в среде CBuilder. Ничего необычного в этом нет. Файл DFM вы открываете так же, как открыли бы исходный, заголовочный или вообще любой текстовый файл. Щелкните кнопку Open File (открыть файл) на панели инструментов и выберите файлы DFM в выпадающем комбинированном списке фильтра файлов по расширению. Выберите файл Unit1.dfm из отображенного списка файлов (вообще-то он должен быть там единственным, но в зависимости от того, как много вы успели написать приложений, их может быть и больше). Выделите файл и нажмите кнопку OK. Сразу же произойдут два события. Во-первых, исходный и заголовочный файлы пропадут из окна редактора. Во-вторых, в окне редактора отобразится файл DFM в виде простого текстового файла. Вот что вы там увидите, если правильно выполнили все мои указания:

object Form1:TForm1 Left = 200

Top = 108

Width = 435

Height = 300 Caption = 'Form1'

Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11

Font.Name = 'MS Sans Serif' Font.Style = []

OnMouseDown = OnMouseDown PixelsPerInch = 96

TextHeight = 13 end

Как можно видеть из приведенного выше листинга, в файле DFM хранится разнообразная информация о свойствах формы: расположение (левый отступ (Left), верхний отступ (Top), ширина (Width) и высота (Height)), заголовок (Caption = Form1) и вся информация о шрифте (Font). Обработчики событий также описаны здесь. В строке, выделенной подсвечиванием, и производится то самое ассоциирование события (левая часть описанного в строке выражения) и обработчика события для нашей формы (правая часть выражения). Как CBuilder различает обработчик события и имя метода? Очень просто при помощи магии. Если серьезно, то мне

Borland C++ Builder (+CD). Библиотека программиста 22

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

Собственно рисование

Теперь, когда вы имеете представление, каким образом все работает, давайте закончим начатый нами пример, добавив код для рисования точек при передвиже нии мыши в окне и для остановки процесса в момент, когда пользователь отпустит наконец левую кнопку мыши. Итак, сначала код для рисования. Добавьте уже известным вам способом обработчик для события OnMouseMove, а в него добавьте следующие строки:

void __fastcall TForm1::OnMouseMove(TObject *Sender, TShiftState Shift,

int X,int Y)

{

if(FbMouseDown))

{

Canvas->LineTo(X,Y);

}

}

Этот метод использует флаг, который мы определили ранее для указания, нажата в данный момент кнопка мыши или нет. Если флаг установлен, то вызывается метод Canvas->LineTo. Этот метод рисует линию из текущей позиции в новую позицию мыши и делает эту новую позицию текущей. Если вы помните, начальная позиция была определена в нашем методе OnMouseDown, когда кнопка мыши была нажата в окне.

И наконец, последний метод, который должен быть выполнен, это обработчик события, когда кнопка мыши отпускается. Этот метод должен всего лишь снять (то есть установить в FALSE) флаг, который показывает, что кнопка мыши нажата. Поскольку единственной возможной функцией останется просто передвиже ние мыши, это будет означать одновременно и окончание процесса рисования точек.

Ниже приведен код для метода OnMouseUp, который вы должны добавить в обработчик для события OnMouseUp (кнопка мыши отпущена) в инспекторе объектов:

void __fastcall TForm1:OnMouseUp(TObject *Sender, TMouseButton Button,

TShiftState Shift, int X, int Y)

{

FbMouseDown = FALSE;

}

Хотите верьте, хотите не верьте, но программа Scribble благополучно дописана. Вы можете сделать ее исполняемой, запустить, не выходя из окружения CBuilder, и рисовать рожицы сколько душе угодно. Небольшое отступление для тех, кто предпочитает использовать клавиатуру, а не мышь. Вы можете использовать сочетание клавиш Ctrl+F9 для того, чтобы скомпилировать проект. Это сработает из окна любого редактора системы.

Scribble, часть вторая

Несмотря на то что только что завершенная нами программа Scribble выполняет все, для чего предназначалась, делает она это не вполне корректно. На данном этапе мы не собираемся сделать

Borland C++ Builder (+CD). Библиотека программиста 23

ее идеальной, но над улучшениями поработаем. Чтобы понять, в чем, собственно, проблема, запустите Scribble и при помощи мыши нарисуйте что-нибудь на пустом поле его окна (я обычно рисую что-то отдаленно напоминающее квадрат). Теперь минимизируйте окно программы, нажав кнопку минимизации (или выбрав команду минимизации из системного меню). Теперь, щелкнув на иконке программы на панели инструментов Windows 95 или NT, раскройте окно опять в полноразмерное состояние. И угадайте, что вы увидите да-да, пустое поле окна. Что же случилось?

Свойство Canvas объекта TForm не является неизменным. То есть все, что нарисовано в поле формы, пропадает после того, как форма была обновлена. Минимизация, а затем восстановление окна влекут за собой событие обновления. Если мы хотим, чтобы наши шедевры были некоторое время под рукой, нам придется как-то разрешить эту небольшую проблему. А разрешение ее лежит в событии OnPaint (при рисовании) и его обработчике.

Метод OnPaint вызывается для формы каждый раз, когда окно формы становится недоступно. Как мы уже видели, это происходит, когда мы минимизируем, а затем восстанавливаем окно формы. Также это происходит, если вы открываете другое окно поверх формы. Например, если вы в центре экрана открываете окно сообщения (message box), то та часть формы, которая окажется под ним, будет недоступной. CBuilder распознает недоступность формы, обрабатывая сообщение Windows WM_PAINT. В ответ на этот метод форма вызывает соответствующий метод формы OnPaint, если таковой имеется. Поскольку в программе нет обработчика события OnPaint, ничего не вызывается, когда форма должна быть перерисована, и, следовательно, ничего не отражается на экране. Пришло время поправить сложившуюся ситуацию.

Копируем проект

Обычно вы выбираете один из двух возможных путей для создания нового проекта. Либо вы создаете новый проект с нуля и постепенно добавляете в него код, необходимый для выполнения вашей задачи, либо вы берете существующий проект и переделываете его в новый. Репозиторий объектов может быть использован для хранения проектов, которые вам надо будет использовать еще или переделывать в новые проекты. Обычные проекты тем не менее вы скорее всего будете просто открывать и использовать команду меню File д Save Project As для создания нового проекта в новом каталоге.

Внимание! Не делайте этого. Создайте копию проекта в новом каталоге, несмотря на то что команда сохранения вроде бы делает то, что вам надо. На самом деле нет. Вместо этого она создает новый проект в новом каталоге, но при этом связывает его с исходными файлами в старом каталоге . Это значит, что вы, сами того не желая, будете модифицировать исходный проект. Будьте очень вниматель ны, сохраняя проект с новым именем. Лучшим способом, пожалуй, будет копировать целиком все содержимое проекта в новый каталог и потом открывать проект в этом новом каталоге. После того как вы открыли проект, используйте команду File д Save Project As для того, чтобы переименовать проект в новом каталоге. После того как вы это проделали, можете удалить старый файл проекта.

В качестве примера давайте скопируем проект Scribble в новый каталог. Предположим, что ваш существующий проект Scribble находится в каталоге d:\work\Scribble. Скопируйте файлы проекта, содержащиеся в каталоге d:\work\Scribble, в каталог d:\work\Scribble2. В CBuilder откройте проект

Scribble из каталога d:\work\Scribble2 и воспользуйтесь командой File д Save Project As, чтобы сохранить новый проект как Scribble2. Удалите все файлы Scribble.* в каталоге d:\work\Scribble2 и живите счастливо.

После того как вы скопировали проект в новый каталог (или, если вам так больше нравится, изменяйте существующий проект Scribble — ведь вы всегда сможете загрузить его снова с

Borland C++ Builder (+CD). Библиотека программиста 24

компакт-диска), откройте его в CBuilder IDE (Integrated Development Environment,

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

Очевидно, что для того, чтобы рисовать форму в ответ на сообщение WM_PAINT, в инспекторе объектов нам потребуется добавить обработчик для события OnPaint. Объект VCL TForm будет вызывать наш обработчик всегда, когда бы ни потребова лось обновить изображение формы. К счастью, мы не должны заботиться о том, какие части формы должны быть обновлены — CBuilder сделает это за нас, причем сделает очень хорошо. Все, о чем мы должны позаботиться, — это как продублиро вать изображение фигуры, которую нарисовал пользователь.

Первое, что мы должны делать, — это сохранять информацию по мере поступления. Для этого мы собираемся завести два массива, в которых будем хранить значения по X и по Y для каждой точки, через которую проходит мышь при создании фигуры. Есть методы, лучшие, чем хранить значения в статических массивах, но их мы рассмотрим несколько дальше при разговоре о библиотеке стандартных шаблонов (Standard Template Library). Тогда же мы разберемся и с некоторыми другими проблемами, возникающими при работе нашей программы, а до тех пор с улучшениями придется подождать.

Для начала добавьте следующие объявления в заголовочный файл для Unit1 (Unit1.h). Для удобства восприятия изменения показаны подсветкой строки.

//-------------------------------------------------------------------

#ifndef Unit1H #define Unit1H

//-------------------------------------------------------------------

#include <vcl\Classes.hpp> #include <vcl\Controls.hpp> #include <vcl\StdCtrls.hpp> #include <vcl\Forms.hpp>

//-------------------------------------------------------------------

const int MaxPoints = 100; class TForm1 : public TForm

{

__published: // IDE-managed Components

void __fastcall OnMouseDown(TObject *Sender, TMouseButton Button,

TShiftStste Shift, int X, int Y);

void __fastcall OnMouseMove(TObject *Sender, TShiftStste Shift, int X, int Y);

void __fastcall OnMouseUp(TObject *Sender, TMouseButton Button,

TShiftStste Shift, int X, int Y); private: // User declarations BOOL FbMouseDown;

int FnPoint;

int FPointX[MaxPoints+1]; int FPointY[MaxPoints+1]; public: // User declarations

__fastcall TForm1(TComponent *Owner);

}

//-------------------------------------------------------------------

Borland C++ Builder (+CD). Библиотека программиста 25

extern TForm1 *Form1; //-------------------------------------------------------------------

#endif

Совет

Оцените удобство описания константы MaxPoints (максимальное количество точек) в заголовочном файле. Вообще определение важных значений как констант вместо прямого вставления значений в код является хорошей практикой. Язык C++ предоставляет декларацию const для использования в коде констант вместо действительных значений. Таким образом, если мы когда-либо решим, что для описания системы нам требуется больше 100 точек, потребуется совершить изменение в единственном месте. В противном случае существует большая вероятность того, что хотя бы в одном месте старое значение останется не измененным, потенциально создавая проблемы или даже приводя к сбоям программы в дальнейшем.

После того как мы определили место для хранения значений X и Y координат точки, давайте сделаем следующий шаг сохраним в нем что-нибудь. Возьмемся пока за это, а потом займемся процессом рисования. Измените метод OnMouseDown следующим образом:

void __fastcall TForm1::OnMouseDown(TObject *Sender, TMouseButton Button,

TShiftState Shift, int X, int Y)

{

FbMouseDown = TRUE; canvas->MoveTo(X,Y); FnPoint = 0; FnPointX[FnPoint] = X; FnPointY[FnPoint] = Y;

}

Здесь, конечно, подсвечены те строки, которые вам следует ввести. Все, что мы делаем, — это в первом элементе соответствующих массивов сохраняем значения по X и по Y для точки, в которой кнопка мыши была нажата. Естественно, теперь соответствующим образом модифицируем метод

OnMouseMove:

void __fastcall TForm1::OnMouseMove(TObject *Sender, TShiftState Shift,int X,int Y)

{

if(FbMouseDown))

{

Canvas->LineTo(X,Y); if ( FnPoint < MaxPoints )

{

FnPoint++;

FPointX[FnPoint] = X;

FPointY[FnPoint] = Y;

}

}

}

И здесь никакого волшебства. Просто по мере поступления сохраняем все точки в массивах.

Borland C++ Builder (+CD). Библиотека программиста 26

Наконец, давайте добавим новый обработчик для метода OnPaint, который бы отображал точки в ответ на сообщение о рисовании. Вот код для метода OnPaint:

void __fastcall TForm1::OnPaint(Tobject *Sender)

{

if ( FnPoiont > 0 )

{

Canvas->MoveTo(FPointX[0],FPointY[0]); for ( int i=1; i<FnPoint; ++i ) Canvas->LineTo(FPointX[i],FPointY[i]);

}

}

Последнее, что нам надо сделать, — это задать начальное количество точек, равное 0, в конструкторе формы. Вот последнее изменение, которое надо сделать:

__fastcall TForm1::TForm1(TComponent* Owner) :TForm(Owner)

{

FbMouseDown = FALSE; FnPoint = 0;

}

Ну вот и все. Вы в считанных строках кода успешно продублировали внутренний пример

Microsoft Visual C++ / MFC (Microsoft Foundation Classes).

К высоким материям

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

Одной из наиболее мощных отличительных черт является возможность динамически изменять или удалять обработчики событий. Если вы привыкли работать с MFC или OWL, эта возможность станет неслыханным отличием от всего, что вам приходилось делать раньше.

В этом примере мы собираемся добавить в Scribble меню с двумя возможнос тями выбора. Первой возможностью будет уже привычное нам рисование линий. Выбор же второго пункта меню позволит нам копировать на экран растровое изображение (bitmap) в позицию, выбранную щелчком мыши. По ходу дела вы узнаете немного о том, как изменять имена обработчиков событий и как в этом может помочь CBuilder. В заключение вы узнаете, как это просто загружать и отображать растровые рисунки в CBuilder. При том что большинство каркасов не имеет никаких возможностей для изображения растровых рисунков, подобная отличительная черта CBuilder выглядит очень мило.

Scribble, третья попытка

Третья версия программы Scribble позволит скомбинировать рисование линий и копирование растровых рисунков. Результаты этого эксперимента можно увидеть на рис. 2.5, на котором показана форма Scribble3 после того, как на нее было добавлено несколько растровых рисунков и нарисована сложная фигура из линий. Полный исходный текст программы Scribble3 можно найти на сопроводительном компакт-диске в каталоге Chapter1\Scribble3.

Borland C++ Builder (+CD). Библиотека программиста 27

Рис. 2.5. Форма Scribble с нарисованными линиями и растровыми рисунками

Для того чтобы воплотить этот шедевр в жизнь, мы должны внести несколько изменений в интерфейс программы. Во-первых, добавить меню, чтобы использовать команды меню для изменения того, что должно происходить, когда пользователь щелкает мышью на поле формы. Итак, положите на форму компонент главное меню (main menu) и присвойте ему заголовок (Caption) Рисование . Добавьте два элемента в новое главное меню. Первую команду меню озаглавьте Линии. Выбор этой команды позволяет рисовать линии в поле формы. Вторую команду меню озаглавьте Рисунки. Для этой команды мы и собираемся осуществить новые возможности.

Следующее, что вам надо сделать, — это изменить название обработчика с OnMouseDown на OnMouseDownLines для того, чтобы текст программы был более удобочитаем. Это будет все тот же старый обработчик, который мы использовали все время, а изменение имени только подчеркнет, что этот обработчик будет использоваться для рисования линий в поле формы. В

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

Для изменения имени существующего обработчика просто перейдите на страницу Events (события) в Object Inspector и найдите имя, которое хотите изменить. Наберите новое имя для метода обработчика событий и нажмите Enter. Код в исходном файле будет автоматически обновлен для отражения сделанного изменения.

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

В секцию, помеченную private: // User declarations (приватных объявлений пользователя), заголовочного файла для нашей формы (Unit1.h) добавьте следующее описание:

void __fastcall OnMouseDownBitmap(TObject *Sender,

TMouseButton Button,

TShiftState Shift, int X, int Y);

Borland C++ Builder (+CD). Библиотека программиста 28

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

Graphics::Tbitmap *FpBitmap;

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

private: // User declarations BOOL FbMouseDown; int FnPoint;

int FPointsX[MaxPoints+1]; int FPointsY[MaxPoints+1]; Graphics::Tbitmap *FpBitmap;

void __fastcall OnMouseDownBitmap(TObject *Sender, TMouseButton Button,

TShiftState Shift, int X, int Y);

Следующий шаг изменить конструктор формы таким образом, чтобы стало возможным загрузить новый растровый рисунок. В данном случае мы собираемся использовать стандартный растровый рисунок Windows, называемый Triangles (треугольники), который вы сможете найти в системном каталоге Windows. Вот как будет выглядеть обновленный код:

__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)

{

FbMouseDown = FALSE; FnPoint = 0;

FpBitmap = new Graphics::TBitmap;

FpBitmap->LoadFromFile("C:\\Windows\\Triangles.BMP");

}

Как и в случае с большинством объектов CBuilder, процесс создания растрового рисунка для изображения состоит из двух последовательных шагов. На первом шаге под объект растровый рисунок выделяется память, а он сам создается, и все это посредством использования оператора C++ new. Обратите внимание на то, что поскольку TBitmap не является составной частью визуального элемента и сам по себе таковым не является, он не требует указания родителя при вызове конструктора. Большинство объектов CBuilder — это на самом деле окна, и они требуют указания window (окна) в качестве родителя. Но не в нашем случае. Следующим шагом после того, как объект был создан и инициализирован посредством оператора new, будет загрузка растрового рисунка в память. Это выполняется при помощи метода LoadFromFile класса TBitmap. Этот метод находит файл растрового рисунка в указанном каталоге и загружает биты растрового рисунка в объект, так что после этого они готовы к использованию.

Теперь, когда растровый рисунок загружен, пришло время написать код, который будет отображать его после того, как пользователь щелкнет кнопкой мыши в поле нашей формы. Вот как выглядит реализация метода OnMouseDownBitmap, которую вам следует ввести в исходный файл (Unit1.cpp):

Borland C++ Builder (+CD). Библиотека программиста 29

void __fastcall TForm1::OnMouseDownBitmap(TObject *Sender, TMouseButton Button,

TShiftState Shift, int X, int Y)

{

Canvas->Draw(X,Y,FpBitmap);

}

Как вы видите, для изображения растрового рисунка не так уж много надо. Свойство Canvas формы (а также всех других объектов, у которых оно есть) уже знает, как отображать растровый рисунок. Все, что вам надо сделать, — это передать указатель на объект «растровый рисунок» и определить позицию, в которой надо изобразить его. Это действительно очень просто.

Итак, теперь у нас есть законченная форма, которая умеет рисовать линии и растровые рисунки. Единственная проблема состоит в том, что если вы теперь откомпилируете и запустите приложение, то увидите, что куда и чем бы вы ни щелкали, форма по-прежнему будет рисовать только линии. Что-то мы явно упустили из виду.

Переключение обработчиков «на ходу»

В нашем маленьком сценарии не предусмотрена возможность для формы вызвать другой обработчик события, но мы можем добавить обработчик для команды меню Рисунки, открыв окно дизайнера меню и дважды щелкнув мышью на нужной нам команде. Новый метод с названием Bitmaps1Click будет добавлен в вашу форму. Добавьте в него строку кода, которая показана в следующем листинге подсветкой:

void __fastcall TForm1::Bitmaps1Click(TObject *Sender)

{

OnMouseDown = OnMouseDownBitmap;

}

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

void __fastcall TForm1::Lines11Click(TObject *Sender)

{

OnMouseDown = OnMouseDownLines;

}

Скомпилируйте и запустите приложение, и вы увидите, что выбор команды меню Рисунки позволяет вам рисовать маленькие треугольнички по всему полю формы. Выбор же команды Линии вернет форму к исходному поведению, то есть рисованию линии в поле формы при перемещении по ней мыши с нажатой левой кнопкой. То, что вы сейчас осуществили с помощью нескольких строк кода написание динамических обработчиков событий, между которыми можно переключаться во время исполнения программы, — чрезвычайно сложно или вообще невозможно в Visual C++ или Borland C++.

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

public: // User declarations

__fastcall TForm1(TComponent* Owner); __fastcall ~TForm1(void);

Borland C++ Builder (+CD). Библиотека программиста 30

В текст исходного файла Unit1.cpp добавьте следующие строки: __fastcall TForm1::~TForm1(void)

{

delete FpBitmap;

}

После того как вы создали что-нибудь при помощи оператора new, важно не забыть удалить это что-нибудь из памяти. Единственным исключением из этого правила является дочерняя форма MDI (Multiple Document Interface, многодоку ментный интерфейс), создаваемая как наследник родительской формы MDI; эти объекты удаляются системой после того, как программа будет выгружена из памяти по завершении работы. Во всех остальных случаях вы должны уничтожать все, что создали, используя оператор new, освобождая отведенную память при помощи оператора delete (уничтожить).

Великое изменение переход к многодокументным формам

Я хочу рассказать вам грустную, но абсолютно правдивую историю из своего программистского прошлого. Как-то несколько лет назад работал я в небольшой компании, разрабатывающей программные продукты. Мы получили задание конвертировать уже написанную программу под MS-DOS в приложение под Windows 3.1, используя для этого Visual C++ и MFC. После переговоров с менеджером по продажам и клиентами нам было велено разрабатывать программу, используя однодокументный (Single Document Interface, SDI) каркас. И я, и другие программисты нашей группы несколько раз спрашивали у них, уверены ли они в том, чего хотят, но они твердо стояли на своем. Складывалось ощущение, что человек, который проектировал программу, никогда не работал в среде Windows и в принципе не знаком с концепцией многодокументного интерфейса. В результате мы провели шесть месяцев, разрабатывая действительно неплохой программный продукт на основе однодокументной модели.

Но вот шесть месяцев закончились, и продукт наконец был готов к системному тестированию. Было приглашено несколько человек из главного управления, в котором слышали хорошие отзывы о нашей программе. Наверное, вы можете угадать конец истории. Один из старших менеджеров, который работал-таки в Windows (то есть просто использовал Word и Excel), взглянул на интерфейс нашей программы и сказал: «Неплохо. Сделайте-ка его многодокументным приложением».

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

Вы спросите в чем же мораль? Что вы должны лучше клиента знать, что ему надо? Возможно. Но тут есть одна небольшая проблема, связанная с тем, что обычно именно клиенты (или ваши шефы) платят за работу, и поэтому они подразумева ют, что все делается так, как им хочется. Если они передумали, ваша проблема переделать все заново, а не их.

К чему я клоню? Ну, давайте предположим, что ваш босс после демонстрации чудесного программного продукта Scribble вызывает вас к себе и заявляет: «Отличная работа. Сделайте теперь вашу программу многодокументной, чтобы можно было рисовать сразу в нескольких окнах. И чтобы изменение в одном отражалось и в остальных». Если бы вы использовали старый продукт типа Borland C++ или Visual C++, вам бы пришлось прийти к тому же решению, что и моей группе разработчиков когда-то: переписать все заново, а потом вставить соответствующие

Соседние файлы в предмете Программирование на C++