Главная » C++, C++ Builder » Scribble, третья попытка C++ Builder

0

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

Рис. 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);

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

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):

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);

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

__fastcall  TForm1::~TForm1(void)

{

delete FpBitmap;

}

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

Источник: Теллес М. – Borland C++ Builder. Библиотека программиста – 1998

По теме:

  • Комментарии