Энциклопедия C++ Builder

         

ГРАФИЧЕСКИЕ КОМПОНЕНТЫ


 

7. ГРАФИЧЕСКИЕ КОМПОНЕНТЫ

Операционная система Windows предоставляет разработчикам приложении мощные средства Интерфейса Графических Устройств GDI (Graphics Device Interface) для построения графических изображений независимо от типа используемого устройства вывода. К сожалению, GDI обременяет программистов множеством дополнительных действий (в частности, по управлению системными ресурсами), которые отвлекают разработчика от его основной задачи - создания графики.

C++Builder берет на себя всю вспомогательную работу GDI, освобождая разработчиков от непродуктивного программирования с поиском утерянных дескрипторов изображений и не освобожденных ресурсов памяти. Это вовсе не означает, что прямое обращение приложений к отдельным функциям Windows GDI запрещается - вы всегда сможете при необходимости вызывать их. Однако, инкапсуляция графических функций

Windows визуальными компонентами представляет собой более перспективную методику создания графики в вашем приложении.

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

7.1 Поддержка графики в C++Builder

C++Builder инкапсулирует функции Windows GDI на разных уровнях. Наиболее важным здесь является способ, посредством которого графические компоненты представляют свои изображения на экране монитора. При прямом вызове функции GDI необходимо передавать им дескриптор контекста устройства (device context handle), который задает выбранные вами орудия рисования - перья, кисти ц шрифты. После завершения работы с графическими изображениями, вы обязаны восстановить контекст устройства в исходное состояние и только потом освободиться от него.

Вместо того, чтобы вынуждать вас работать с графикой на таком уровне детализации, C++Builder предоставляет вам простой и завершенный интерфейс посредством свойства Canvas (Канва) графических компонент. Это свойство про-инициализирует правильный контекст устройства и освободит его в нужное время, когда вы прекратите рисование. По аналогии с функциями Windows GDI канва имеет вложенные свойства, представляющие характеристики пера, кисти и шрифта.


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

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

Листинг 7.1 содержит два фрагмента кода, которые наглядно иллюстрируют, насколько C++Builder упрощает программирование графики. Первый фрагмент применяет стандартные функции GDI для того, чтобы нарисовать в окне OWL приложения для Windows

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

void TMyWindow::Paint(TDC& PaintDC, bool erase, TRect& rect) {

HPEN PenHandle, OldPenHandle;

HBRUSH BrushHandle, OldBrushHandle;

PenHandle = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));

OldPenHandle = SelectObject(PaintDC, PenHandle);

BrushHandle = CreateSolidBrush(RGB(255, 255, 0));



OldBrushHandle = SelectObject(PaintDC, BrushHandle);

Ellipse(10, 10, 50, 50);

SelectObject(OldBrushHandle) ;

DeleteObject(BrushHandle) ;

SelectObject(OldPenHandle);

DeleteObject(PenHandle) ;

)

void_fastcall TFormI::FormPaint(TObject *Sender) {

Canvas->Pen->Color = clBlue; //

выбрать цвет контура Canvas->Brush->Color = clYellow; // выбрать цвет заливки Canvas->Ellipse(10, 20, 50, 50); // нарисовать эллипс }



Листинг 7.1. Использование функций

Windows GDI u свойства канвы на примере рисования эллипса.

7*2 Использование канвы

Объектный класс канвы инкапсулирует графические функции Windows на различных уровнях, начиная с функций высокого уровня для рисования отдельных линий” фигур и текста. Далее идут свойства и методы среднего уровня для манипуляций с канвой для рисования. Наконец, на нижнем уровне обеспечивается доступ к самим функциям Windows GDI. В следующей таблице обобщаются характеристики основных методов и свойств канвы.

Уровень Действие Методы Свойства
Высокий Определяет текущую позицию пера MoveTo PenPos
Рисует прямую до заданной точки LineTo PenPos
Рисует прямоугольник заданного размера Rectangle  

Рисует эллипс заданного размера Ellipse  

Выводит текстовую строку TextOut  

Задает высоту, отведенную для вывода текстовой строки TextHeight  

Задает ширину, отведенную для вывода текстовой строки TextWidth  

 

Вывод текста внутри прямоугольника TextRect  

Заливка указанного прямоугольника цветом и текстурой текущей кисти FillRect.  

Заливка области канвы (произвольной формы) заданным цветом FloodFill  

Средний Используется для установки цвета, стиля, ширины и режима пера  

Pen
Используется для установки цвета и текстуры при заливке графических фигур и фона канвы.  

Brush
Используется для установки шрифта заданного цвета, размера и стиля  

Font
Используется для чтение и записи цвета заданного пикселя канвы  

Pixels
Копирует прямоугольную область канвы в режиме

CopyMode
CopyRect CopyMode
Копирует прямоугольную область канвы с заменой цвета BrushCopy  

Рисует битовый образ, пиктограмму, метафайл в заданном месте канвы Draw  

Рисует битовый образ, пиктограмму или метафайл так, чтобы целиком заполнить заданный прямоугольник StretchDraw  

Низкий Используется как параметр при вызове функций Windows GDI  

Handle
<


 

7.3 Работа с рисунками

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

При работе с рисунками в среде C++Builder следует принимать во внимание три важных аспекта.

7.3.1 Рисунок, графика или канва9

В среде C++Builder существует три рода объектов, которые имеют отношение к графике:

• Канва предоставляет битовую карту поверхности для рисования на форме,

графической компоненте, принтере или на другом битовом образе. Канва не является самостоятельным объектом, она всегда является свойством какого-то другого графического объекта.

• Графика представляет растровое изображение некоторого файла или ресурса (битового образа, пиктограммы или метафайла). C++Builder определяет производные от базового класса TGraphic объектные классы

TBitmap, Ticon и TMetafile. Конечно, вы можете объявить свои собственные классы графических объектов. TGraphic предоставляет минимальный стандартный интерфейс для использования в вашем приложении всех видов графики.

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

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

Отметим, что объект "рисунок" всегда содержит некоторую графику, которой в свою очередь может потребоваться иметь канву (единственный стандартный графический класс с канвой - это TBitmap). Обычно, имея дело с рисунком, вы работаете только с той частью графического объекта, которая открыта для доступа через контейнер TPicture. Если вам надо указать доступ к конкретному графическому объекту, задайте его в свойстве Graphic данного рисунка.



7.3.2 Графические файлы

В любой момент работы вашего приложения C++Builder поддерживает загрузку и сохранение рисунков и графиков в файлах изображений стандартного формата. Имена сохраняемого и исходного файла изображений могут совпадать или различаться.

Для загрузки изображения в рисунок из файла воспользуйтесь методом рисунка

LoadFromFile. Чтобы сохранить изображение в файле, вызовите метод рисунка SaveToFile.

Единственным параметром этих методов является имя файла. Метод LoadFromFile использует расширение файла для распознавания вида графического объекта, который он создаст и загрузит. Метод SaveToFile сохраняет файл с расширением, соответствующим виду сохраняемого графического объекта.

Листинг 7.2 содержит инструкцию, которую вы должны записать в тексте кодового модуля для загрузки битового образа в компонентный объект рисунка.

void_fastcall TFormI::FormCreate(TObject *Sender) {

Imagel->Picture->LoadFromFile("c:\\windows\\clouds.bmp");

}

Листинг 7.2. Загрузка битового образа из файла clouds, bmp.

Рисунок распознает стандартное расширение файлов битовых образов .bmp и создает свою графику как объект класса TBitmap, а затем вызывает метод LoadFromFile загрузки изображения из файла с указанным именем.

7.3.3 Обслуживание палитр

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

этот процесс называется реализацией палитр (palette realizing).

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



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

При работе с устройством типа дисплея или принтера, компоненты C++Builder автоматически поддерживают механизм реализации палитр. Таким ;

образом, если ваша компонента имеет палитру, вы можете воспользоваться двумя методами GetPalette и

PaletteChanged, наследованными от базового компонентного класса

TControl, чтобы управлять тем, как Windows

обращается с этой палитрой:

• Связь палитры с компонентой. Если требуется использовать некоторую палитру для графической компоненты, ваше приложение должно узнать об этом. Чтобы ассоциировать палитру с вашей компонентой, перегрузите ее объектный метод GetPalette

так, чтобы он возвращал дескриптор

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

• Реакция на изменение палитры. Когда ваша компонента ассоциируется с некоторой палитрой посредством перегрузки метода GetPalette, C++Builder автоматически берет на себя реакцию на сообщения Windows от палитр с помощью метода PaletteChanged. При нормальной работе вам никогда не придется переопределять поведение этого метода, установленное по умолчанию. Основная задача метода PaletteChanged состоит в том, чтобы определить вид реализации палитры (для фоновых или активных окон). C++Builder продвигается на шаг вперед, по сравнению с реализацией палитр в

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



7.4 Внеэкранные битовые образы

Общепринятая методика программирования сложных графических приложении для

Windows заключается в создании внеэкранного битового образа, рисовании или заполнении его конкретным изображением и, наконец, копировании всего изображения из битового образа на указанное место экранного окна. Благодаря этому уменьшается заметное глазу мерцание экрана монитора, вызванное повторным рисованием непосредственно в экранном окне.

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

7.4.1 Копирование битовых образов.

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

Требуемый результат Метод
Полное копирование графики Draw
Копирование с масштабированием StretchDraw
Копирование прямоугольного участка канвы CopyRect
Копирование с растровыми операциями BrushCopy
 

7.4.2 Создание и обслуживание

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

Paint графических компонент.

Пример рисования сложного изображения на внеэкранном битовом образе дает Индикатор (Gauge),

представленный на вкладке Samples Палитры компонент. Исходные файлы Gauges.cpp

и Gauges.h

программного модуля компоненты TGauge можно найти в каталоге: \.. .\CBuilder\Examples\Controls\Source.

Фрагмент файла Gauges.cpp (Листинг 7.3) показывает основные операции, выполняемые компонентным методом Paint

рисования на канве внеэкранного битового образа TBitmap. Сначала функция PaintBackground закрашивает прямоугольную фоновую область индикатора цветом, выбранным в свойстве Color. Затем в соответствии с заданным значением свойства Kind контур нужной формы обводится цветом свойства



ForeColor и заливается цветом свойства BackColor (в нашем случае индикатора со стрелкой Kind = gkNeedle это выполняет функция PaintAsNeedle). Заключительные инструкции устанавливают свойство режима копирования канвы CopyMode, снабжают индикатор текстом (метод PaintAsText) и только затем (с помощью метода Draw)

канва внеэкранного битового образа отображается на экране.

void _fastcall TGauge::Paint()

{

std::auto_ptr<Graphics::TBitmap> Thelmage

(new Graphics::TBitmap() ) ;

std::auto_ptr<TBltBitmap> Overlaylmage (new TBitBitmap());

TRect PaintTRect;

The Image->Height = Height;

TheImage->Width = Width;

PaintBackgroundtThelmage.get()) ;

PaintTRect = ClientRect;

if (FBorderStyle == bsSingle)

InflateRect(&RECT(PaintTRect), -1, -1);

OverlayImage->MakeLike(Thelmage.get() ) ;

PaintBackground(Overlay Image.get());

switch(FKind) {

case gkText:

PaintAsNothing(Overlay Image.get(), PaintTRect); break;

case gkHorizontalBar:

case gkVerticalBar:

PaintAsBar(Overlaylmage.get(), PaintTRect); break;

case gkPie:

PaintAsPie(Overlay Image.get(), PaintTRect); break;

case gkNeedle:

PaintAsNeedle(Overlaylmage.get(), PaintTRect); break;

}

The Image->Canvas->CopyMode = cmSrcInvert;

TheImage->Canvas->Draw(0, 0, Overlaylmage.get()) ;

TheImage->Canvas->CopyMode = cmSrcCopy;

if (ShowText == true)

PaintAsText(Thelmage.get(), PaintTRect);

Canvas->CopyMode = cmSrcCopy;

Canvas->Draw(0, 0, Thelmage.get()) ;

}

Листинг 7 3 Метод рисования на канве компоненты индикатора.

Рис. 7.1 показывает, что текст программы, реализующей перемещение стрелки индикатора по сигналам таймера, состоит всего из двух строк обработчика события OnTimer компоненты TTimer из вкладки System. Первая инструкция функции обработки события Timer1Timer устанавливает значение 1000 (принятое по умолчанию) для односекундного интервала времени объекта Timer1, а вторая инкрементирует значение свойства Progress объекта Gauge 1.



Рис. 7.1. Индчкппюр в виде шкалы со стрелкой (см. свойство Kind).



Если вы соберете и запустите это приложение, то сможете убедиться, что при движении стрелки индикатора с любой скоростью, мерцание экрана монитора действительно отсутствует.

7.4.3 Реакция на изменения

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

Реакция на изменения объектов графической компоненты особенно важна в том случае, если эти объекты объявлены в исходном файле модуля компоненты как published. Тогда единственный способ обеспечить, чтобы вид компоненты на стадии проектирования приложения соответствовал свойствам, установленным Инспектором объектов, заключается в подключении обработчика события, который будет реагировать на изменения компонентного объекта. Для графических компонент вы должны предусмотреть реакцию на событие OnChange.

class TMyShape : public TGraphicControl

{

public:

virtual _fastcall TMyShape(TComponent* Owner);

__publi shed:

TPen *FPen;

TBrush *FBrush;

void_fastcall StyleChanged(TObject *Sender) ;

};

_fastcall TMyShape::TMyShape(TComponent* Owner)

: TGraphicControl(Owner) {

Width = 64;

Height = 64;

PPen = new TPen;

FPen->OnChange = StyleChanged; //

изменить стиль пера

FBrush = new TBrush;

FBrush->OnChange = StyleChanged; //

изменить стиль кисти }

void_fastcall TMyShape::StyleChanged(TObject *Sender) (

Invalidate();

}

Листинг 7.4. Содержание файлов Unit1.h и Unit1.cpp компоненты TMyShape.

Графическая компонента рисования геометрических фигур TShape Библиотеки Визуальных Компонент объявляет свои свойства, представляющие перо и кисть, в секции _published.

Конструктор компонентного объекта присваивает метод StyleChanged

событию OnChange, заставляя компоненту перерисовывать изображенные на ней фигуры при любом изменении пера или кисти. Хотя оригинальный текст компоненты TShape написан на языке Объектный Паскаль, Листинг 7.4 приводит его трансляцию на C++ с новым именем TMyShape.



7.5 Разработка графического приложения

Вот уже более 20 лет автор специализируется на системах обработки изображений, полученных при космической съемке Земли и других объектов Солнечной системы. Создан существенный задел алгоритмов и программ, реализованных на Borland C++ версии 4.5 для операционной системы Windows. Сюда относятся программы статистического анализа и сжатия многозональных изображений, геометрического трансформирования, ортогональных преобразований в область пространственных частот и многие другие. Заканчивая книгу, я мог бы предложить читателю проследить на выбранном примере за переводом этих приложений в среду C++Builder. Именно этой деятельностью я и занимаюсь в последнее время.

Однако мне кажется, что такой пример представлял бы узко профессиональный интерес для ограниченного числа прикладных программистов. Поэтому я выбрал задачу из совершенно другой области, которая интриговала меня много лет, с момента появления первых качественных игровых программ. Как реализуется эффективная компьютерная графика в приложениях анимации? Неужели можно достичь требуемого быстродействия на языке высокого уровня, таком как C++, не прибегая к утомительному программированию на ассемблере?

Возможно, многие читатели задавали себе подобные вопросы и, так же как и автор, не находили доходчивых ответов в литературе, не рискнули "потерять время даром" и попробовать свои силы самостоятельно запрограммировать подобную задачу. Любопытному читателю адресуется разработка в среде C++Builder простого графического приложения анимации, за основу которого взят алгоритм Давида Свэнни.

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

Фактически приложение MOVEIT и заключается в использовании объектов Sprite

класса SpriteClass



с буферизацией графики. Более полная иллюзия движения фигур на экране достигается за счет автоматической прокрутки изображения фона. Большая часть времени ушла на подготовку изображений битовых образов фона и различных движущихся фигур (самолетов и вертолетов). Я использовал для этой цели систему Corel

Draw!, хотя любой другой имеющийся в вашем распоряжении редактор изображений справился бы с рисованием простейших картинок.

7.5.1 Проектирование формы

Начнем проектирование приложения, перетаскивая из Палитры на форму следующие компоненты:

=> Три невидимых и пустых контейнера TImage из вкладки Additional и один видимый и пустой контейнер TPaintBox из вкладки System. Объекты DrawBox класса TImage и PaintBox класса TPaintBox совместно реализуют двойную буферизацию графики: сначала фигуры и фон рисуются на канве внеэкранного битового образа, в объекте DrawBox, а затем изображение канвы копируется на экран, в объект PaintBox.

=> Панель инструментов TPanel из вкладки Standard.

=^> Таймер TTimer из вкладки System.

=> Компоненту редактирования TSpinEdit с кнопками "а" и "-у" из вкладки Samples для управления скоростью анимации.

=> Три быстрые кнопки TSpeedButton из вкладки Additional для управления работой программы.

=^ Компоненту TOpenDialog из вкладки Dialogs диалога открытия файлов.

Рис. 7.2 показывает форму приложения, фоном которой служит изображение облачного неба из файла Clouds.bmp,

а в качестве движущихся фигур выступают два самолета из файла Planes, bmp

или два вертолета из файла Helicopters.bmp. Редактор изображений открыт двойным щелчком мышью в графе значений свойства Picture компонентного объекта Figures.

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





Рис. 7.2. Форма приложения анимации.

7.5.2 Программный модуль

К файлу модуля Unit1.h (Листинг 7.5) добавлено описание структуры FigureType, включающей позицию (X,Y), смещение (DX,DY) фигуры и номер объекта спрайта (SD); а в секции public класса формы объявлены четыре переменные размеров изображений, две фигуры Fig [2] и соответствующие им две пары спрайтов Sprite [4]. Класс SpriteClass и его методы определены в файлах Sprite.h и Sprite.cpp, соответственно.

ttifndef UnitlH

#define UnitlH

#include <vcl\Classes.hpp> ttinclude <vcl\Controls.hpp> ftinclude <vcl\StdCtrls.hpp>

#include <vc1\Forms.hpp> ttinclude "sprite.h"

#include <vcl\Buttons.hpp> ftinclude "sampreg.h" ftinclude <vcl\Dialogs.hpp>

typedef struct { int X, Y, DX, DY, SD; } FigureType;

class TFormI : public TForm (

_published: // IDE-managed Components TPaintBox *PaintBox;

TImage *DrawBox;

TImage *Background;

TImage *Figures;

TTimer *Timerl;

TPanel * Panel 1;

TSpeedButton *SpeedButtonl;

TSpeedButton *SpeedButton2;

TSpeedButton *SpeedButton3;

TSpinEdit *SpinEditl;

TOpenDialog *OpenDialog;

void _fastcall TimerlTimer(TObject * Sender);

void _fastcall SpinEditlKeyUp(TObject *Sender, WORD &Key, TShiftState Shift);

void _fastcall SpinEditlKeyDown(TObject * Sender,

WORD &Key, TShiftState Shifts-void_fastcall SpeedButtonlClick(TObject *Sender) ;

void_fastcall SpeedButton2Click(TObject * Sender);

void_fastcall SpeedButton3Click(TObject * Sender);

private: // User declarations public: // User declarations _fastcall

TFormI(TComponent* Owner);

int W, H, w, h;

FigureType Fig[2];

SpriteClass Sprite[4];

};

extern TFormI *Forml;

#endif

Листинг 7.5. Содержание файла Unii1.h.

Файл модуля Unit1.cpp (Листинг 7.6) содержит 5 обработчиков событий от нажатия кнопок управления и обработчик события таймера.

//-_---------_____________-___-_-----__-____________________-

^include <vcl\vcl.h>

#pragma hdrstop

#include "Unitl.h"



#pragma link "sampreg"

#pragma resource "*.dfm" TFormI *Forml;

//----------------——--——--—------———------—-----------

_fastcall TFormI::TFormI(TComponent* Owner) : TForm(Owner) ( // Конструктор формы устанавливает размеры по умолчанию W = Н = 400; w = h =61;

} //----------------------------------------------------------

void_fastcall TFormI::SpeedButtonlClick(TObject *Sender) { if

(OpenDialog->Execute())

{ // Открыть файл изображения фона

Background->Picture->LoadFromFile(OpenDialog->FileName) ;

W = Background->Picture->Width;

H = Background->Picture->Height;

}

} //----—----------——-------—-——---—-—-—-------------

void_fastcall TFormI::SpeedButton2Click(TObject *Sender) { if

(OpenDialog->Execute())

{ // Открыть файл изображения фигур

Figures->Picture->LoadFromFile(OpenDialog->FileName);

w = (Figures->Picture->Width)/6;

h = Figures->Picture->Height;

//______---------------------------------------------------

void_fastcall TFormI::SpeedButton3Click(TObject *Sender)

{ // Инициализировать поля структуры обеих фигур Fig[0].X = W/4; Fig[l].X = 3*W/4;

Fig[0].Y = H/4; Fig[l].Y = 3*H/4;

Fig[0].DX = 1; Fig[l].DX = -1;

Fig[0].DY = 1; Fig[l].DY = -1;

Fig[0].SD = 0; Fig[l].SD = 0;

// Подготовить экземпляры спрайта

Sprite[0].SetSprite(Figures->Canvas, 0,0, 4*w,0, w,h);

Sprite[1].SetSprite(Figures->Canvas, 2*w,0, 4*w,0, w,h);

Sprite[2].SetSprite(Figures->Canvas, w,0, 5*w,0, w,h);

Sprite[3].SetSprite(Figures->Canvas, 3*w,0, 5*w,0, w,h) ;

Timerl->Enabled = true;

}

void _fastcall TFormI::SpinEditlKeyUp(TObject *Sender,

WORD &Key, TShiftState Shift) { Timerl->Interval++; } void _fastcall

TFormI::SpinEditlKeyDown(TObject *Sender,

WORD &Key, TShiftState Shift) { Timerl->Interval--; } //-.____-_-_-_-_.....____.__________________________________

int Shift = 0; // переменная прокрутки фона void _fastcall

TFormI::TimerlTimer(TObject *Sender) ( //

Сместить фигуры в пределах периметра



Fig[0].X += Fig[0].DX; Fig[0].Y += Fig[0].DY;

if (Fig[0].X > (W/2-w)) Fig[0].DX = -1;

if (Fig[0].X < 20) Fig[0].DX = 1;

if (Fig[0].Y > (H-2*h)) Fig[0].DY = -1;

if (Fig[0].Y < 20) Fig[0].DY = 1 ;

Fig[l].X += Fig[l].DX; Fig[l].Y += Pig[l].DY;

if (Fig[l].X > (W-w)) Fig[l].DX = -1;

if (Fig[l].X < (W/2+w)) Fig[l].DX = 1;

if (Fig[l].Y > (H-h)) Fig[l].DY = -1;

if (Fig[l].Y < 30) Fig[l].DY = 1 ;

// Оживить фигуры, переключая экземпляр спрайта

Fig[0].SD = (Fig[0].SD == 0) ? 2 : 0;

Fig[l].SD = (Fig[l].SD == 1) ? 3 : 1 ;

// Нарисовать фон и сдвинуть его влево

if (Shift == 0)

{ DrawBox->Canvas->CopyMode = cmSrcCopy;

DrawBox->Canvas->CopyRect(Rect(О, О, W, H),

Background->Canvas, Rect(0, 0, W, H));

}

else

{ DrawBox->Canvas->CopyMod^s = cmSrcCopy;

DrawBox->Canvas->CopyRect(Rect(0, 0, W-Shift, H),

Background->Canvas, Rect(Shift, 0, W, H) ) ;

DrawBox->Canvas->CopyRect(Rect(W-Shift, 0, W, H),

Background->Canvas, Rect(0, 0, Shift, H)) ;

}

Shift += 2;

if (Shift >= W) Shift -= W;

// Нарисовать фигуры на канве внеэкранного битового образа

Sprite[Fig[0].SD].Draw(DrawBox->Canvas,Fig[0].X, Fig[0].Y) ;

Sprite[Fig[l].SD].Draw(DrawBox->Canvas,Fig[1].X, Fig[l].Y) ;

// Скопировать изображение на экран

PaintBox->Canvas->CopyMode = cmSrcCopy;

PaintBox->Canvas->CopyRect(Rect(0, 0, W, H),

DrawBox->Canvas, Rect(0, 0, W, H)) ;

}

Листинг 7 6 Содержание файла Unit1 cpp.

Быстрые кнопки компонент TSpeedButton служат для управления программой. Первая кнопка открывает и загружает объект Background

класса TImage

из файла с изображением фона (размером w на H). Вторая кнопка открывает и загружает объект Figures класса TImage из файла с изображениями фигур (размером w на h каждая).

Третья кнопка устанавливает фигуры в начальные позиции и подготавливает объекты спрайта посредством обращении к методу

SetSprite., а затем запускает таймер.

Нажатие кнопок компоненты редактирования TSpinEdit вызывает увеличение или уменьшение на единицу значения интервала таймера (по умолчанию устанавливается значение 40, соответствующее кадровой частоте 1/25 сек).



Ядром приложения является обработчик события OnTimer объекта Timerl. Первый блок кода реакции на прерывание от таймера отвечает за перемещение фигур, изменяя направление движения всякий раз, когда они "утыкаются" в фиксированные границы отведенного периметра. Рис. 7.3 изображает структуру канвы объектов DrawBox и PaintBox.



Рис. 7.3. Структура канвы для рисования движущихся фигур.

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

Shift. Заключительный блок рисует, при помощи метода Draw, фигуры на канве невидимого объекта DrawBox, а затем копирует изображение канвы на экран, в видимый объект PaintBox.

7.5.3 Спрайты

Экземпляры класса SpriteClass (Листинг 7.7) обеспечивают анимацию одной маскируемой фигуры. Банк данных спрайта содержит канву невидимой компоненты TImage с битовыми образами фаз. Естественно, что все изображения банка данных спрайта должны быть одинакового размера. Изображения фаз анимации должны иметь черный фон, маска контура - белый.

class SpriteClass

private:

TCanvas *SpriteCanvas;

int ImageLeft, ImageTop;

int MaskLeft, MaskTop;

int Width, Height;

public:

void SetSprite(TCanvas *aSpriteCanvas,

int aImageLeft, int aImageTop, int aMaskLeft, int aMaskTop, int

aWidth, int aHeight);

void Draw( TCanvas *aDrawCanvas, int aLeft, int aTop) ;

);

Листинг 7.7. Объявление класса спрайта в файле Spite, h.

В классе спрайта определены только два метода установки и рисования спрайта (Листинг 7.8). При вызове метода SetSprite аргументы aImageLeft и aImageTop определяют позицию спрайта на канве aSpriteCanvas, аргументы aMaskLeft и

MaskTop - позицию маски, аргументы aWidth и aHeight - размеры спрайта. При вызове метода Draw



аргумент aDrawCanvas задает канву рисования, а аргументы aLeft и aTop - позицию спрайта на этой канве.

void SpriteClass::SetSprite(TCanvas *aSpriteCanvas,

int aImageLeft, int aImageTop, int aMaskLeft, int aMaskTop, int aWidth, int aHeight) { SpriteCanvas = aSpriteCanvas;

ImageLeft = aImageLeft;

ImageTop = aImageTop;

MaskLeft = aMaskLeft;

MaskTop = aMaskTop;

Width = aWidth;

Height = aHeight;

} void SpriteClass::Draw(TCanvas *aDrawCanvas,

int aLeft, int aTop) { aDrawCanvas->CopyMode = cmSrcAnd;

aDrawCanvas->CopyRect(Rect(aLeft, aTop,

aLeft+Width, aTop+Height), SpriteCanvas, Rect(MaskLeft, MaskTop, MaskLeft+Width, MaskTop+Height)) ;

aDrawCanvas->CopyMode = cmSrcPaint;

aDrawCanvas->CopyRect(Rect(aLeft, aTop,

aLeft+Width, aTop+Height), SpriteCanvas,

Rect(ImageLeft, ImageTop, ImageLeft+Width.ImageTop+Height));

}

Листинг 7.8. Определение методов класса спрайта в файле Sprite.cpp.

Довольно трудно составить впечатление от работы приложения анимации по снимку одного кадра - тем более в черно-белом исполнении (Рис. 7.4). Книга не является подходящим носителем для распространения компьютерных мультфильмов. Если проблема вас заинтересовала, нет другого способа изучать ее дальше, как придумать и подготовить картинки и разработать собственное приложение, используя приведенные листинги в качестве прототипа.



Рис. 7.4. Снимок с экрана работающего приложения MOVEIT.

Сами фигуры представляют собой массив типа структуры, а не экземпляр какого-то класса. Однако не надо быть гениальным программистом, чтобы ввести логику работы с фигурами в соответствующий класс FigureClass, который будет инкапсулировать, в частности, свойство периметра и метод перемещения. Однако не стоит наследовать SpriteClass от класса фигур. Дело в том, что экземпляры этих классов имеют разную природу: спрайты - это графические объекты, а фигуры - логические конструкции. Если бы вам потребовалось произвести анимацию более, чем двух одинаковых фигур, все они по-прежнему будут разделять единственный класс спрайта, используя поле структуры Fig [ I ] . SD для связи I-фигуры с нужным экземпляром спрайта.

Взгляните на изображения фаз анимации самолета или вертолета. На второй фазе каждой фигуры пропеллер просто отсутствует. Постоянно переключая фазы, можно создать иллюзию вращения пропеллера. Зная, что программа не моделирует фактическое вращение, спросите, тем не менее, у наблюдающего за работой приложения: "В какую сторону вращается пропеллер?" - и любой уверенный ответ убедит вас в том, что время на программирование примера было потрачено не зря. Можно придумать какой-нибудь другой впечатляющий эффект, например, стреляющего пулемета. Расширяя банк данных спрайта дополнительными фазами фигур и соответствующими масками, можно добиваться различных эффектов


ИНСТРУМЕНТЫ ВИЗУАЛЬНОЙ РАЗРАБОТКИ ПРИЛОЖЕНИЙ


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

Интегрированная среда разработки C++Builder IDE (Integrated Development Environment), предназначенная для эффективной разработки приложений, поможет вам воспользоваться ее новшествами и в полной мере ощутить преимущества нового стиля программирования. Вы сможете быстро переводить приложение из стадии начального прототипа в рабочую программу. В главе 2 читатель уже составил общее представление о работе с базовыми инструментальными средствами C++Builder - Палитрой компонент. Редакторами форм и кода. Инспектором и Хранилищем объектов. В данной главе мы продолжим знакомство с этими и другими инструментами среды C++Builder, уделяя особое внимание описанию визуальных компонент, представленных на Палитре.

4.1 Администратор проекта

Администратор проекта предназначен для манипуляций с текущим проектным файлом с расширением .срр. Чтобы открыть окно администратора (Рис. 4.1), выполните команду View [ Project Manager.

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

Запись изменений проекта
Установка проектных опций
Включение редактора форм
Включение редактора кода
Вычеркивание файла из списка
Добавление файла к проекту
Список ассоциированных файлов проекта
Контекстное меню администратора проекта

Рис. 4.1. Окно администратора проекта.

Открыть контекстное меню администратора проекта можно щелчком правой кнопкой мыши в любом месте окна администратора или нажатием клавиш Alt+FlO. Контекстное меню содержит следующие опции:


1. Командой File | New Application создайте новое приложение.

2. Командой File | New Form ( кнопка быстрого вызова) создайте новую форму.

3. Командой File | Open Project (кнопка быстрого вызова) откройте существующий проект.

Добавить компоненту к форме можно одним из способов:

1. Найдите нужную компоненту на вкладках Палитры компонент и щелкните на ней левой кнопкой мыши. Переведите курсор в окно Редактора и вновь щелкните мышью.

2. Дважды щелкните левой кнопкой мыши на нужной компоненте.

Закрыть активное окно Редактора форм можно одним из способов:

1. Кнопкой в правом верхнем углу окна или клавишами Alt+F4.

2. Командой File | Close.

Закрыть все окна, кроме окна Инспектора объектов, можно командой File | Close All.

Если вы модифицировали текущую форму и не сохранили изменения, C++Builder выдаст предупреждение и откроет диалог команды File | Save As, чтобы вы могли ввести новое имя модуля (по умолчанию, Unit1). Если вы модифицировали текущий проект и не сохранили изменения, C++Builder выдаст предупреждение и откроет диалог команды File | Save As, чтобы вы могли ввести новое имя файла проекта (по умолчанию. Project 1).

Чтобы получить контекстно-зависимую справку при работе с Редактором форм, выберите компоненту, о которой вы хотите получить справочные сведения, и нажмите клавиши Ctrl+Fl. Если искомые сведения не обнаружены, справочная служба Help

выдаст сообщение "Help Topic Does Not Exist".

4.3 Инспектор объектов

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

Свойства (Properties) и События (Events).

Вкладка свойств дает вам возможность манипулировать свойствами компонент, помещаемых на форму (и свойствами самой формы) на стадии проектирования, определяя тем самым начальное состояние компонент. Установка свойств компонент во время выполнения программы требует написания соответствующих текстов кода для обработки событий. Свойство может, в свою очередь, включать вложенные свойства, что отмечается знаком "+" в левой позиции соответствующей графы базового свойства.



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

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

Значение fsNormal свойства FormStyle самой формы означает, что вы создаете SDI

приложение с однодокументным интерфейсом, а значение fsMDIForm - MDI приложение с многодокументным интерфейсом. Обратите внимание, что свойству Sorted компоненты TListBox присвоено значение

true, поэтому элементы списка будут упорядочены в алфавитном порядке.



Рис. 4.2. Свойства компоненты TListBox в окне Инспектора объектов.

Открыть контекстное меню Инспектора объектов можно щелчком правой кнопкой мыши в любом месте окна Инспектора или нажатием клавиш

Alt+FlO. Контекстное меню содержит следующие опции управления и установок:

• Revert to Inherited

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

• Expand показывает вложенные свойства объекта. Такое же действие вызывает двойной щелчок мышью по выбранному базовому свойству.

• Collapse прячет отображение вложенных свойств объекта. Такое же действие вызывает двойной щелчок мышью по выбранному базовому свойству.

• Stay On Top

располагает окно Инспектора поверх остальных окон и диалогов среды C++Builder.

• Hide прячет активное окно Инспектора, которое открывается вновь клавишей F11 или по команде View | Object Inspector.



• Help вызывает соответствующую страницу справочной службы.

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

 

4.4 Хранилище объектов

Хранилище объектов обеспечивает возможность разделения (sharing) или повторного использования (reuse) содержащихся в нем объектов. В качестве объектов хранения могут выступать либо подготовленные C++Builder, или созданные вами формы, проекты, модули данных и эксперты. Кроме самих объектов, вы можете адресовать в хранилище их шаблоны, в которых зафиксированы только неизменяемые в процессе разработки компоненты.

Хранилище в сущности является индексным текстовым файлом, содержащим ссылки на страницы, объединяющие указанные объекты.

4.4.1 Разделение объектов

При разделении объектов разработчик приложения может преследовать разные цели:

Разделение объектов между проектами.

Добавляя формы, диалоги и модули данных к хранилищу, вы делаете их доступными другим проектам.

Например, все ваши проекты могли бы использовать диалог часто используемой команды меню About,

содержащий, наряду с фиксированными текстами и кнопками управления, пустые поля для записи фамилий авторов приложения, года выпуска и т.д. Из этого шаблонного диалога все ваши проекты произведут диалоги стандартизованного вида, заполняя переменные поля новым конкретным содержанием.

Разделение объектов внутри проекта.

Вы можете наследовать формы, уже включенные в проект. Открывая командой File | New диалог New Items, вы увидите вкладку с именем вашего проекта. Если щелчком мыши выбрать эту вкладку, откроются списки всех форм, диалогов и модулей данных этого проекта. Затем можно произвести новый объект - форму из существующей и приспособить ее по назначению.

Например, некоторому приложению СУБД может понадобиться несколько форм, отображающих одни и те же данные, но с разными кнопками управления. Вместо того, чтобы создавать ряд почти идентичных форм, добавьте к хранилищу единую форму с общими элементами отображения данных, а затем из этой шаблонной формы производите формы с разными кнопками. Тщательно планируя содержание форм вашего проекта, вы сэкономите массу времени и усилий, которые понадобились бы при повторной разработке сходных форм в одном проекте.



Разделение проектов.

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

Использование экспертов.

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

4.4.2 Включение объектов в проект

Существует три способа включения в проект объектов из хранилища с целью их разделения:

Копирование объектов хранилища.

Простейший вариант разделения заключается в копировании точного дубликата объекта в ваш проект. Будущие изменения этого объекта в хранилище никак не отразятся на вашей копии, и наоборот, модификации копии не коснутся оригинала объекта в хранилище.

Замечание. Копирование представляет единственную возможность использования проектных шаблонов.

Наследование объектов хранилища.

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

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

Прямое использование объектов хранилища.

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



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

Разработка нового проекта может начинаться не с пустого проекта (с именем Project 1 по умолчанию), а с некоторого шаблона из хранилища объектов.

Чтобы открыть новый проект на базе шаблона:

1. Выполните команду File | New, которая откроет диалог New Items.

2. Выберите вкладку Projects.

3. Укажите нужный шаблон и нажмите кнопку ОК.

4. В открывшемся диалоге Select Directory укажите каталог, в котором хранятся

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

4.4.3 Добавление объектов к хранилищу

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

Чтобы добавить новый объект к хранилищу:

1. Выполните команду Project | Add To Repository, которая откроет диалог, показанный на Рис. 4.3.

2. В область редактирования Title введите название объекта.

3. В область Description введите описание объекта.

4. Из выпадающего списка Page выберите имя страницы, в которой вы хотите завести новый объект.

5. В область Author введите фамилию автора.

6. Нажмите кнопку Browse, чтобы выбрать пиктограмму, которая будет представлять объект в хранилище.

7. Нажмите кнопку ОК, чтобы сохранить текущий объект.

Имя объекта

Кнопка выбора пиктограммы
Описание объекта
Автор объекта
Страница объектов указанного типа
<


Рис. 4.3. Добавление формы к хранилищу объектов.

Чтобы добавить к хранилищу проект или форму в виде шаблона:

1. Если необходимо, откройте проект или форму, шаблоны которых вы хотите добавить к хранилищу.

2. Выполните команду Tools | Repository.

3. На вкладке Project Templates (или Form Templates) выберите команду

Add, которая отроет диалог Save Project Template (или Save Form Template).

4. В область редактирования Title введите название проекта или формы.

5. В область Description введите описание проекта или формы.

6. Из выпадающего списка Page выберите имя страницы Projects (или Forms), в которой вы хотите завести соответствующий шаблон.

7. В область Author введите фамилию автора.

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

9. Нажмите кнопку ОК, чтобы сохранить текущий проект или форму в виде шаблона.

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

Чтобы увидеть описание выбранного объекта:

1. Выполните команду File | New, которая откроет диалог New Items.

2. Выберите вкладку объектов нужного типа.

3. Щелкните правой кнопкой мыши по выбранному объекту.

4. Из появившегося контекстного меню выберите опцию View Details. Описание объекта появится в столбце Description.

4.4.4 Проект и формы, создаваемые по умолчанию

Проект по умолчанию для нового приложения открывается с помощью команды File |

New Application. Если вы не меняли соответствующих установок хранилища объектов, C++Builder создаст пустой проект с пустой формой. Вы можете сменить шаблон проекта по умолчанию, а также назначить запуск некоторого эксперта проектов, который проведет вас через ряд диалогов, руководящих созданием нового проекта.

Чтобы сменить проект по умолчанию:

1. Выполните команду Tools | Repository, чтобы открыть диалог хранилища Object Repository.

2. Выберите страницу с именем Projects из списка Pages.



3. Укажите проект, который вы хотите создавать по умолчанию, в списке Objects.

4. Выберите опцию New Project.

5. Нажмите кнопку OK для регистрации новой установки по умолчанию.

Новая форма по умолчанию для существующего проекта открывается с помощью

команд File | New Form (кнопка быстрого вызова). Если вы не меняли соответствующих установок хранилища объектов, C++Builder создаст пустую форму. Вы можете сменить шаблон формы по умолчанию, а также назначить запуск некоторого эксперта форм, который проведет вас через ряд диалогов, руководящих добавлением новой формы к проекту.

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

1. Выполните команду Tools | Repository, чтобы открыть диалог хранилища Object Repository.

2. Выберите страницу с именем Forms из списка Pages.

3. Укажите форму, которую вы хотите создавать по умолчанию, в списке Objects.

4. Выберите опцию New Form.

5. Нажмите кнопку OK для регистрации новой установки по умолчанию.

Основная форма (или эксперт форм) по умолчанию для нового проекта устанавливается в хранилище объектов точно так же, как и форма для существующего проекта.

Чтобы сменить основную форму по умолчанию для нового проекта:

1. Выполните команду Tools | Repository, чтобы открыть диалог хранилища Object Repository.

2. Выберите страницу с именем Forms из списка Pages.

3. Укажите форму, которую вы хотите создавать по умолчанию, в списке Objects.

4. Выберите опцию Main Form.

5. Нажмите кнопку OK для регистрации новой установки по умолчанию.

4.5 Редактор кода

Редактор кода программ предоставляет удобное и надежное средство для просмотра и редактирования текста программного модуля (Unit), независимо компилируемого в объектный файл. Модуль состоит из двух частей: файла объявлений с расширением .h и кодового файла с расширением .срр.

Окно Редактора может содержать несколько вкладок с редактируемыми файлами. Например, когда вы начинаете работу с открытия некоторого проекта, он становится первой вкладкой в окне Редактора; вкладки всех других отрываемых файлов занимают последовательные позиции в ряду вкладок.



C++Builder автоматически отрывает в окне Редактора новую вкладку с текстом модуля в следующих ситуациях:

1. Командой File | New Application создается новое приложение.

2. Командой File | New Form (кнопка IS1 быстрого вызова) создается новая фор ма.

3. Командой File | New Unit создается новый модуль.

4. Командой File | Open Project (кнопка 1в 1 быстрого вызова) открывается существующий проект.

5. Командой File | Open (кнопка 1^1 быстрого вызова) открывается существующий файл текста модуля. По умолчанию вам будут предложены кодовые файлы с расширением .срр. Вы можете сменить установки умолчания для текущего каталога и расширений файлов на вкладке Directories/Conditionals

диалога команды Options | Project.

6. Командой Project | Add to Project (кнопка Ц.а| быстрого вызова) к проекту добавляется текущая форма или модуль.

Чтобы редактировать текст модуля:

1. Выберите вкладку окна Редактора с именем нужного модуля или укажите его

в списке, предлагаемом командой

View | Units (кнопка IQH быстрого вызова). Если вы хотите создать новое окно Редактора, воспользуйтесь командой View | New Edit Window.

2. Поместите курсор в то место текста, которое вы хотите редактировать.

3. Редактируйте текст с помощью операций, принятых стандартными редакторами

Microsoft Windows. Вводимые строки программы разделяются нажатием

клавиши Enter.

Если вы модифицировали текст текущего модуля и не сохранили изменения, C++Builder выдаст предупреждение и откроет диалог Save As, чтобы вы могли ввести новое имя файла модуля (по умолчанию, Uniti). Если вы модифицировали текущий проект и не сохранили изменения, C++Builder выдаст предупреждение и откроет диалог Save As, чтобы вы могли ввести новое имя файла проекта (по умолчанию, Project1).

 

Закрыть модуль в окне Редактора кода можно одним из способов:

1. Кнопкой в правом верхнем углу окна или клавишами Alt+F4.

2. Командой File | Close.

3. Окно Редактора закрывается только тогда, когда все находящиеся в нем файлы были закрыты.

Важнейшей особенностью C++Builder является автоматическая генерация строк программы. Когда вы добавляете компоненту к форме, в тексте файла Unit1.h появляется объявление переменной экземпляра класса данной компоненты. Например, перенос на пустую форму компоненты кнопки TButton



сгенерирует объявление объекта Button 1, а определение события OnClick -

объявление метода ButtonlClick обработчика этого события (Рис. 4.4).



Рис. 4.4. C++Biiilder генерирует объявления в файле модуля Unit1.h.

Открыть контекстное меню Редактора кода можно щелчком правой кнопкой мыши в любом месте окна Редактора или нажатием клавиш AIt+FlO. Контекстное меню содержит следующие опции для просмотра исходного текста вашей программы и ее отладки:

• Swap Cpp/Hdr Files

переключает файлы составляющих редактируемого модуля Unit.cpp/Unit.h.

• Close Page закрывает текущую вкладку с текстом редактируемого файла модуля.

• Open File At Cursor

открывает текстовый файл модуля, начиная с текущей позиции курсора.

• New Edit Window

открывает новое окно Редактора кода.

• Topic Search выдает контекстно-зависимую справку о слове в тексте модуля, на которое наведен курсор. Если искомые сведения не обнаружены, справочная служба выдаст сообщение "Help Topic Does Not Exist".

• Toggle Breakpoint

включает и выключает останов программы в точке текста, указанной курсором. Чтобы модифицировать свойства точки останова, выполните команду View | Breakpoints и в списке Breakpoint list щелкните правой кнопкой мыши на выбранной точке.

• Run to Cursor запускает загруженную программу до точки текста, указанной курсором. Такое же действие вызывает команда Run | Run To Cursor.

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

Run | Step Over или Run | Trace Into

• Go to Address переходит к заданному адресу в ассемблерной программе (см. опцию View CPU).

• Inspect открывает окно инспекции выделенного символа. Символ может быть обнаружен не только в текущем, но и в любом исходном файле, скомпилированном и собранном как часть одного проекта. Чтобы поиск символа производился, необходимо разрешить опции компиляции Local symbols и Symbol info на вкладке Pascal диалога команды

Options | Project.



• Evaluate/ Modify открывает диалог, который дает возможность вычислить значение некоторого выражения или изменить его значение. Такое же действие вызывает команда Run | Evaluate/Modify.

• Add Watch at Cursor

открывает диалог, который позволяет следить за изменением значения выражения, на которое указывает курсор. Все отслеживаемые выражения заносятся в список Watch List. Подобное действие вызывает команда Run | Add Watch .

• Read Only

устанавливает атрибут "только чтение", запрещающий делать какие-либо изменения текущего файла. Это состояние файла отображается в нижней строке состояния Редактора кода.

• Message View открывает окно сообщений и ошибок, полученных на фазах компиляции и сборки программы.

• View CPU открывает окно отладчика нижнего уровня - ассемблерных команд.

• Properties позволяют просматривать и изменять текущие установки Редактора кода.

4.6 Палитра компонент

C++Builder поставляется вместе с усовершенствованной 32-разрядной Библиотекой Визуальных Компонент VCL (Visual Component Library),

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

Библиотека включает полную инкапсуляцию стандартных интерфейсных объектов Графического Интерфейса Пользователя операционных систем Windows и Windows 95 (области редактируемого ввода, простые и комбинированные списки и многие другие), наряду со специализированными компонентами, среди которых особое место занимают компоненты для управления реляционными базами данных. Читателям, заинтересованным общей методикой и особенностями разработки приложений для баз данных, адресована отдельная глава 5.

C++Builder в полной мере использует возможности объектно-ориентированного программирования (ООП) для создания надежных и эффективных приложений. Поскольку C++Builder это среда ООП, введение управляющих элементов OLE (OCX) не вызывает особых трудностей. Используйте имеющиеся компоненты Библиотеки, расширяйте возможности производных компонент так, чтобы наилучшим образом удовлетворить требованиям вашей задачи.



Ключевая характеристика C++Builder заключается в его способности не только пользоваться готовыми компонентами в процессе визуальной разработки программ, но и создавать новые компоненты. Новые компоненты могут быть такими же простыми, как исходные, со слегка расширенными функциональными возможностями, или отличаться совершенно оригинальным видом, поведением и кодовым содержанием. Эти проблемы рассматриваются подробно в главе 6. Создание компонент базируется на механизме наследования ООП, практически не имеет ограничений и проходит через следующие стадии:

• наследование от существующего компонентного типа;

• определение новых свойств, методов и событий;

• регистрация созданной компоненты.

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

4.6.1 Стандартные компоненты

Компоненты вкладки Standard палитры компонент



осуществляют включение в вашу программу 14 стандартных интерфейсных элементов

Windows.

4.6.1.1 TMainlVlenu

Создает панель команд главного меню и соответствующие им выпадающие меню для формы. Подробная инструкция по конструированию меню приведена в разделе "Дизайнер меню".

Идентификаторы всех команд меню определяются свойством Items, которое имеет доступ к любой конкретной команде меню. Свойство AutoMerge вместе с методами

Merge и Unmerge управляют процессом слияния меню разных форм.

4.6.1.2 TPopUpMenu

Создает специальное меню для формы или для другой компоненты. Заметьте, что именно для этой цели любая прочая компонента имеет свойство PopUpMenu, в котором вы можете задать ссылку на связанное с ней меню. Подробная инструкция по конструированию меню приведена в разделе "Дизайнер меню".

Если вы хотите, чтобы специальное меню появлялось при нажатии правой кнопки мыши на форму или другой элемент, которому приписана данная компонента, установите значение true свойства AutoPopup. Работающее таким образом специальное меню называется контекстным. С помощью обработчика события ОпРорир



можно определить процедуру, которая будет выполняться непосредственно перед появлением специального меню.

4.6.1.3 TLabel

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

Текст названия является значением свойства Caption. Свойство Alignment определяет способ выравнивания текста. Чтобы размер шрифта автоматически соответствовал максимальному заполнению области, установите значение true свойства AutoSize. Чтобы весь текст можно было увидеть внутри короткой области, задайте значение true свойства WordWrap. Установкой значения true свойства Transparent вы можете оставить видимой часть другой компоненты сквозь название, расположенное прямо на ней.

4.6.1.4 TEdit

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

TEdit является прямой производной от класса TCustomEdit, полностью наследуя его свойства, методы и события.

4.6.1.5 ТМето

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

TMemo является прямой производной от класса TCustomMemo, полностью наследуя его свойства, методы и события.

4.6.1.6 TButton

Создает прямоугольную кнопку с надписью. Нажатие на кнопку инициирует некоторое действие в программе.

Кнопки чаще всего используются в диалоговых окнах. Кнопка по умолчанию, выбранная значением true свойства Default, запускает обработчик события OnClick всякий раз, когда нажимается клавиша Enter в окне диалога. Кнопка прерывания, выбранная значением true свойства Cancel, запускает обработчик события OnClick всякий раз, когда нажимается клавиша Escape в окне диалога.

TButton является производной от класса TButtonControl.



4.6.1.7 TCheckBox

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

Состояние бокса "check" соответствует выбору некоторого варианта (отмечается перечеркиванием бокса), а состояние "uncheck" соответствует снятию выбору - при этом свойство компоненты Checked меняется соответственно и возникает событие OnClick. Описательный текст хранится в свойстве Caption. Затемнить бокс (подкрасить серым цветом) можно установкой значения true свойства AllowGrayed. Свойство State отражает текущее состояние и цвет бокса.

TCheckBox является производной от класса TButtonControl.

4.6.1.8 ЕЙ TRadioButton

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

Радио-кнопки представляют набор взаимоисключающих вариантов выбора:

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

Checked меняется соответственно и возникает событие OnClick.

Обычно радио-кнопки размещаются внутри предварительно установленного на форме группового контейнера. Если выбрана одна кнопка, выбор всех прочих кнопок той же группе автоматически снимается. Например, две радио-кнопки на форме могут быть выбраны одновременно только в том случае, когда они размещены в разных контейнерах. Если группировка радио-кнопок явно не задана, то по умолчанию, все они группируются в одном из оконных контейнеров (TForm, TGroupBox или TPanel).

TRadioButton является производной от класса TButtonControl.

4.6.1.9 TListBox

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

Если все элементы списка не умещаются в отведенную область, то список можно просматривать с помощью линейки прокрутки. Элементы списка содержатся в свойстве Items, а номер элемента, который будет выбран во время выполнения программы, - в свойстве



Itemlndex. Окно текстового редактора элементов

списка открывается кнопкой в графе значений свойства Items.

Можно динамически добавлять, вычеркивать, вставлять и перемещать элементы списка с помощью методов Add, Append, Delete и Insert объекта Items, например:

ListBoxl->Items->Add("Последний элемент списка");

Значение true

свойства Sorted

устанавливает сортировку элементов списка по алфавиту.

TListBox является производной от класса TCustomListBox, полностью наследуя его свойства, методы и события.

4.6.1.10 TComboBox

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

Значение свойства Text заносится непосредственно в область редактирования. Элементы списка, которые может выбирать пользователь, содержатся в свойстве Items,

номер элемента, который будет выбран во время выполнения программы, -в свойстве

Itemlndex, а сам выбранный текст - в свойстве SelText. Свойства SelStart и SelLength позволяют установить выборку части текста или обнаружить, какая часть текста выбрана.

Можно динамически добавлять, вычеркивать, вставлять и перемещать элементы списка с помощью методов Add, Append, Delete и Insert объекта Items, например:

ComboBoxl->Items->Insert(0, "Первый элемент списка");

Значение true

свойства Sorted

задает сортировку элементов списка по алфавиту. Вид компоненты TComboBox можно выбрать в свойстве Style.

TComboBox является производной от класса TCustomComboBox, полностью наследуя его свойства, методы и события.

4.6.1.11 TScrollBar

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

Поведение прокручиваемого объекта определяется обработчиком события OnScroll. Насколько должен продвинуться бегунок, когда пользователь щелкает мышью на самой линейке (по обеим сторонам от бегунка), определяет значение свойства LargeChange. Насколько должен продвинуться бегунок, когда пользователь щелкает мышью по кнопкам со стрелками (на концах линейки) или нажимает клавиши позиционирования, определяет значение свойства SmallChange



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

Position. Метод SetPcirums определяет значения всех свойств Min, Мах и Position одновременно.

4.6.1.12 TGroupВох

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

Windows.

4.6.1.13 TRadioGroup

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

Радио-кнопки "группируются" при помещении их в один и тот же контейнер. Только одна кнопка из данной группы может быть выбрана. Добавление кнопок к компоненте TRadioGroup выполняется редактированием свойства Items.

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

4.6.1.14 TPanel

Создает пустую панель, которая может содержать другие компоненты. Вы можете использовать TPanel для создания на вашей форме панелей инструментов или строк состояния.

TPanel является производной от класса TCustomPanel, полностью наследуя его свойства, методы и события.

4.6.2 Компоненты Win95

Компоненты вкладки Win95 палитры компонент



осуществляют включение в вашу программу 12 интерфейсных элементов Windows 95.

4.6.2.1 TTabControl

Отображает набор частично перекрывающих друг друга картотечных вкла-док. Названия вкладок

вводятся в список свойства Tabs кнопкой

в графе значений этого свойства. Рис. 4.5 показывает заготовку формы приложения для работы с алфавитным библиотечным указателем. Если все поля не умещаются на форме в один ряд, то можно установить значение true свойства MultiLine, или прокручивать вкладки с помощью кнопок со стрелками.





Рис. 4.5. Картотечные вкладки с названиями.

Установка значения false свойства Enabled запретит выборку отдельных вкладок.

 

4.6.2.2 TPageControl

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

Чтобы создать новую страницу диалога с соответствующей вкладкой, выберите опцию New Page из контекстного меню данной компоненты. Вы можете активизировать конкретную страницу одним из следующих способов: с помощью мыши, выбрав ее из выпадающего списка свойства ActivePage, а также перелистывая вкладки с помощью опций Next Page и Previous Page контекстного меню. Свойство Pagelndex содержит номер активной страницы. Установкой значения false свойства Tab Visible можно сделать эту страницу невидимой.



Рис. 4.6. Многостраничный диалог.

Рис. 4.6 показывает заготовку формы приложения с многостраничным диалогом для второй активизированной страницы. Работу с вкладками реализует встроенная компонента управления TTabSheet. Если все вкладки не умещаются в один ряд, компонента выводит кнопки прокрутки. Задайте значение true свойства MultiLine, чтобы отобразить вкладки в несколько рядов.

Отображает поле с иерархическим (древовидным) перечнем элементов - заголовков документов, записей в указателе, файлов или каталогов на диске. Действие этой компоненты можно увидеть во многих приложениях Windows 95.

Свойство Items ссылается на объект TTreeNodes, которое содержит редактируемый список элементов дерева. Окно редактора элементов дерева (Рис. 4.7) открывается кнопкой в графе значений этого свойства. Каждый элемент дерева состоит из метки, списка ассоциируемых с ним субэлементов и ряда битовых образов (если таковые имеются). Щелкая мышью на элементе, пользователь может раскрывать или закрывать соответствующий список суб-элементов. Двойной щелчок мышью раскрывает один уровень родительского узла дерева, показывая только его прямых потомков. Свойство ShowButtons отвечает за отображение кнопки (со знаком "+", если данный узел не раскрыт и содержит суб-элементы, или со знаком "-" в противном случае) слева от родительского узла: нажатие этой кнопки является альтернативой двойного щелчка мышью по родительскому элементу.





Рис. 4.7. Конструирование дерева компоненты TTreeView.

Число раскрываемых потомков задается значением свойства Indent. Чтобы упорядочить списки потомков в алфавитном порядке, установите значение stText

для свойства SortType. Значение true свойства Visible вызывает отображение линий - ветвей дерева, связывающих родителей с их потомками.

Элементы можно добавлять и вставлять в список динамически с помощью следующих методов для объекта Items ->TTreeNode: AddChildFirst, AddChild, AddChildObjectFirst, AddChildObject, AddFirst, Add, AddObjectFirst,AddObject.Insert,InsertObject.

4.6.2.4 TListView

Отображает поле с иерархическим (древовидным) списком элементов в различных видах. Свойство ViewStyle определяет вид отображения элементов списка: по столбцам с заголовками, вертикально, горизонтально, с малыми или с большими пиктограммами.

Свойство Items позволяет добавлять, вычеркивать и модифицировать подписи, а также подбирать пиктограммы для элементов списка. Редактор списка вызывается кнопкой в графе значений этого свойства.

Свойство Columns содержит редактируемый список названий заголовков столбцов в списке. Окно редактора столбцов открывается кнопкой

графе значений этого свойства. Чтобы увидеть заголовки, задайте значение vsReport для свойства ViewStyle, а значение true для свойства

ShowColumnHeaders. Установка значения true

свойства ColumnClick определяет поведение заголовка аналогичное кнопке: когда пользователь щелкает мышью по подписи, возникает событие OnColumnClick. События OnEdiling и OnEcUtecl возникают, когда пользователь начинает и завершает редактирование подписи.

Для выбора источника пиктограмм из выпадающего списка свойств Largelmages (Smalllmages) задайте значения

vslcon (vsSmallIcon) для свойства ViewStyle. В режиме AutoArrange свойства IconOptions пиктограммы выравниваются в соответствии с выбранным значением свойства Arrangement, а свойство WrapText указывает необходимость переноса текста подписи, когда она не умещается на пиктограмме по ширине. Рис. 4.8 показывает процесс конструирования древовидного списка, причем источником больших пиктограмм является компонента TImageList, на объект которой указывает свойство Largelmages.







Рис. 4.8. Конструирование древовидного списка и

его отображение на форме.

4.6.2.5 TImageList

Создает контейнер для коллекции из графических изображений одинакового размера K *k, каждое из которых можно выбирать по его индексу в интервале значении от 0 до п-1.

Графические коллекции используются для эффективного обслуживания больших наборов битовых образов или пиктограмм, которые хранятся как единый битовый образ шириной k*n. Монохромные изображения с масками отображаются как прозрачные трафареты. TImageList имеет методы, облегчающие процессы записи, выборки и вывода хранимых изображений.



Рис. 4.9. Конструирование коллекции пиктограмм.

Окно редактора коллекции изображений (Рис. 4.9) открывается двойным щелчком мышью по компоненте или опцией ImageList Editor из ее контекстного меню.

TImageList является производной от класса TCustomImageList, полностью наследуя его свойства, методы и события.

4.6.2.6 THeaderControl

Создает контейнер для набора заголовков столбцов, ширину которых можно менять в процессе выполнения программы. Заголовки, перечисленные в свойстве Sections, можно размещать над информационными полями, например, над списками компонент TListBox. Окно редактора заголовочных секций (Рис. 4.10) открывается кнопкой в графе значений этого свойства.



Рис. 4.10. Конструирование секций заголовков.

Поскольку секции заголовков можно подогнать буквально к любым другим компонентам (Рис. 4.11). манипуляция с их шириной автоматически не вызовет адекватного изменения ширины ассоциированных компонент. Если же вы хотите, чтобы ширина столбца изменялась согласно изменениям ширины секции, вам придется написать обработчик события OnSectionResize, ответственный за эти действия.



Рис. 4.11. Конструирование библиографического справочника.

4.6.2.7 TRichEdit

Отображает область редактируемого ввода множественных строк информации в формате RTF (Rich Text Format),

который включает различные вариации атрибутов шрифта и форматирования параграфов. Данный формат принимают многие профессиональные текстовые процессоры, например, Microsoft Word.





Рис. 4.12. Проектирование и исполнение приложения для чтения RTF

файла.

В окне Редактора кода (средняя часть Рис. 4.12) выделена единственная инструкция обработчика события OnАctivate, возникающего при активизации формы и вызывающего чтение файла OVER VIEW.RTF в объект

RichEditI компоненты редактируемого ввода. Нижняя часть рисунка демонстрирует работу скомпилированного и собранного приложения.

TRichEdit является прямой производной от класса TCustomRichEdit, полностью наследуя его свойства, методы и события.

4.6.2.8 TStatusBar

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

Каждая панель представлена в списке свойства Panels. Панели нумеруются слева-направо, начиная с индекса 0. Окно редактора панелей (Рис. 4.13) открывается кнопкой в графе значений этого свойства. Свойство SimplePanel используется для переключения вида отображения строки состояния (одно- или много- панельная).



Рис. 4.13. Конструирование строки панелий состояния.

В окне Редактора кода (средняя часть Рис. 4.14) выделена единственная инструкция обработчика события OnMoiiseMovc', возникающего при перемещении мыши по форме и вызывающего вывод координатор курсора в панель Panels->Item[l] объекта StatusBarl компоненты строки состояния. Нижняя часть рисунка демонстрирует работу скомпилированного и собранного приложения.



Рис. 4.14. Вывод информации па петель строки состояния.

Эта компонента представляет собой инкапсуляцию одноименного объекта Windows.

4.6.2.9 TTrackBar

Создает шкалу с метками и регулятором текущего положения (вариант линейки прокрутки).

Свойства Min

и Мах устанавливают интервал значений шкалы, причем свойство Position отражает текущую позицию регулятора внутри заданного интервала. Число изображаемых меток специфицирует свойство Frequency. На сколько меток должен продвинуться регулятор, когда пользователь щелкает мышью на самой шкале (по обеим сторонам от регулятора) или нажимает клавиши PageUp



и PageDown,

определяет значение свойства PageSize. На сколько меток должен продвинуться регулятор, когда пользователь нажимает клавиши позиционирования курсора, определяет значение свойства LineSize.

Чтобы изменить вид шкалы, используйте свойства TickStyle и

TickMarks. Значения свойств SelStart и

SelEnd устанавливают границы разрешенных перемещений регулятора.

4.6.2.10 TProgressBar

Создает индикатор, который отслеживает процесс выполнения некоторой процедуры в вашей программе. По мере выполнения процедуры, прямоугольный индикатор постепенно окрашивается слева направо заданным цветом.

Свойства Min и Мах устанавливают интервал значений индикатора. Свойство Step задает шаг изменения значения свойства Position всякий раз, когда позиция индикатора меняется.

C++Builder поставляется вместе с шуточным примером, который демонстрирует работу прогресс-индикатора в тесте для измерения "скорострельности" работы машинисток

=> По команде главного меню File | Open Project

откройте диалог выбора проектов. => Войдите в каталог \...\CBuilder\Examples\Apps\Wpm. => Выберите проектный файл Wpm и нажмите кнопку Open.

=> Командой главного меню Run | Run запустите процесс компиляции и сборки приложения.

Код программного модуля WPMMAIN.CPP чрезвычайно лаконичен и не нуждается в дополнительных комментариях. Вы легко сможете адаптировать поведение приложения в соответствии со своим вкусом, в частности, переведя его на родной язык. Результат самотестирования автора книги (Рис. 4.15) показывает его совершенную непригодность к машинописи.



Рис. 4.15. Работа приложения для тестирования машинисток.

4.6.2.11 TUpDown

Создает спаренные кнопки со стрелками л.

(вверх) и •”• (вниз). Нажатие этих кнопок вызывает, соответственно, увеличение или уменьшение численного значения свойства Position.

Эта компонента обычно используется вместе с сопровождающим элементом управления, задаваемым свойством Associate. Когда сопровождающим элементом служит область редактируемого ввода, значение свойства Position определяет форматирование вводимого текста. Если свойство Associate не специфицировано, значение свойства



Position содержит числовую величину.

4.6.2.12 И THotKey

Используется для установки клавиш быстрого вызова (shortcut)

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

(Ctrl, Alt или

Shift) и любого символа, включая функциональные клавиши

F1,..F12.

Введенную комбинацию, записанную в свойстве HotKey, можно присвоить свойству Shortcut другой компоненты. Чтобы выбрать горячие клавиши на стадии проектирования, используйте свойства HotKey и Modifiers, а чтобы отменить их - свойство InvalidKeys. Чтобы изменить комбинацию во время выполнения программы, удерживайте нажатой клавишу модификатора и одновременно введите новый символ.

4.6.3 Дополнительные компоненты

Компоненты вкладки Additional палитры компонент



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

 

4.6.3.1 TBitBtn

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

Графические кнопки имеют свойства для спецификации битовых образов, их вида и размещения на кнопке. Вы можете пользоваться готовыми стилями графических кнопок из отдельного каталога изображений, входящего в поставку C++Buider или собственными картинками, созданными одной из систем редактирования изображений. Различным состояниям кнопки (например, "нажата", "отпущена", "запрещена" и т.п.) могут соответствовать разные битовые образы.



Окно редактора файлов изображений с расширением bmp (Рис. 4.16) открывается кнопкой

значений свойства Glyph. Свойство Kind поможет вам создать стандартизованные кнопки, снабженные надписями и соответствующей графикой: ОК, Cancel. Helo и другие.

Рис. 4.16. Редактор изображений файлов битовых образов с расширением bmp.

4.6.3.2 TSpeed Button

Создает графическую кнопку, обычно располагаемую на панели (TPanel) быстрого вызова определенных команд меню или установки режимов.



Различным состояниям быстрой кнопки (например, "нажата", "отпущена", "запрещена" и т.п.) могут соответствовать разные графические образы. Имеются свойства для выбора заменяющих друг друга изображений и текста надписи. Окно редактора файлов изображений с расширением (Рис. 4.16) открывается кнопкой графе значений свойства Glyph. Другие свойства быстрых кнопок организуют их работу в некоторой группе.

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

EditMask хранит код текущей маски. Окно редактора масок (Рис. 4.17)

открывается кнопкой в графе значений этого свойства.



Рис. 4.17. Создание маски для ввода телефонных номеров.

TMaskEdit является прямой производной класса TCustomMaskEdit.

Создает регулярную сетку для отображения символьных последовательностей по строкам или столбцам.

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

Все объекты, связанные с символьными последовательностями, заключены в свойстве Objects, которое позволяет обращаться к нужному объекту. Во время выполнения программы символьные последовательности и связанные с ними объекты некоторого столбца сетки адресуются свойством Cols. Свойство Rows позволяет подобным образом оперировать со строками сетки. Все символьные последовательности сетки содержатся в свойстве Cells, которое адресует нужную ячейку сетки.

4.6.3.5 TDrawGrid

Создает регулярную сетку для отображения структурированных графических данных по строкам или столбцам. Свойства RowCount и ColCount задают число ячеек сетки по вертикали и по горизонтали.

Значение свойства Options позволяет изменить вид сетки (например, с разделительными линиями между столбцами) и ее поведение (например, с переходом от столбца к столбцу по клавише Tab). Ширина разделительных линий сетки задается свойством GridLineWidth, а линейки прокрутки добавляются свойством ScrollBars. Свойства FixedCols и FixedRows позволяют запретить прокрутку столбцов и строк, а свойство FixedColor присваивает определенный цвет всем столбцам и строкам.



Значение true

свойства DefauItDrawing вызывает автоматическую прорисовку содержимого ячеек сетки, причем ее фон, канва и цвет выбираются по умолчанию. Установка значения false свойства DefauItDrawing требует написания обработчика события OnDrawCell для заполнения ячеек сетки "вручную". С помощью свойств DefaultColWidths и DefaultRowHeights можно установить ширину всех столбцов и высоту всех строк, выбираемых по умолчанию. Свойства ColWidth и RowHeight

специфицируют ширину конкретного столбца и высоту конкретной строки.

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

CellRect. Метод MouseToCell возвращает координаты номера столбца и строки ячейки, на которую установлен курсор мыши. Выбранная ячейка сетки становится значением свойства Selection.

Можно определить, какая строка является в момент выполнения верхней строкой сетки или поставить указанную строку в верхнее положение с помощью свойства TopRow. Чтобы определить, какой столбец будет первым видимым столбцом сетки, воспользуйтесь свойством LeftCol. Значения свойств VisibleColCount и VisibleRowCount специфицируют общее число видимых столбцов и строк сетки.

4.6.3.6 HTImage

Создает на форме контейнер графического изображения (битового образа, пиктограммы или метафайла).

Окно редактора файлов изображений (Рис. 4.16) открывается кнопкой

в графе значений свойства Picture. Чтобы контейнер изменил свои размеры так, чтобы вместить изображение целиком, установите значение

true свойства

AutoSize. Чтобы исходное изображение меньшего размера растянулось на весь контейнер, задайте значение true свойства Stretch.

Используйте методы LoadFromFile и SaveToFile объектного свойства Picture для динамической загрузки и сохранения файлов изображений с помощью инструкций типа:

Image->Picture->LoadFromFile("<имя файла>") ;

Image->Picture->SaveToFile("<имя файла>");

4.6.3.7 TShape

Рисует простые геометрические фигуры - окружность и эллипс, квадрат и прямоугольник (можно с закругленными углами).



Вид выбранной геометрической фигуры определяется свойством Shape, а цвет и способ ее окраски - двумя вложенными в Brush свойствами Color и Style. Размеры фигур определяются соответствующими свойствами.

4.6.3.8 TBevel

Создает линии, боксы или рамки, которые выглядят объемными, как бы вырезанными стамеской.

Рисуемый компонентой объект определяется свойством Shape, а значение свойства Style меняет вид объекта, делая его выпуклым или вдавленным. Чтобы сохранить относительное положение объекта неизменным, даже если пользователь изменит размеры формы, установите значение true свойства Align.

4.6.3.9 TScrollBox

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

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

Другое использование боксов прокрутки заключается в возможности создания множественных прокручиваемых областей (видов) в некотором окне. Виды часто присутствуют в коммерческих текстовых процессорах, бухгалтерских программах и в программах планирования проектов. Бокс прокрутки может содержать другие компоненты, например, TButton и

TCheckBox.

4.6.4 Компоненты доступа к базам данных

Невидимые компоненты вкладки Data

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

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



Компоненты осуществляют включение в вашу программу 8 интерфейсных элементов доступа к наборам данных (datasets) - таблицам, запросам, хранимым процедурам, сессиям и другим основным сущностям баз данных.

Доступ к базам данных поддерживает его основа - 32-разрядный механизм BDE (Borland Database Engine).



4.6.4.1 TDataSource

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

Каждый набор данных должен ассоциироваться с источником, чтобы манипулировать данными посредством компонент управления. С другой стороны, каждая компонента управления должна ассоциироваться с источником, чтобы она могла принимать данные и манипулировать ими.

Компоненты TDataSource также способны организовать парные связи таблиц между собой по принципу master-detail и поддерживать синхронизацию обмена.

Установка значения false свойства AutoEdit запрещает режим редактирования набора данных. Свойство DataSet указывает, с каким набором данных (таблицей, запросом) связан их источник.

4.6.4.2 ТТаble

Представляет собой интерфейс между механизмом BDE и компонентой TDataSource, которая, в свою очередь, образует соединение с такими компонентами управления, как TDBGrid.

Именно посредством ТТаЫе, обеспечивается доступ на этапе проектирования к живым данным (live data) из таблицы локальной базы данных: все записи или столбцы адресуемой таблицы сразу же становятся доступными для приложения.

Свойство Active устанавливает активное состояние связи с таблицей, чтобы можно было увидеть на форме живые данные. Свойство DatabaseName содержит псевдоним адресуемой базы данных или полный путь к ее каталогу, а свойство TableName - имя таблицы.

Установите значение true свойства ReadOnly, если хотите запретить изменения содержимого таблицы. Установите значение true

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

4.6.4.3 TQuery

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



Благодаря командам на языке структурированных запросов SQL (Structured Query Language), компонента TQuery получает групповой доступ к таблице. В дальнейшем мы будем ссылаться только на четыре базовые команды, которые поддерживаются всеми версиями стандарта SQL: SELECT - для выбора данных;

INSERT - для добавления новых данных; UPDATE - для модификации таблиц;

DELETE -для удаления данных. Синтаксис построения и параметры этих команд поясняются на конкретных примерах, приведенных в главе 5.

C++Builder передает запросы BDE серверу (или SQL серверу), который интерпретирует их и возвращает вашему приложению результирующий набор

(result set) - запрошенную группу записей или столбцов.

Свойство Active устанавливает активное состояние связи с таблицей, чтобы можно было увидеть на форме живые данные, полученные в результате обработки SQL запроса. Свойство DatabaseName содержит псевдоним базы данных или полный

путь к ее каталогу для направления запроса.

Свойство Params специфицирует значения параметров динамического запроса, передаваемого во время выполнения программы. Чтобы ввести символическую запись самой команды статического или динамического запроса, нажмите

кнопку в графе значений свойства SQL.

4.6.4.4 TStoredProc

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

Свойство DatabaseName содержит псевдоним базы данных сервера, на котором находится хранимая процедура, а свойство StoredProcName - имя процедуры.

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



Хранимую процедуру необходимо подготовить к запуску: на стадии проектирования - с помошью редактора параметров. а во время выполнения программы - с помощью метода Prepare

Исполнение хранимой процедуры реализует метод ЕхесРгос (если процедура возвращает одиночный результат в виде единственной записи) или метод Open (если процедура возвращает результирующий набор в виде множественных записей).

4.6.4.5 TDatabase

Эта компонента не участвует в организации доступа на уровне наборов данных, хотя предоставляет возможность соединения клиент/сервер с одиночной базой данных в одной сессии. Компонента TDatabase используется для выдачи специфических команд управления базой данных или создания временного локального псевдонима некоторой удаленной базы данных, но особенно целесообразна для организации управления обработкой транзакций на удаленном

SQL сервере.

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

 

4.6.4.6 TSession

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

Компонента TSession организует стандартные сессии, множественные сетевые сессии с файлами базы данных Paradox и сессии приложений с повторными вхождениями.

Сетевое приложение, которое одновременно обращается к таблицам базы данных

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

Вы можете управлять поведением сессии во время работы приложения, обращаясь к ее свойствам, событиям и методам.



4.6.4.7 TBatchMove

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

• добавление группы записей в некотором наборе данных к таблице назначения базы данных:

• вычеркивание группы записей в некотором наборе данных из таблицы назначения базы данных;

• копирование набора данных с созданием новой таблицы назначения или с обновлением содержания существующей таблицы.

Выпадающие списки свойств Source и Destination позволяют выбрать имя таблицы источника и таблицы назначения, соответственно. Установите нужную пакетную операцию

(batAppend, batUpdate, batAppendUpdate, batCopy или batDelete) в свойстве Mode и обратитесь к методу Execute, чтобы выполнить ее. Свойство ProblemTableName инструктирует BDE, в какую таблицу заносить те записи источника, обращение с которыми вызвало проблемы в ходе пакетной операции.

Реализовать пакетные операции, хотя и с некоторыми ограничениями, можно также при помощи компоненты TTable.

4.6.4.8 TUpdateSQL

Позволяет использовать механизм котируемых обновлений (cached updates) в стиле Delphi для обслуживания результирующих наборов с атрибутом "только чтение", возвращаемых некоторыми запросами. Кэшируемые обновления заметно ускоряют отклик SQL сервера за счет уменьшения общего числа сетевых обменов с клиентом. Будучи упакованными, множественные коммуникации проявляют себя как одиночные транзакции, тем самым снижая загруженность сервера и улучшая производительность вашего приложения.

Установка свойства UpdateObject обеспечивает связь данной компоненты с набором данных.

Свойство ModifySQL представляет собой SQL команду UPDATE, которая выполняется, когда кэшируемое обновление является модификацией существующей записи. Свойство InsertSQL представляет собой команду INSERT, которая выполняется, когда кэшируемое обновление содержит вставку новой записи. Свойство DeleteSQL представляет собой команду DELETE, которая выполняется, когда кэшируемое обновление состоит в вычеркивании некоторой записи. Перечисленные свойства обеспечивают нормальную передачу параметров для кэ-шируемых обновлений. Используйте префикс



"OLD_" с именем поля, чтобы получить его значение перед тем, как кэшируемое обновление было разрешено. Доступ к старому значению поля обычно требуется при создании конструкции WHERE перечисленных команд SQL.

Метод Apply

используется для принудительного исполнения команд SQL, например, из обработчика события OnUpdateRecord. Этот метод сочетает обращение к SetParams

(установка связки параметров) и к ExecSQL (фактическое выполнение команды SQL).

4.6.5 Компоненты управления данными

Видимые компоненты вкладки Data Controls палитры компонент обеспечивают взаимодействие пользователя с источниками данных вашего приложения.



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

4.6.5.1 TDBGrid

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

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

Вы должны связать TDBGrid с набором данных посредством компоненты источника TDataSource, который идентифицируется значением свойства DataSource. Свойство Columns содержит редактируемый список названий заго-ловков столбцов в сетке. Окно редактора столбцов (Рис. 4.18) открывается кнопкой в графе значений этого свойства или опцией Columns Editor из контекстного меню компоненты.



Рис. 4.18. Редактор столбцов компоненты сетки.

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

TitleFont определяет шрифт, используемый при написании заголовков столбцов сетки. Свойство Fields содержит массив всех полей набора данных, изображаемых в сетке во время работы программы, свойство FieldCount - их число, а свойство

SelectedField - поле, выбранное в данный момент.



Значение true

свойства ReadOnly запрещает, а значение false разрешает редактирование данных при условии, что набор данных находится в режиме редактирования. Прервать редактирование можно нажатием клавиши Esc или аналогичной кнопки на панели навигатора. Фактическое изменение данных в полях происходит только после того, как выбрана новая запись, или при выходе из программы.

 

4.6.5.2 TDBNavigator

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

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

Когда пользователь нажимает одну из кнопок на панели навигатора (Рис. 4.19), выполняется надлежащее действие над записью в наборе данных, с которым связан навигатор. Например, при нажатии кнопки "+" пустая запись вставляется в таблицу перед текущей записью.



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

Рис. 4.19. Форма с панелью навигатора и компонентой TDBGrid.

Вы должны связать TDBNavigator с набором данных посредством компоненты источника TDataSource, который определяется значением свойства DataSource.

4.6.5.3 TDBText

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

Вы должны связать TDBText с набором данных посредством компоненты источника, который определяется значением свойства DataSource. Свойство DataField содержит поле в наборе данных, к которому вы хотите обратиться.

Свойство Alignment определяет способ выравнивания текста. Чтобы автоматическая установка размера шрифта позволяла бы отображать текст названия целиком, установите значения true свойства AutoSize. Чтобы можно было просмотреть длинный текст названия по частям, установите значения true



свойства Wordwrap. Задавая значение true свойства Transparent, вы можете оставить видимой часть графики сквозь название.

4.6.5.4 TDBEdit

Создает, по аналогии с компонентой

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

Свойство Text

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

4.6.5.5 TDBMemo

Создает, по аналогии с компонентой

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

Свойство Text

адресует указанное поле в наборе данных, содержащее многострочную алфавитно-цифровую последовательность или Большой Бинарный Объект (BLOB).                                                                 


ИСПОЛЬЗОВАНИЕ И СОЗДАНИЕ ВИЗУАЛЬНЫХ КОМПОНЕНТ


 

6. ИСПОЛЬЗОВАНИЕ И СОЗДАНИЕ ВИЗУАЛЬНЫХ КОМПОНЕНТ

Эта глава посвящена основе построения приложений в C++Builder- Библиотеке Визуальных Компонент VCL (Visual Component Library). Обсуждается иерархическая структура компонент VCL, объясняется назначение общих свойств, методов и событий, присущих различным базисным уровням в иерархии.

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

Библиотека Визуальных Компонент была впервые введена системой программирования

Delphi 1.0 на языке Объектный Паскаль и модифицирована в Delphi 2.0 для поддержки 32-разрядных приложений. Delphi оказалась наиболее популярной на рынке систем быстрой разработки программных приложений, однако, многие потребители высказывали интерес к подобной системе для языка C++, которая в конце концов и воплотилась в C++Builder. C++Builder унаследовал версию Библиотеки Визуальных Компонент Delphi 2.0 без каких-либо изменений.

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

6.1 Назначение и устройство VCL

Библиотека Визуальных Компонент позволяет программистам визуально создавать программные приложения, не прибегая более к кодированию классов "вручную", или кодированию в рамках стандартных библиотек MFC (Microsoft Foundation Class), или OWL (Object Windows Library).

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


Для создания новых компонент можно с одинаковым успехом пользоваться средствами C++Builder или Delphi, однако если разработанные компоненты предлагаются для внешнего применения, автор обязан удостовериться, что они работают в рамках обеих систем.

6.1.3 Компоненты VCL

Компоненты — это строительные кирпичи, из которых конструируется интерфейс программы с пользователем, с помощью которых "здание" программы приобретает новый внешний облик и скрытые особенности. Для прикладного программиста любая компонента VCL представляет собой объект, который можно "перетащить" из вкладок Палитры компонент (Рис. 6.1) на форму создаваемого приложения. Поместив компоненту на форму, можно манипулировать ее свойствами (посредством Редактора форм) и кодом (с помощью Редактора кода), придавая компоненте специфическое поведение.



Рис. 6.1. Палитра компонент с выбранной пиктограммой TLahel.

Для разработчика компоненты представляют собой объекты на C++ или на Объектном Паскале. Некоторые компоненты инкапсулируют поведение типовых элементов управления, предоставляемых операционными системами Windows. Другие компоненты вводят совершенно новые видимые и невидимые элементы, программный код которых полностью определяет их поведение.

Сложность компонент различна. Так

TLabel из вкладки Standard Палитры компонент способна лишь отображать статистический текст. Можно сконструировать значительно более сложную компоненту, которая, например, инкапсулирует законченное обслуживание бухгалтерских документов специализированной базы данных.

6.2 Типы компонент

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

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



Из определения объектных классов вы знаете, что при определении некоторого класса (наследника) вы производите его от существующего объектного типа (непосредственного предшественника). Стандартный абстрактный тип TObject является, по умолчанию, первым предшественником (прародителем) всех объектов Библиотеки Визуальных Компонент.

Компоненты по сути представляют собой объекты специальных типов. Лишь несколько исключении выделяют структуру компонент из общих правил структурирования объектов на языке C++:

• Большинство компонент представляют собой элементы управления интерфейсом с пользователем, причем некоторые обладают весьма сложным поведением.

• Все компоненты являются прямыми или косвенными потомками одного общего класса-прародителя (TComponent).

• Компоненты обычно используются непосредственно, путем манипуляций с их свойствами; они сами не могут служить базовыми классами для построения новых подклассов.

• Компоненты размещаются только в динамической памяти с помощью оператора new.

Понимание VCL основано на трех фундаментальных принципах. Во-первых, вам придется ознакомиться со специальными характеристиками четырех базисных типов компонент: стандартного управления, оригинального управления (custom control),

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

6.2.1 Стандартные компоненты

Некоторые компоненты VCL инкапсулируют поведение таких типовых элементов управления операционной системы Windows, как TButton, TListbox и TEdit. Вы найдете стандартные компоненты на вкладках Standard и Win95 Палитры компонент.

Любая стандартная компонента выглядит и ведет себя точно так же, как и инкапсулированный ею элемент управления Windows. VCL добавляет обрамление, которое никак не меняет свойств исходного элемента управления, а лишь делает доступной модификацию вида и поведения компоненты посредством свойств и методов.



Если вы собираетесь использовать стандартные компоненты без изменений, вам не нужно вникать в правила построения обрамлений VCL. Разработчик компонент может открыть файл исходных текстов стандартных компонент, входящий в поставку версий C++Builder Professional или Client/Server Suite, чтобы понять, каким образом известные элементы управления Windows обрамляются при включении в Библиотеку.

Например, компонента TListBox отображает элементы списка в один столбец, хотя инкапсулирует класс простого списка LISTBOX

из Windows,

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

6.2.2 Оригинальные компоненты

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

оригинальных компонент являются TPanel и TStringGrid.

Следует отметить, что как стандартные, так и оригинальные компоненты всегда ассоциируются с некоторым окном управления, поэтому иногда называются оконными (windowed components). Данный аспект подробно обсуждается в параграфе, описывающем класс TWinControl. Оконные компоненты обладают следующими свойствами: они могут быть активизированы (принять фокус ввода), используют системные ресурсы и могут служить контейнерами, т.е. являться родителями других элементов управления. Примером контейнерной компоненты является TPanel.

6.2.3 Графические компоненты

Графические компоненты представляют собой видимые элементы управления, которые не могут принять фокус ввода, т.к. не являются оконными. Графические компоненты обеспечивают отображение объектов без использования системных ресурсов, они требуют меньших "накладных расходов", нежели стандартные или оригинальные компоненты. Примерами графических компонент являются TImage и TShape.



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

6.2.4 Невидимые компоненты

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

С помощью Инспектора объектов вы можете модифицировать свойства невидимых компонент и предусматривать код обработчиков событий для них. Примерами таких компонент являются TOpenDialog, TTable или TTimer.

6.2.5 Контейнерные компоненты

Некоторые компоненты в VCL могут владеть другими компонентами или являться родителями других компонент. Указанные аспекты имеют разное смысловое значение, что и проясняется в следующих параграфах.

6.2.5.1 Право владения

Любая компонента может находиться во владении (ownership) других компонент, но не все компоненты могут являться владельцами. Свойство компоненты

Owner (Владелец) содержит ссылку на компоненту, которая ею владеет. Рис. 6.2 показывает иерархию владения некоторой формы.



Рис. 6.2. Пример иерархии владения.

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

Владение применимо не только к видимым, но и к невидимым (Ttimer, DataSource) компонентам.

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

передается конструктору компоненты

TButton как параметр. TButton выполнит присваивание значения переданного параметра свойству Owner

кнопки MyButton:

MyButton = new TButton(this);

Когда форма, владеющая компонентой

TButton освобождается, автоматически уничтожается и кнопка

MyButton.



Вы можете создать компоненту, у которой нет владельца, передавая значение параметра 0 конструктору компоненты. Однако, когда эта компонента перестает быть нужной, ее уничтожение выполняется принудительно (с помощью оператора delete). Следующий пример иллюстрирует обращение с компонентой TTable, не имеющей владельца:

TTable* MyTable = new TTable(0)

// Код, реализующий работу с MyTable

delete MyTable;

Свойство Components типа массив содержит перечень компонент, которыми владеет данная компонента. Листинг 6.1 содержит фрагмент кода обработчика события OnClick с циклом отображения имен классов всех компонент, которыми владеет некоторая форма.

void _fastcall TFormI::ButtonlClick(TObject *Sender) {

for (int i=0; i<ComponentCount; i++)

ShowMessage(Components[i]->ClassName()) ;

}

Листинг 6.1. Использование свойства

Components.

6.2.5.2 Родительское право

Понятие родительского права

(parentship) существенно отличается от права владения и применимо только к видимым (оконным) компонентам.Родитель компоненты не может быть ее владельцем.

Родительские компоненты обращаются к соответствующим внутренним функциям, чтобы вызвать отображение компонент-потомков. Родитель также ответствен за освобождение своих потомков, когда сам родитель уничтожается. Свойство компоненты Parent (Родитель) содержит ссылку на компоненту, которая является ее родителем. Рис. 6.3 показывает родительскую иерархию некоторой формы.



Рис. 6.3. Пример родительской иерархии.

Многие свойства видимых компонент (например. Left, Width, Top, Height)

относятся к родительским элементам управления. Другие свойства (например, ParentColor и ParentFont) позволяют потомкам использовать свойства родителей.

К оконным компонентам относятся такие видимые элементы, как TEdit, TListBox и TMemo. Чтобы отобразить оконную компоненту, ей надо присвоить родителя, ответственного за отображение. Это присваивание выполняется автоматически на стадии проектирования, когда вы перетаскиваете нужную компоненту из Палитры компонент на форму. Напротив, при создании компоненты во время выполнения программы вы должны явно записать это присваивание, иначе компонента не будет отображена (Листинг 6.2).



void _fastcall TFormI::FormCreate(TObject *Sender)

{

MyEdit = new TEdit(this); //

Передать this как владельца MyEdit->Parent = this;

// Передать

this как родителя

}

Листинг 6.2. Создание компоненты TEdit во время выполнения.

6.2.5.3 Поточность

Поточность (streaniabilily) компоненты выражается в способе хранения самой компоненты и информации, относящейся к значениям ее свойств, в файле или в отведенной области памяти. Например, создаваемый C++Builder ресурсный файл с расширением .dfm содержит информацию о форме и компонентах, размещенных на ней. Эта информация автоматически сбрасывается в поток ресурсного файла.

Разработчики компонент VCL должны разбираться в механизме поточного ввода/вывода, поскольку им придется вручную сбрасывать в поток специальные данные о новых компонентах. VCL не автоматизирует этот процесс.

6.3 Свойства компонент

Определение класса в языке C++ содержит инкапсуляцию членов данных и методов, оперирующих с данными и определяющих поведение объекта. Эта концепция всех систем ООП принята в VCL.

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

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

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

6.3.1 Зачем нужны свойства?

Наиболее очевидное достоинство свойств проявляется в том, что они представлены в окне Инспектора объектов. Это существенно упрощает работу программиста: вместо того, чтобы реализовывать ввод и обработку параметров при конструировании объектов во время выполнения, вы всего лишь считываете значения. присвоенные пользователем.



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

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

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

• Применение свойств приводит к побочным эффектам в операторах присваивания членов данных. Эти внешне простые операторы могут подразумевать вызов метода, который, в принципе, может сделать все, что угодно. Простым примером служит свойство всех компонент под названием Тор. Присваивание не только меняет значение этого свойства, но и, благодаря побочному эффекту, приводит к перемене положения компоненты на форме и перерисовке ее содержания. Отметим, что побочный эффект установки свойств может не ограничиваться данной компонентой. Например, установка значения true свойства Down в одной из компонент группы быстрых кнопок приводит к изменению свойств всех других быстрых кнопок этой группы на значение false.

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



6.3.2 Объявление свойств

C++Builder использует ключевое слово _property для идентификации свойств. Синтаксис описания свойства имеет вид:

property <тип свойства> <имя свойства> = {<список атрибутов>} ;

где список атрибутов содержит перечисление следующих атрибутов свойства:

write = < член данных или метод записи >;

read = < член данных или метод чтения >;

default = < булева константа, управляющая сохранением значения>;

stored = < булева константа или функция, сохраняющая значение >.

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

6.3.2.1 Доступ к внутренним данным свойств

C++Builder не вводит ограничений на способ хранения значений свойств. Однако, все компоненты VCL придерживаются следующих соглашений:

• Значения свойств хранят члены данных объекта.

• Идентификаторы членов данных, хранящих значения свойств, образуются добавлением префикса F к имени этого свойства. Так исходные значения свойства Width

компоненты TControl хранит член данных под именем

FWidth.

• Идентификаторы членов данных, хранящих значения свойств, должны быть объявлены как private. При этом компонента, объявившая эти свойства, имеет к ним доступ, а пользователь данной компоненты и ее производные - нет.

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

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

Прямой доступ является простейшим способом обращения к значениям свойств. Атрибуты read и write объявления свойства указывают, что чтение или присваивание значений внутренним членам данных свойства происходит непосредственно, без вызова соответствующих методов. Прямой доступ чаще всего используется для чтения значений свойств. При этом побочный эффект не возникает, однако данное свойство будет представлено в окне Инспектора объектов.



Методы чтения и записи замещают имена членов данных в атрибутах read и write объявления свойства. Вне зависимости от конкретной реализации методов, они должны быть объявлены как приватные, а производные компоненты должны использовать наследованные методы для чтения и записи значений свойства. Объявление методов приватными защищает пользователя производной компоненты от случайного вызова неадекватных методов, модифицирующих свойства не так, как ожидалось.

Значение свойства по умолчанию представляет собой именно то начальное значение инициализации свойства, которое устанавливает конструктор данной компоненты. C++Builder использует объявленное значение свойства по умолчанию default, чтобы определить, следует ли сохранять свойство в файле формы с расширением .dim (если атрибут stored явно не запрещает это).

Листинг 6.3 объявляет компоненту с единственным свойством IsTrue, имеющим значение по умолчанию

true, а также конструктор, который устанавливает это значение при инициализации компонентного объекта. Заметим, что если свойство имеет значение по умолчанию false, то не нужно явно устанавливать его в конструкторе, поскольку все объекты (включая компоненты) всегда инициализируют свои члены данных значением 0, т.е. false.

class TMyComponent : public TComponent { private:

Boolean FIsTrue;

public:

virtual _fastcall TMyComponent(TComponent* AOwner);

_J?ublished:

_property Boolean IsTrue =

{ read=FIsTrue, write=FIsTrue, default=true };

};

_fastcall TMyComponent::

TMyComponent (TComponent* AOwner) : TComponent (AOwner) {

FIsTrue = true;

}

Листинг 6.3. Установка конструктором значения свойства по умолчанию

6.3.2.2 Свойства обеспечивают доступ к членам данных

Существует два способа, посредством которых свойства обеспечивают доступ к внутренним членам данных компонент: прямой или косвенный посредством методов чтения/записи.

class _declspec(delphiclass) TCustomEdit;

class _declspec(pascalimplementation) TCustomEdit :

public Controls::TWinControl { private:

int FMaxLength;



void _fastcall SetMaxLength(int Valued-protected:

property int MaxLength = { read=FMaxLength, write=SetMaxLength, default=false };

};

Листинг 6.4. Способы доступа свойства к членам данных.

Листинг 6. 4 содержит код объявления компоненты TCustomEdit, взятый из VCL. TCustomEdit — это базовый класс для таких компонент редактирования как, TEdit и TMemo.

TCustomEdit имеет внутренний член данных FMaxLength типа

int, который определяет максимальное значение длины символьной строки, которую пользователь может ввести в данный элемент управления. Вместо прямого присваивания FMaxLength этого значения, выполняется присваивание свойству MaxLength, которое обеспечивает доступ к члену FMaxLength.

Определение свойства MaxLength содержит тип, имя свойства и объявления атрибутов: прямого чтения члена данных FMaxLength,

косвенного присваивания свойству

MaxLength посредством метода записи SetMaxLength и значения по умолчанию 0.

6.3.2.3 Методы записи и чтения свойств

Метод записи имеет единственный параметр того же типа, что и свойство, и не возвращает значения. По соглашению, название функции образуется из слова "Set", за которым следует имя свойства. Например, метод записи свойства MaxLength имеет имя SetMaxLength и тип void. Метод записи свойства присвоит значение своего параметра соответствующему члену данных. Одна из причин использования метода записи — вызвать побочный эффект как результат операции присваивания свойству.

Листинг 6.5 представляет пример реализации ранее объявленного метода записи SetMaxLength.

void TCustomEdit::SetMaxLength(int Value) {

if (FMaxLength i= Value) {

FMaxLength = Value;

if (HandleAllocated) SendMessagefHandle, EM_LIMITTEXT, Value, 0);

} }

Листинг 6.5. Пример реализации метода записи.

Метод SetMaxLength проверяет, не присваивается ли свойству то значение, которое уже в нем хранится. Если нет, то новое значение присваивается члену данных FMaxLength. Кроме того, метод выдает сообщение EM_LIMITTEXT Windows в то окно, которое инкапсулирует компонента TCustomEdit. По этому сообщению устанавливается верхний предел длины текста, который пользователь может ввести в данный элемент управления. Последнее действие представляет собой простейший вариант побочного эффекта, вызываемого методом записи свойства.



Метод чтения представляет собой функцию без параметров (или с параметрами индексов для свойства типа массив), которая возвращает типизированное значение свойства. По соглашению, название функции образуется из слова

"Get", за которым следует имя свойства. Например, метод чтения свойства MaxLength имеет имя GetMaxLength и возвращает значение типа int.

Метод чтения может осуществлять преобразование типа члена данных. Такие операции производят, например, методы AsString, AsFloat и Aslnteger, реализованные в компоненте TField.

 

6.3.3 Переопределение свойств

Все компоненты наследуют свойства своих предшественников, причем абстрактные базовые классы обычно объявляют свои свойства преимущественно в секциях public или protected. Чтобы такие свойства стали доступными пользователям производных компонент (как на стадии проектирования, так и во время выполнения программы), они обязаны переопределить их с ключевым словом _published.

Как видно из предыдущего примера, свойство MaxLength было определено в секции protected базовой компоненты

TCustomEdit. Листинг 6.6 содержит переопределение свойства

MaxLength как _published в производной компоненте TEdit.

class TEdit : public TCustomEdit { published:

property int MaxLength = { nodefault } ;

// Другие объявления };

Листинг 6.6. Переопределение свойства в производном классе.

Такое переопределение только снимает ограничения свойства, т.е. вы можете переопределить protected свойство как public, но не можете "спрятать" свойство, объявив его как protected. При переопределении свойства достаточно указать его имя, однако вы можете изменить значения атрибутов stored и default. Отметим также, что свойство MaxLength теперь вообще не имеет значения по умолчанию, хотя в унаследованном свойстве оно было задано.

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

Правила видимости, объявленные ключевыми словами private, protected и public, действуют на свойства так же как и на обычные члены данных и методы. Единственное отличие объявлений, сделанных в секции _published, от объявлений в секции public, проявляется в том, что во время работы программы Инспектору объектов передается информация RTTI (Run-Time Type Identification) о типах членов данных и свойств.



6.3.4 Типы свойств

Свойство может быть любого типа, который способна возвратить функция (так как реализация свойства может возлагаться на функцию). Разные типы свойств по-разному представлены в окне Инспектора объектов и определяют разные варианты их редактирования, предлагаемые Инспектором. Более того, мы уже знаем, что некоторые свойства имеют собственные редакторы. .

Правилами языка C++ устанавливаются следующие обобщенные группы типов компонентных свойств:

Тип свойства Действия Инспектора объектов
Simple Простые числовые, символьные и строчные свойства показываются Инспектором в виде чисел, символов или символьных строк, соответственно. Можно непосредственно вводить и редактировать значения простых свойств.
Enumerated Свойства перечисляемого типа (в том числе булевы) показываются Инспектором в виде значений, определенных в исходном тексте программы. Можно выбирать возможные значения из выпадающего списка перечислений.
Set Свойства типа множества показываются Инспектором в виде элементов множества. При расширении множества следует обращаться с каждым его элементом как с булевым значением: true, если элемент принадлежит множеству, или false в противном случае.
Object Свойства, которые сами по себе являются объектами, обычно обслуживаются своими собственными редакторами. Инспектор позволяет индивидуально редактировать те объектные свойства, которые объявлены какpublished. Объектные свойства должны быть производными от TPersistent
Array Свойства типа массив должны обслуживаться своими собственными редакторами свойств. Инспектор не имеет встроенных средств для редактирования таких свойств.
 

6.3.4.1 Свойства типа множество

Как известно из главы 3, C++Builder объявляет несколько шаблонных классов для встроенных типов Delphi, которых нет в языке C++.



В частности, типы стиля шрифта определяются следующим образом:

enum TFontStyle

{ fsBold, fsltalic, fsUnderline, fsStrikeOut } ;

typedef Set

<TFontStyle, fsBold, fsStrikeOut>TFontStyles ;



TFontStyle является перечисляемым типом. TFontStyles определен как множество — неупорядоченная коллекция типа

TFontStyle. Инспектор объектов позволяет переключать булевы значения элементов множества, выбирая значения false или

true. Рис. 6.4 показывает пример манипуляций свойством Style типа множество в окне Инспектора. Это свойство, определяющее основные характеристики шрифта, имеют многие компоненты, в том числе, сама форма.

Рис. 6.4. Свойство Style.

6.3.4.2 Свойства типа массив

Эти свойства имеют множественные элементы, каждый из которых соответствует некоторому индексному значению. Например, свойство Lines стандартной компоненты TMemo представляет собой индексируемый список (массив) текстовых строк, составляющих многострочное поле редактирования. В данном случае свойство Lines предоставляет пользователю естественный доступ к указанному элементу массива (строке) в большом тексте.

Листинг 6.7 содержит объявление свойства String и метода чтения GetNumberSize,

возвращающего индексируемую строку массива.

class TDemoComponent : public TComponent { private:

String _fastcall GetNumberSize(int Index);

public:

property String Number[int Index] = { read=GetNumber };

// Другие объявления };

String _fastcall TDemoComponent::GetNumberSize(int Index) {

String Result;

switch (Index) {

case 0: Result = "Zero"; break;

case 100: Result = "Medium"; break;

case 1000: Result = "Large"; break;

default: Result = "Unknow size";

) : .. return Result;

}

Листинг 6. 7. Свойство типа массив и его метод чтения.

Объявление свойств типа массив имеет следующие особенности:

• Объявление свойства включает один или несколько индексов, любого типа (по числу размерностей массива). В этом состоит первое отличие от обычных массивов, где индекс всегда имеет тип int.

• Доступ к элементам массива реализуется посредством методов чтения/записи, которые имеют дополнительные параметры - индексы массива, перечисляемые в том же порядке, что и при объявлении методов. В этом состоит второе отличие от обычных массивов, где допускаются ссылки не только на отдельные элементы, но и на весь массив.



6.4 События

События представляют собой средства, с помощью которых компонента сообщает пользователю о том, что на нее оказано некоторое предопределенное воздействие. Типичные простые события — нажатие кнопки на форме или клавиши на клавиатуре. Вкладка "События" (Events) Инспектора объектов позволяет получить доступ к событиям выбранной компоненты.

6.4.1 Зачем нужны события?

В общих словах событие определяют как механизм связи происшествия с некоторым кодом. Более точно событие - это closure, указатель на специфический метод в специфическом экземпляре класса.

С точки зрения прикладного программиста, событие представляет собой имя, которому можно присвоить некоторый вызываемый метод. Например, экземпляр компоненты TButton - кнопка Buttoni имеет методы для события OnClick. По умолчанию C++Builder генерирует обработчик события с именем ButtonlClick и присваивает его событию OnClick. Когда происходит нажатие кнопки, объект вызывает метод, присвоенный событию OnClick, в данном случае, ButtonlClick.

Таким образом, прикладной программист воспринимает событие как способ указания, к какому из написанных им методов должна обращаться программа, когда данное событие происходит. С точки зрения разработчика компонент, в понятии события заключено значительно большее. Автор компоненты обязан предусмотреть программный интерфейс, к которому можно подключить методы, вызываемые при определенных воздействиях на компоненту. Ваша компонента предоставляет "разъемы", в которые прикладной программист сможет вставлять специфические коды реакции на события.

6.4.2 Определение событий

Формально C++Builder определяет событие как типизированный указатель на метод в специфическом экземпляре класса:

<тип> (_closure * <имя метода>) (<список параметров>)

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



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

все символы к верхнему регистру. Для этого надо определить следующий обработчик события нажатия клавиши:

void _fastcall TFormI::EditlKeyPress

(TObject *Sender, char SKey) {

Key = UpCase(Key) ;

)

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

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

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

• Прикладные программисты не обязаны обрабатывать события. Различные события возникают практически постоянно при работе любого приложения Windows. Простое смещение курсора по компоненте вызывает передачу многочисленных сообщений Windows данной компоненте о передвижении мыши, которые компонента транслирует в события OnMouseMove. Если поведение компоненты не зависит от манипуляций мышью, то в большинстве случаев программа просто не обращает внимание на такие события.

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

6.4.2.3 Стандартные события

Все компоненты VCL наследуют большинство общих сообщений Windows стандартные события. Такие события встроены в защищенные секции компонент, поэтому пользователи не могут подсоединять к ним свои обработчики.



Существует две категории стандартных событий: определенные для всех компонент и определенные только для оконных компонент (стандартных и оригинальных). Все компоненты наследуют от базового абстрактного класса Tcontrol следующие стандартные события:

OnClick______OnDragDrop___OnEndDrag____OnMouseMove

OnDblClick____| OnDragOver___| OnMouseDown | OnMouseUp

В дополнение к этим событиям, оконные компоненты наследуют от базового абстрактного класса TWinControl

еще и следующие стандартные события:

OnEnter OnKeyDown OnKeyPress
OnKeyUp OnExit
Чтобы стандартные события вашей компоненты были видимы Инспектору объектов на стадии проектирования или во время выполнения программы, вы должны переопределить свойства событии в секции public или published. Листинг 6.9 показывает, как сделать стандартное событие OnClick видимым.

class TMyControl : public TCustomControl {

_published:

_property OnClick; // OnClick

стало видимым Инспектору };

Листинг 6.9. Переопределение стандартного события

Все стандартные события имеют соответствующие защищенные динамические методы, унаследованные от TControl,

имена которых образованы от названия события без частицы "On". Например, события OnClick вызывают метод Click.

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

void _fastcall TMyControl::Click() {

// Стандартное обслуживание, включающая вызов обработчика

TWinControl::Click() ;

// Далее следует ваш код переопределения метода

}

Листинг 6.10. Переопределение защищенного метода.

6.4.2.4 Собственные события

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



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

Определение события проходит через четыре этапа, для реализации которых вам необходимо:

1. Знать, какое действие вызывает событие. Для некоторых событий ответ очевиден. Например, при нажатии левой кнопки мыши Windows посылает сообщение

WM_LBUTTONDOWN. Принимая это сообщение, компонента вызывает метод

MouseDown, который в свою очередь обращается к обработчику события, который пользователь подсоединил к событию OnMouseDown.

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

2. Определить тип обработчика события. Обработчик события может просто опознавать событие нотификации

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

вызываемого при нажатии любой клавиши на клавиатуре.

3. Объявить тип и свойство для события. Инспектор объектов определяет, что данное свойство является событием, обнаруживая тип свойства



closure, и представляет его на вкладке События. Давайте событиям значимые и описательные имена, по которым пользователь догадается о том, что это за событие. C++Builder рекомендует начинать имена событий с частицы "On.".

4. Создать виртуальный метод, который вызывает обработчик события пользователя и обеспечивает обработку по умолчанию. Правильное функционирование вашей компоненты не должно зависеть от конкретной реакции, которую пользователь заложил в обработчик события. В частности, пустой обработчик события так же допустим, как и его отсутствие. Более того, пользователь имеет право переопределить обработку по умолчанию. Чтобы предоставить ему такую возможность, передайте в обработчик дополнительный адресный аргумент, значение которого можно проверять при возврате. При этом пустой обработчик события не изменит значения аргумента, и обработка по умолчанию всегда будет иметь место после возврата из пустого обработчика.

 

6.4.2.5 События и сообщения Windows

Опытный программист определенно заметит сходство некоторых событий C++Builder и сообщений Windows. В следующей таблице приведен краткий список событий объекта TForm и соответствующих сообщений Windows, которые вы использовали бы в обычной программе на языке С:

Событие VCL Сообщение Windows
OnCreate WM CREATE
OnClose WM DESTROY
OnReSize WM SIZE
OnActivate, OnDeactivate WMACTIVATE
OnShow, OnHide WM SHOWWINDOW
OnKeyDown WM KEYDOWN
OnKeyUp WM KEYUP
OnKeyDown WM KEYDOWN
OnMouseDown WM LBUTTONDOWN, WM RBUTTONDOWN
On Mouse Up WM LBUTTONUP,WM RBUTTONUP
OnMouseMove WMMOUSEMOVE
OnDblClkk WM LBUTTONDBLCLK, WMRBUTTONDBLCLK
OnPaint WM PAINT
He всякому сообщению Windows можно найти соответствующее событие VCL. Например, в обычной программе на языке С для Windows сообщение WM_COMMAND используется как для обслуживания нажатий на кнопки, так и выбора команд из меню. В C++Builder для этих целей используются разные события: TButton::OnClick и TMenuItem::OnCUck, соответственно.



С другой стороны, некоторые события VCL расширяют функциональность встроенных сообщений Windows. Так события OnDragOver и OnDragDrop Объекта TForm просто и прямолинейно реализуют операции перетаскивания

(drag-and-drop) в вашей программе. Большинство компонент на вкладках Standard и

Win95 Палитры компонент лишь специальным образом обрамляют известные элементы управления Windows. Компоненты на других вкладках представляют совершенно новые элементы управления (и события) для особых областей функционирования.

Компоненты вкладок Standard и Win95 инкапсулируют стандартные элементы управления

Windows. За взаимодействие между пользователем и программой, которое ранее поддерживалось реакцией на сообщения

Windows, теперь отвечают обработчики событий компонент VCL. Однако, в некоторых ситуациях возникает необходимость "взять на себя" те сообщения

Windows, которые не имеют соответствующих событий VCL или не адекватны им. Для таких случаев в VCL предусмотрена методика ООП, обеспечивающая непосредственный отклик на события Windows,

подобно средствам библиотек базовых классов OWL или MFC. Эта методика, реализуемая с помощью макросов BEGIN_MESSAGE_MAP, MESSAGE.HANDLER и END_MESSAGE_MAP, весьма трудоемка и здесь не рассматривается. Поэтому предварительно тщательно просмотрите имеющиеся в VCL компоненты, которые могут содержать подходящие события.

6.4.3 Обработка событий

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



Рис. 6.5 показывает вкладку Events Инспектора объектов с выбранным событием OnClick компоненты TButton. Это событие возникает при нажатии кнопки Button 1. Если дважды щелкнуть мышью на поле события, C++Builder автоматически сгенерирует соответствующее объявление метода в файле объявлений Unitl.h, и Редактор кода переведет вас в нужную позицию в кодовом файле Unitl.cpp, где вы сможете написать код, реализующий этот метод.



Нижеследующий пример иллюстрирует процесс создания кода обработчика события OnClick (Нажата кнопка Button 1) для компоненты

TButton.

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

Чтобы связать ваш собственный обработчик с событием OnClick компоненты TButton воремя выполнения программы, вы должны сначала создать метод для обслуживания этого события. Как и любой метод, он должен принадлежать существующему объекту — форме, которая владеет компонентой TButton и на которой она размещена.

Рис. 6.6 показывает окно Редактора кода с файлами Unitl.h и

Unintl.cpp программного модуля, реализующего обработку события OnClick.

Объявленный метод становится обработчиком события, когда событию Buttonl->OnClick присваивается указатель некоторого метода MyOnClickEvent.

Указанное присваивание можно также сделать динамически при работе программы в обработчике события OnCreate вашей формы. Результат будет таким же, как и при создании обработчика событий с помощью Инспектора объектов на этапе проектирования, за исключением того, что в этом случае C++Builder сохраняет связь события с его обработчиком в ресурсном файле с расширением .dfm. При запуске приложения VCL считывает форму из ресурсного файла и динамически присваивает значения свойств и событий компонент, размещенных на форме.



Рис. 6.6. Определение метода обработки события OnClick.

Когда вы определяете методы для обработчиков событий, эти методы должны быть того же типа, что и типы свойства и членов данных, на которые ссылается свойство. Например, событие OnClick ссылается на внутренний член данных FOnClick функционального типа TNotifyEvent.

 

6.5 Методы

Компонентные методы ничем не отличаются от других объектных функции-членов. Хотя

C++Builder не вводит никаких специальных ограничении на оформление компонентных методов, имеется ряд правил, которых стоит придерживаться:

1. Минимизируйте число методов, которые вызывает прикладной программист, чтобы использовать вашу компоненту. Многое из того, что вы намеревались реализовать в виде методов, вероятно, лучше инкапсулировать в свойства компоненты. В отличие от свойств, методы работают только во время исполнения программы.



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

3. Придерживайтесь соглашения об именах методов. Названия должны быть описательными, т.е. включать глагол действия и отражать возвращаемое значение (например, метод PasteFromClipboard передает в компоненту данные из доски объявлений, а метод GetHorizontalPosition возвращает горизонтальную позицию некоторой величины).

4. Правильно защищайте методы. Все методы (включая конструкторы и .деструкторы), к которым имеют право обращаться пользователи вашей компоненты, следует объявлять как public. Все методы, к которым имеют право обращаться производные объекты вашей компоненты, следует объявлять как protected, что запрещает пользователям преждевременно вызывать методы, данные для которых еще не созданы. Только те методы, которые реализуют доступ к свойствам компоненты, должны быть объявлены как private, поскольку пользователи оперируют со значениями свойств напрямую.

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

6.5.1 Вызовы статических методов

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

class TFirstComponent : public Tcomponent

{

public:

void _fastcall Move() ;

void _fastcall Flash();

};

class TSecondComponent : public TPirstComponent { public:

void _fasfccall Move(); //

отличен от наследованного метода

int _fastcall Flash(int HowOften); //

тоже отличается };



Листинг 6.11. Переопределение статических методов.

Адреса статических методов не меняются при наследовании, а значит, статические методы не следует переопределять - они призваны выполнять одинаковые действия во всех родственных компонентных объектах. Листинг 6.11 показывает, что переопределение статических методов в производном классе по сути заменяет родительские методы.

6.5.2 Вызовы виртуальных методов

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

Ключевое слово virtual в объявлении метода создает запись в таблице виртуальных методов объекта (VMT). При выполнении программы эти записи преобразуются в фактические адреса всех виртуальных методов данного компонентного класса. Когда вы производите новый объектный класс, он наследует VMT всех своих предшественников, добавляя к таблице дополнительные виртуальные методы, объявленные в производном классе. Кроме того, производный класс может переопределять наследованные виртуальные методы. Любой конструктор компоненты всегда должен быть виртуальным.

6.6 Иерархия классов VCL

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

Рис. 6.7 показывает ключевые классы в иерархической структуре, от которых произведены все компоненты VCL. Каждый объект представляет некоторый набор методов, событий и свойств и имеет специальное назначение.

TObiect

TPersistent

TComponent

TControl

TGraphicControl TWinControl

TCustomControl

Рис. 6.7. Иерархия ключевых базовых классов VCL.

Подобно тому как TObject является базовым классом для всех порождаемых классов, TComponent является базовым классом для всех порождаемых компонент. $



Невидимые компоненты произведены от класса TComponent. Графические компоненты, не ассоциированные с оконными элементами управления, произведены от класса TGraphicControl.

Являясь оконными элементами, компоненты стандартного управления произведены непосредственно от класса TWinControl, а оригинальные компоненты — косвенно от класса

TCustomControl, восходящего к TWinControl. Именно на уровне TWinControl

и вводится "оконный дескриптор"

(window handle). Рис. 6.8 S продолжает иерархическую структурную схему компонентных классов VCL.

* TButtonControl

о TButton

+ TBitBtn о

TCustomCheckBox

+ TCheckBox

+ TDBCheckBox о

TRadioButton

* TCustomComboBox о TComboBox о

TDBComboBox о

TDriveComboBox о

TFilterComboBox

* TCustoinControl

о TCustomGrid

+ TCustomDBGrid + TDBGrid + TDBLookupList

+ TPopupGrid + TCustomOutline

+ TOutline + TDrawGrid

+ TStringGrid о

TCustomGroupBox

+ TCustomRadioGroup + TDBRadioGroup + TRadioGroup

+ TGroupBox о

TCustomPanei

+ TDBNavigator

+ TPanel о TDBImage о TDBLookupControl

+ TDBLookupComboBox

+ TDBLookupListBox

+ TPopupDataList о

THeader о THintWindow о TMediaPlayer о TNotebook о TOleContainer о TPage о TScroller о TTabSet

* TCuatonEdit

о TCustomMaskEdit

+ TDBEdit

+ TInplaceEdit

+ TMaskEdit о

TCustomMemo

+ TCustomRichEdit + TRichEdit

+ TDBMemo

+ TMemo о

TDBLookupCombo о TEdit

* TCustomHotKey о THotKey

* TCuafcomListBox о TDBListBox о

TDirectoryListBox о

TFileListBox о

TListBox

* TCuetomLietView о TListView

* TCuetomTabControl о TPageControl о TTabbedNotebook о TTabControl

* TCustomTreeView о TTreeView

* TCustomUpDown 0 TUpDown

* TDBCtrlGrid

* TDBCtrlPanel

* THeaderControl

* TOleControl

* TProgressBar

* TScrollBar

* TScrollingWinControl

о TForm

+ TDesignWindow + TInputReqDialog + TLoginDialog + TPasswordDialog

о TScrollBox

* TStatueBar

* TTabPage

* TTabSheet

* TTrackBar

Puc. 6.8. Дерево производных компонент от TCustomControl и TWinConlrol.

6.6.1 TObject

TObject является базовым классом для всех прочих порождаемых классов. TObject инкапсулирует общее для всех объектов системы



C++ Builder функциональное поведение, обусловленное методами, которые обеспечивают:

• Способность конструктора создавать, а деструктора разрушать объект-экземпляр класса в динамической памяти. Конструктор

TObject возвращает указатель на создаваемый объект.

• Информацию RTTI об имени, типе производного объекта и его свойствах, которые объявлены как _published.

• Поддержку обработки сообщений.

Большинство этих методов предназначены для внутреннего использования средой C++Builder, поэтому не следует прямо обращаться к ним из вашей программы. Часть методов TObject объявлены как статические (с ключевым словом static). Это означает, что вам не нужно создавать экземпляр данного класса для того, чтобы обратиться к его статическим методам.

Все компоненты должны порождаться непосредственно от класса TComponent или от его потомков.

TComponent, будучи в свою очередь потомком TObject, наследует его члены данных, методы и свойства.

Используйте TObject для объявления простых объектов, которые не являются компонентами и не нуждаются в поточности и присваивании. Среди полезных не компонентных классов отметим TStringList, TIniFile и TPrinter.

6.6.2 TPersistent

Класс TPersistent непосредственно произведен от

TObject. Этот абстрактный класс не определяет никаких специальных свойств или событий, однако его производные приобретают особые способности присваивания и поточности.

TPersistent определяет ряд поточных методов, используемых разработчиками компонент, которые могут быть перегружены производными компонентами:

• Assign позволяет присваивать значения свойствам.

• AssignTo позволяет присваивать содержимое одного объекта другому (например, как делает это производный от TPersistent класс TClipboard).

• DefineProperties позволяет определить процедуру загрузки и сохранения в потоке особых дополнительных свойств. По умолчанию сохраняются только свойства, объявленные как _published.

6.6.3 TComponent

Класс TComponent

непосредственно произведен от

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



• Перенос на форму из Палитры компонент и манипуляции в окне Редактора

форм.

• Способность владения и обслуживания других компонент.

• Специальные характеристики поточности, с которыми может манипулировать Инспектор объектов на этапе проектирования.

• Возможность манипулирования некоторыми невидимыми компонентами на стадии проектирования.

Класс TComponent

определяет ряд свойств, которые придают объекту особую функциональность:

Свойство Назначение

Owner_______| Ссылается на владельца компоненты.

ComponentCount | Число компонент в перечне, которыми владеет данная компонента.

Componentlndex Индекс компоненты в перечне, начиная с 0.

Components | Свойство, содержащее перечень компонент, которыми владеет данная компонента.

ComponentState Текущее состояние компоненты.

ComponentStyle Стиль, определяющий поведение компоненты.

Name Имя компоненты.

Tag | Свойство типа int, которое не имеет предопределенного значения и может содержать любые данные или указате-ли, по усмотрению программиста.

Designlnfo | Используется Редактором форм.

Класс TComponent

определяет ряд методов, которые придают объекту право владения другими компонентами и возможность доступа к ним посредством Инспектора объектов:

• Destroying и

DestroyComponents устанавливают атрибуты данной компоненты и компонент, которыми она владеет, в состояние, указывающее на то, что они подлежат уничтожению.

• HasParent возвращает булево значение, указывающее на наличие родителя компоненты. Обращаться к этому методу следует до ссылок к родителю данной компоненты. Отметим, что наличие владельца компоненты не идентифицируется.

• insertComponent добавляет компоненту, передаваемую в качестве параметра, к перечню компонент, которыми владеет данная компонента, а RemoveComponent удаляет компоненту из этого перечня.

• FindComponent возвращает указатель экземпляра компоненты, о которой известно только имя, но неизвестна ссылка на владельца. Допустим, что форма содержит экземпляр компоненты TEdit с именем Editl. Чтобы получить указатель на экземпляр Editl и адресовать его текст, используйте следующий код:



void_fastcall TFormI::ButtonlClick(TObject *Sender)

{

TEdit * Editlnstance = FindComponent("Editl");

(TEdit *)(FindComponent("Editl"))->Text = "Hello";

}

He создавайте экземпляров класса TComponent. Используйте TComponent в качестве базового класса при создании невидимых компонент.

6.6.4 TControl

Класс TControl

определяет общие для видимых компонент члены данных, методы и события. Поскольку элементы TControl обладают способностью отображать себя, некоторые его свойства оперируют с положением, размером и видом объекта (Top, Left, Width, Height и Cursor, Hint), а другие свойства относятся к параметрам области клиента (ClientRect, ClientWidth и

ClientHeight).

TControl также вводит свойства, устанавливающие видимость, доступность” цвет и шрифт элементов управления (Visible, Enabled, Color и Font). Свойств” Text и

Caption обеспечивают установку редактируемых текстов и названий.

Наличие свойства Parent (Родитель), содержащего соответствующую ссылку, обусловлено возможностью класса TControl иметь родителя. Этот родитель может быть производным от TWinControl, поскольку родители обязаны быть оконными элементами управления.

TControl содержит ряд событий, возникающих при манипуляциях мышью над, видимыми элементами управления (OnClick, OnDblClick, OnMouseDowit, OnMouseMove, OnMouseUp, OnDragOver, OnDragDrop и OnEndDrag).

Поскольку TControl редко используется непосредственно, его события большинство свойств объявлены в секции protected. Разработчики производных компонент могут, таким образом, выбирать, какие свойства и события перенести в секцию

public или _published, расширяя тем самым права доступа.

Большинство компонент являются производными от TWinControl или TGraphicControl. Эти базовые классы рассматриваются в следующих параграфах.

6.6.5 TWinControl

Класс TWinControl инкапсулирует оконные элементы управления с дескрипторами. Некоторые производные от TWinControl (компоненты TEdit, TListBox и TComboBox)

инкапсулируют стандартные элементы управления Windows — поля редактирования, простые и комбинированные списки и т.д. Поэтому вам не придется манипулировать с ними посредством стандартных функций Windows API, a пользоваться свойствами и методами, предоставляемыми самими компонентами.



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

Свойство Назначение
Brush Управляет цветом и орнаментом канвы, используемой при заливке графических фигур и фона.
Controls Содержит список элементов управления, для которых TWinControl является родителем.
ControlCount Содержит число элементов управления, для которых TWinControl является родителем.
Ctl3d Определяет, требуется ли трехмерное отображение компоненты.
Handle Ссылается на оконный дескриптор объекта Windows, который инкапсулирует TWinControl. Это свойство передается тем стандартным функциям Windows API, которые принимают дескриптор как параметр.
HelpContext Задает номер контекстной справки, соответствующий некоторому окну в файле помощи с расширением .hip. Это свойство позволяет организовать контекстно-чувствительный поиск в справочной службе для отдельных компонент.
Showing Указывает, видима или невидима компонента.
TabStop Указывает, можно ли использовать клавишу табуляции для выбора нужной компоненты.
TabOrder Определяет позиции табулятора выбора компонент.
Методы TWinControl главным образом ориентированы на разработчиков компонент и предназначены для управления фокусом, получения статусной информации, диспетчеризации сообщений и позиционирования:

• Broadcast используется для рассылки сообщений всем потомкам TWinControl.

• CanFocus возвращает булево значение, которое определяет, может ли TWinControl принять фокус ввода. Например, компонента не сможет принять фокус, если ее свойство Visible имеет значение false.

• ContainsControl определяет, содержится ли данный элемент управления внутри класса TWinControl. Этот метод не сообщает о том, является ли данный элемент потомком по отношению к TWinControl. Например, внешний класс TWinControl может быть родителем другого элемента, и эта родительская преемственность может продолжаться далее. Однако, все внутренние элементы содержатся во внешнем классе TWinControl.



• ContrblAtPos возвращает ссылку на потомка, если элемент управления заключен в заданных координатах области клиента родителя. Таким образом можно найти относительное положение потомка по отношению к родителю.

• DisableAlign и

EnableAlign используются для временного запрещения или разрешения выравнивания компонент внутри

TWinControl.

• Focused возвращает значение true,

если TWinControl

находится в фокусе ввода, т.е. является активным элементом формы, на которой он размещен.

• HandleAl located возвращает значение true,

если элемент управления имеет оконный дескриптор. HandleNeeded создает новый дескриптор, если он еще не был создан. Аналогичное действие выполняется автоматически при прямом обращении к свойству Handle.

• InsertControl добавляет элемент управления к свойству Controls (типа массив), делая

TWinControl своим родителем. Лучший способ добавить потомка во время работы программы — просто присвоить ссылку на родителя свойству Parent. RemoveControl

удаляет элемент управления из массщ Controls.

• Invalidate и

Repaint выполняют перерисовку компоненты. Мето;

Repaint обрабатывает сообщение WMJPAINT, обращается к метол Update, который в свою очередь вызывает функцию Windows АP UpdaleWindow. PaintTo может использоваться для перерисовки содержимого TWinControl в область (device context) другого элемента управления. ReAlign вызывает повтор выравнивания компонент внутри

TWinControl. ScaleBy используется для масштабирования TWinControl в заданном процентном отношении к исходному размеру. ScrollBy можно использовать, если вам не нравится логика прокрутки TWinControl, принятая по умолчанию.

• SetBounds устанавливает свойства границ компоненты (Left, Top, Width, Height) для

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

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

TWinControl окон и их дескрипторов: .



• CreateWnd создает оконный элемент управления, инкапсулированны TWinControl, посредством последовательного обращения к

CreateParams и CreateWindowHandle.

• CreateParams инициирует начальные значения всех оконных параметров Перегрузка этого метода позволяет менять оконные параметры, установлен ные по умолчанию.

• CreateWindowHandle создает оконный дескриптор путем обращения функции Windows API Create WindowEx.

• DestroyWnd уничтожает инкапсулированный оконный элемент

управления путем обращения к методу DestroyWindowHandle,

который в свою очередь обращается к функции Windows API Destroy Window.

TWinControl имеет события, вызываемые взаимодействием с клавиатурой i изменением фокуса (OnKeyDown, OnKey Press, OnKeyUp, OnEnter и OnExif).

Разрабатываемые компоненты редко происходят непосредственно от TWinControl. Лучше производить новые компоненты от общего класса TCustomControl, который предоставляет канву для рисования и обрабатывает сообщение WM_PAINT, или от некоторых более специализированных классов (TButtonControl, TCustomComboBox, TCustomEdit или TCustomListBox).

6.6.6 TGraphicControl

Производные от абстрактного класса

TGraphicControl, в отличие от TWinControl, не имеют оконного дескриптора, не могут принять фокус ввода и не могут являться родителями других элементов управления.

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

Производные TGraphicControl имеют обработчики событий, вызываемые манипуляциями с мышью.

TGraphicControl возлагает на пользователя операции перерисовки. Этот класс содержит свойство Canvas (Канва), которое обеспечивает доступ к отведенной для рисования поверхности, и виртуальный метод Paint, который вызывается в ответ на сообщение WM_PAINT, принимаемое родительским элементом управления.



6.6.7 TCustomControl

Стандартные компоненты, как производные от TWinControl (например, TEdit и

TListbox), уже имеют способности собственного отображения, предоставленные инкапсулированными элементами управления Windows. А как создать оконную компоненту, которая отображает себя в виде, соответствующем оригинальным требованиям пользователя? Решение именно этой задачи и обеспечивает TCustomControl.

Будучи производным от класса

TWinControl, TCustomControl является оконным элементом управления и, следовательно, может принять фокус ввода. Разработанные компоненты могут быть произведены от

TCustomControl. Как и TGraphicControl, TCustomControl

содержит свойство Canvas (Канва), которое предоставляет возможность произвольного рисования на выбранной прямоугольной области. По существу, производные компоненты от TCustomControl предоставляют в ваше распоряжение виртуальный метод Paint, перегрузка которого позволит рисовать компоненты так, как вы пожелаете.

6.7 Схема разработки компонент

Процесс разработки собственной компоненты (мы будем называть ее TMyComponent) проходит через выполнение следующих этапов:

1. Создание модуля для новой компоненты.

2. Наследование производного класса от существующего базового компонентного класса.

3. Добавление нужных свойств, событий и методов.

4. Регистрация компоненты в C++Builder.

5. Отладка.

6. Инсталляция компоненты на Палитру.

7. Сохранение файлов компоненты.

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

6.7.1 Создание модуля компоненты

Программный модуль состоит из двух файлов МуСотр.срр и MyComp.h, которые компилируются в объектный файл с расширением MyComp.obj C++Builder использует модули в различных целях - каждая форма и большинств компонент (или их логических групп) имеют свой собственный модуль. При paзработке компоненты вы либо создаете новый модуль для компоненты, или до бавляете ее к существующему модулю.



Чтобы создать модуль, выполните команду File | New и в открывшемся диалоre New Items выберите значок Unit. Чтобы добавить компоненту к существую щему модулю, выполните команду File | Open и в открывшемся диалоге отьшите ваш файл МуСотр.срр. Имея открытый модуль в окне Редактора кода, вы можете приступить к разработке компоненты. Для начала перечислите в МуСотр.h необходимые файлы фазы предкомпиляции и объявите производный класс ваше компоненты (Листинг 6.12).

^include <vcl\sysutils.hpp>

#include <vcl\controls.hpp>

#include <vcl\classes.hpp>

#include <vcl\forms.hpp>

class TMyComponent : public <

базовый компонентный класс >

{

};

Листинг 6.12. Заготовка файла MyComp.h модуля компоненты. 1

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

6.7.2 Наследование компоненты

Любая компонента является производной от общего прародителя TComponent, от его более специализированных наследников (таких как TControl или TGraphicControl) или от существующего компонентного класса. Компонеитой может стать практически любой элемент вашей программы, поведением которого вы хотите управлять на стадии проектирования.

Цель Базовый класс
Модификация существующей компоненты Любая существующая компонента, например,

TListBox, или абстрактный компонентный класс TCustomListBox.
Создание оригинальной компоненты TCustomControl
Создание графической компоненты TGraphicControl
Создание невидимой компоненты TComponent
 

6.7.2.1 Модификация существующих компонент

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



Например, вы можете произвести новую компоненту списка со специальными свойствами, которых нет в стандартном классе

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

TCustomListBox, которая реализует все мыслимые свойства производных компонент списка, однако не выставляет всех их в секции _published.

Наследуя вашу компоненту от одного из абстрактных типов (таких как TCustomListBox), вы всего лишь объявляете в секции _published те свойства, которые хотите включить в вашу компоненту, оставляя остальные в секции protected.

6.7.2.2 Создание оригинальных оконных компонент

С оконным интерфейсным элементом, видимым во время работы программы, пользователь обычно может взаимодействовать. Все оконные компоненты являются производными от базового класса TWinControl. Стандартный элемент оконного управления характеризует так называемый "оконный дескриптор" (window handle), который заключен в свойстве Handle.

Благодаря оконному дескриптору, Windows "узнает" данную компоненту, в частности, что она может принять фокус ввода и передавать оконный дескриптор функциям Windows API для идентификации рабочего окна.

Хотя вы можете создать оригинальный интерфейсный элемент (который не имеет существующих аналогов и никак не связан с ними), используя TWinControl как отправную точку, C++Builder предоставляет компоненту TCustomControl как раз для этой цели. TCustomControl - это специализированный оконный элемент управления, который упрощает рисование сложных визуальных изображений. Если вашей компоненте не нужно принимать фокус ввода, вы можете наследовать ее от графического элемента управления, который дает экономию системных ресурсов. Все компоненты стандартного оконного управления: кнопки, списки, поля редактирования (за исключением TLabel, которая никогда не принимает фокус ввода) - являются косвенными производными TWinControl.

6.7.2.3 Создание графических компонент



Оригинальные оконные и графические компоненты очень сходны. Однако в отличие от производных TCustomControl,

графические компоненты лишены оконного дескриптора и не могут принять фокус ввода. Windows "не узнает" графические компоненты, поэтому их применение не приводит к дополнительным накладным расходам на передачу дескриптора. Графические компоненты обеспечивают отображение объектов без использования системных ресурсов.

Вы должны производить новые графические компоненты от базового абстрактного класса TGraphicControl (который, в свою очередь, является потомком TControl). TGraphicControl предоставляет выбор канвы для рисования и обрабатывает сообщения WM_PAINT. Все, что вам следует сделать, это переопределить метод рисования Paint в соответствии заданными требованиями.

6.7.2.4 Создание невидимых компонент

Мы знаем, что все без исключения компоненты имеют общего прародителя абстрактный класс TComponent. Однако, только невидимые компоненты можно наследовать непосредственно от TComponent.

Любая производная от TComponent наследует все встроенные в нее свойства и методы. Невидимые компоненты встречаются довольно редко и используются, главным образом, в качестве интерфейсных элементов с другими компонентами (доступа к базам данных или как держатели диалоговых окон.

6.7.3 Добавление свойств, событий и методов.

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

События играют чрезвычайно ответственную роль в поведении компонент, Событие - это связь между некоторым происшествием в системе (таким как воздействие пользователя на компоненту или изменение фокуса) и кодом-обработчиком события, который реагирует на это происшествие. Обработчик события почти всегда пишется прикладным программистом, ибо только он знает, какой должна быть реакция на данное событие. Используя события, прикладной программист может приспособить поведение компонент к своим требованиям, без необходимости изменения самих объектов. Предоставить прикладному программисту такую возможность в отношении новой компоненты и является задачей разработчика компоненты. События, возникающие в результате наиболее типичных действий пользователя (например, движений мышью) встроены во все стандартные компоненты VCL, однако вы также можете определить новые события. Мы уже знаем, что C++Builder реализует события как свойства. Помните об этом, когда решите создать или изменить компонентные события.



Мы уже знаем, что компонентные методы ничем не отличаются от других объектных функций-членов. Хотя C++Builder не вводит никаких специальных ограничений на оформление компонентных методов, имеется ряд правил, которых стоит придерживаться. Помните об этом, когда решите создать или изменить компонентные методы.

6.7.4 Регистрация компоненты

Перед тем как ваша компонента сможет работать на стадии проектирования приложения, C++Builder должен зарегистрировать ее. При регистрации становится известным положение новой компоненты в Палитре компонент C++Builder.

Регистрация компоненты - это простой процесс, который информирует C++Builder о том, какая компонента добавляется к VCL и на какой вкладке Палитры она должна появиться.

Чтобы зарегистрировать компоненту:

1. Добавьте функцию Register к файлу МуСотр.срр, заключив ее имя в пространство имен (заметьте, что название пространства имен начинается с заглавной буквы, а все остальные буквы - прописные).

2. В теле функции Register объявите массив типа TComponentClass, в который введите регистрируемую компоненту.

3. В теле функции Register вызовите функцию

RegisterComponents стремя параметрами: название вкладки Палитры компонент, массив компонентных классов и размер компонентных классов.

namespace Mycomp {

void _fastcall Register()

{

TComponentClass classes[1] = {_claesid(TMyComponent)};

RegisterComponents("Samples", classes, 0) ;

) }

Листинг 6.13. Регистрация компоненты.

Листинг 6.13 представляет включение в файл МуСотр.срр кода для регистрации компоненты TMyComponent на вкладке Samples Палитры компонент.

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

6.7.5 Отладка неинсталлированной компоненты

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



1. Включите файл модуля MyComp.h вашей компоненты в заголовочный файл некоторой формы.

2. Добавьте объектный член данных, представляющий испытываемую компоненту, в конец секции public объявлений класса формы, вне области объявлений, которые делает C++Builder.

3. Подсоедините обработчик к событию

OnCreate формы.

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

5. Сразу же за вызовом конструктора установите свойство Parent - родителя компоненты, обычно представляющего собой форму, группирующую рамку или панель инструментов. Обычно значением этого свойства является указатель this. Внимание: Если ваша компонента не является элементом управления, т.е. вы

не наследовали ее от TControl, пропустите этот шаг.

6. Инициируйте значения других свойств компоненты.

Предположим, вы собираетесь испытать компоненту TMyComponent в модуле с именем МуСотр. Создайте новый проект, а затем следуйте перечисленным шагам процесса подготовки модуля формы. Листинг 6.14 содержит законченный образец текста модуля формы отлаживаемой компоненты.

#ifndef TestFormH

#define TestFormH

//---_-_______-_-__-________-_-_._-_____________-_-___-_-_

ttinclude <Classes.hpp>

#include <Controls.hpp> ftinclude <StdCtrls.hpp>

#include <Forms.hpp>

#include "MyComp.h" // 1. //----—---——----—-----—-----—---—_--____-_----------

class TFormI : public Tform {

publ i shed:

private:

public:

TMyComponent* MyComponentI; // 2,

virtual _fastcall TFormI (TComponent* Owner); •// 3,

};

//----—--—---—------—-—-———---—--——-—------——--

extern TFormI *Forml;

//_--__--______----—-----—---------------------—--------

#endif

// Это файл

MyComp.cpp модуля формы:

#include <vcl.h>

#pragma hdrstop



#include "TestForm.h" //——-----——-——--—------—-—--——---—--—----—--—--

ftpragma resource "*.dfm"

TFormI *Forml;

//---------—--—-------------------—---—--------------—

_fastcall TFormI::TFormI(TComponent* Owner) : TForm(Owner)

{

MyComponentI = new TMyComponent(this); // 4. MyComponent->Parent = this;

// 5. MyComponentl->Left = 12; // 6.

}

Листинг 6.14. Текст модуля формы новой компоненты.

6.7.6 Инсталляция компоненты на Палитру

Компонентные модули, написанные на C++, имеют расширение .срр, а компоненты, написанные на Объектном Паскале, имеют расширение

.pas.

При инсталляции новой компоненты или при выполнении команды Component | Rebuild Library, Библиотека Визуальных Компонент перестраивается, и C++Builder создает временный файл CMPLIB32.CPP исходных текстов VCL. Чтобы сохранить этот файл, с помощью команды Options | Environment | Library откройте диалог опций и установите флаг Save Library Source Code.

Чтобы добавить к VCL компоненту, выполните следующие шаги:

1. С помощью команды Component | Install откройте диалоговое окно инсталляции компонент.

2. Нажмите кнопку Add, которая открывает диалог добавления модуля. Введите имя модуля непосредственно в поле Module Name или найдите его местоположение, нажав на кнопку поиска Browse. Имя добавленного вами компонентного модуля появится внизу списка названий группы Installed Components. В списке Component classes вы увидите имена компонентных классов, уже находящихся в выбранной группе Библиотеки. У вновь введенного модуля имя компонентного класса отсутствует.

3. Нажмите кнопку ОК, закрывая диалог инсталляции компонент. Библиотека будет перестроена и новая компонента установлена на ту вкладку Палитры, которую вы определили как параметр функции регистрации (см. Листинг 6.13).

Чтобы удалить компоненту из VCL, выполните следующие шаги:

1. Выполните команду Component | Install, которая открывает диалоговое окно установки компонент.

2. Найдите ненужный вам более компонентный класс в списке Component classes выбранной группы Библиотеки и нажмите кнопку Remove.



3. Нажмите кнопку ОК. Библиотека будет перестроена и новая компонента удалена из Палитры.

Чтобы перестроить Палитру, выполните следующие шаги:

1. Откройте диалог установки опций Палитры с помощью команд Component | Configure Palette или Options | Environment | Palette.

2. Нажмите кнопку Add и выберите имя для новой вкладки. Имя добавленной вами вкладки появится внизу списка Pages названий вкладок.

3. Перетащите мышью выбранную компоненту в списке Components

на нужную вкладку списка Pages.

4. Нажмите кнопку ОК. Библиотека и Палитра будут перестроены.

6.7.7 Сохранение файлов новой компоненты

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

• объектный файл результата компиляции MyComp.obj;

• заголовочный файл объявлений, сгенерированный компилятором (MyComp.h для исходного текста на C++ или MyComp.hpp для исходного текста на Объектном Паскале);

• файл битового образа Палитры

(MyComp.res или

MyComp.dcr);

• файл формы MyComp.dfm, если компонента использует форму.

Перед тем, как использовать вновь созданную компоненту, перепишите в каталог \..

.\CBuilder\LIB\OBJ следующие файлы компоненты МуСотр: все двоичные файлы (с расширениями .dfm, .res и .dcr), все исходные файлы (с расширениями .срр или .pas), все объектные файлы (с расширениями .obj и .Но) и все заголовочные файлы (с расширениями .h или .hpp).

Желательно создать и сохранить контекстно-справочный файл (с расширением .hip).

6.8 Разработка простой компоненты

Перед тем, как приступить к разработке новой компоненты, вы должны заранее четко представить себе, что точно она должна делать и как будет реализовано ее оригинальное поведение. Удостоверьтесь, что ни одна из имеющихся компонент не обладает требуемыми вами способностями. Поскольку в cтaндapтнoм варианте поставки C++Builder отсутствует Инструкция по написанию компонент и исходные тексты VCL, пришлось заимствовать элементарное руководство Криса Эриксона, которое я скачал по сети Internet. Его компонента моделирует бинарный индикатор, который меняет цвет при изменении состоянии. Пока очевидно только, что некоторое свойство компоненты будет хранить текущее состояние (true, если индикатор включен, и false - в противном случае).



Из данной главы мы уяснили, что желательно выбрать для наследования наиболее близкий в иерархии VCL базовый компонентный класс; очевидно, что индикатор представляет собой графическую компоненту семейства TGraphicControl. Поскольку мы разрабатываем "ну очень простую" компоненту, пусть она будет иметь тривиальную форму окружности, а не более хитроумный битовый образ. На первый взгляд, компонента TShape из вкладки Палитры Additional выглядит ближайшим родственником. При внимательном рассмотрении TShape имеет больше свойств и событий, чем нам требуется, хотя и обладает всей нужной функциональностью.

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

Итак, все что мы хотим изменить при наследовании от TShape - это форму; индикатора и цвет кисти при его переключении. Звучит достаточно просто. По";

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

6.8.1 Форма тестового приложения

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

=> С помощью команды File | New

Application создайте пустую форму. => Разместите кнопку TButton на форме.

=> С помощью команды File | Save All сохраните форму и проект приложения в файлах под именами

LEDForm.cpp и

LEDProj.mak.

6.8.2 Модуль тестового приложения

Мастер компонент (Component Wizard) упрощает начальные шаги создания компоненты. Мастер не может автоматически добавлять компоненту к существующему модулю, вам придется проделать это вручную.



=> Выполните команду Component | New и в открывшемся диалоге Мастера компонент заполните поля диалога указанными значениями (Рис. 6.9). Нажмите кнопку ОК.



Рис. 6.9. Диалог Мастера компонент.

=> С помощью команды File | Save или File | Save As сохраните файл

Unitl.cpp под именем LED.cpp.

Теперь можно посмотреть в окне Редактора кода, что сделал C++Builder для подготовки нашей компоненты. Файл LED.h будет содержать объявление нового компонентного класса с конструктором, а также несколько заголовочных файлов предкомпиляции. Файл LED.cpp будет содержать пустой конструктор объекта и функцию Register для регистрации компоненты. Не слишком много для автоматизированного начала...

6.8.3 Члены данных, свойства и методы

Ознакомившись с заготовками программного модуля компоненты, которые создал для нас C++Builder, можно приступить к написанию собственно кода компоненты. Прежде всего, в файле LED.h опишем булеву переменную состояния индикатора и две переменные перечисляемого типа TColor для хранения цветов, отображающих оба состояния. Из главы 3 об основах объектно-ориентированного программирования мы знаем как ограничивать область видимости и уяснили, что эти члены данных следует спрятать в секции private объявлений класса. Там же расположим прототипы функций записи соответствующих свойств, а сами свойства объявим в секции _published (Листинг 6.15).

//---------------________________________________-_____-_--

#ifndef LEDH

#define LEDH //------------_____-_____--_________________________-___--.

#include <vcl\SysUtils.hpp>

#include <vcl\Controls.hpp>

#include <vcl\Classes.hpp>

#include <vcl\Forms.hpp> ^include <vcl\ExtCtrls.hpp> //____----------__________________________________------—

class TLED : public TShape { private:

bool FOnOff; TColor FOnColor; TColor FOffColor;

void _fastcall SetOnOff(const bool Value) ;

void _fastcall ' SetOnColor

void _fastcall SetOffColor (conet TColor OffColor) ;

protected:

public:

_fastcall TLED(TComponent* Owners-published:



property bool LEDOn= { read= FOnOff,write= SetOnOff) ; property ТСоlог OnColor= { read=FOnColor,write=SetOnColor} ; :.,. __property TColor OffColor=

{ read=FOff Color, write= SetOffColor} ;

};

//_____________-___-_----____________------------------——

#endif

Листинг 6.15. Добавления в файл LED.h модуля компоненты.

Еще проще окажутся добавления в файл LED.cpp (Листинг 6.16). Необходимо написать три функции для присвоения значений свойств соответствующим членам данных, а также наполнить конструктор компоненты инструкциями для инициализации переменных.

#include <vcl\vcl.h>

#pragma hdrstop

# include "LED.h" //_-------—----—-____--------—---.————---—---—----—--

static inline TLED *ValidCtrCheck() {

return new TLED(MULL) ;

)

void _fastcall TLED::SetOnOf?(const bool Value) {

POnOff = Value;

Brush->Color ” (POnOff) ? FOnColor : POffColor?

}

//_———————————————-——-^-.-——.————.——————

void _fastcall TLED::SetOnColor(const TColor OnColor) {

POnColor = OnColor;

Brush->Color = (FOnOff) ? FOnColor : FOffColor;

}

//-—---——-„--—--------————----------——--———---—--

void _fastcall TLED::SetOЈfColor(const TColor OffColor) {

FOffColor = OffColor;

Brush->Color = (FOnOff) ? FOnColor : FOffColor;

}

//---_------------------------------------------------------

_fastcall TLED::TLED(TComponent* Owner) : TShape(Owner)

{

Width = 15; // тирина по умолчанию Height = 15; // высота по умолчанию FOnColor = cILime; //

зеленый, когда включен FOffColor = cIRed; // красный, когда выключен FOnOff = false; //

выключен по умолчанию Shape ? atEllipse; //в форме эллипса по умсвдчани Pen->Color = clBlack; //

черный контур по умолчанию Pen->Width = 2; // ширина контура по уйолчанию Brush->Color ^ FOffColor; // цвет заливки по умолчанию

}

//---------------____-______________________--________.

namespace Led

{

void _fastcall Register () {

TComponentClass classes[1] = {__classid(TLED)} ;

RegisterComponents("Samples", classes, 0) ;

} }



Листинг 6.16. Добавления в файл LED.cpp модуля компоненты.

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

6.8.4 Испытание компоненты

Теперь, когда мы закончили с написанием текста модуля компоненты, проверим работает ли она.

=> С помощью команды File | Save All сохраните все сделанные добавления. => Выбрав вкладку LEDForm.cpp в окне Редактора кода, по команд File | Include Unite Hdr включите строку

#include "LED. h" в заголовок файла формы. По неведомой причине, эта команда не работает с файлом LEDForm.h, поэтому строку

#include "LED.h"

приходится вставлять вручную. К секции private этого же файла добавьте описание объекта индикатора:

private: // User declarations TLED* LED1;

=> Активизируйте форму Formi и в окне Инспектора объектов дважды щелкните мышью в графе значений события OnCreate. С помощью Редактора кода введите обработчик этого события в файл LEDForm.cpp.

Следующий код создаст компоненту TLED динамически (определяя ее родителя Parent и помещая в в центре родительской формы) во время выполнения тестового приложения:

void_fastcall TFormI::FormCreate(TObject *Sender)

t

LED1 = new TLED(this);

LED1->Parent = this;

// Центрировать компоненту по ширине формы LEDl->Left = (Width/2)-(LEDl->Width/2);

// Центрировать компоненту по высоте формы LEDl->Top = (Height/2)-(LEDl->Height/2);

}

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

void_fasfccall TPormI::ButtonlClick(TObject *Sender) (

LEDl->LEDOn = !LEDl->LEDOn;



}

=> Наконец, скомпилируйте и запустите тестовое приложение посредством команды Run | Run.

Если компилятор не выдаст ошибок (а их не должно быть, если вы точно следовали изложенной процедуре), то посередине формы тестового приложения вы увидите красный индикатор в состоянии "выключен". Нажав кнопку, вы включите индикатор и он окрасится зеленым цветом (Рис. 6.10).

Теперь осталось создать битовый образ пиктограммы, которой новая компонента будет представлена в Палитре. Из меню редактора изображений, открывающегося по команде Tools | Image Editor,

выберите File | New | Resource File, a затем - Resource | New) Bitmap.

В диалоге свойств битового образа установите размеры пиктограммы 24х24 и число цветов VGA (16 Colors).

Переименуйте битовый образ компоненты (TLED) по команде Resourse | Rename и дважды щелкните мышью на выбранном имени в древовидном списке ресурсных файлов, чтобы нарисовать подходящую картинку индикатора (например, зеленый кружок). Командой File | Save As сохраните ресурсный файл LED.res в своем рабочем каталоге и закройте Редактор изображений.



Рис. 6.10. Динамическое создание компоненты индикатора.

 

6.8.5 Инсталляция компоненты

Перед тем, как приступить к инсталляции новой компоненты на Палитру, выполните последний раз команду File | Save All.

=> С помощью команды Component | Install откройте диалоговое окно инсталляции компонент. Нажмите кнопку Add, которая открывает диалог добавления модуля. Найдите местоположение модуля LED.cpp, нажав на кнопку поиска Browse. Нажмите кнопку ОК и приготовьтесь ждать окончания перестройки VCL и установки новой компоненты на Палитру.

=> Выполните команду File | Close All, а затем File | New

Application. Поместите новую компоненту LED и кнопку TButton на форму. Снова определите обработчик события OnClick кнопки управления индикатором:

void_fastcall TFormI::ButtonlClick(TObject *Sender) {

LEDl->LEDOn = lLEDl->LEDOn;

}

=> Выполните команду Run | Run и вы увидите, что компонента действительно работает.

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

рекомендует использовать каталог \..

ACBuilder\LIB\OBJ) и приступайте к планированию вашей следующей компоненты.

6.9 Итоги

Планируете ли вы использовать Библиотеку Визуальных Компонент при создании прикладного программного обеспечения, или развивать существующую Библиотеку при разработке новых компонент — глубокие знания состава и уст роиства VCL

будут способствовать успешному решению поставленных задач


Компоненты вкладки Data Access


2.2.4 Компоненты вкладки Data Access

Компоненты этой вкладки осуществляют включение в ваше приложение следующих элементов, обеспечивающих доступ к базам данных:

TDataSource Действует как интерфейс между TTable, TQuery и TStoredProc и компонентами управления данными типа TDBGrid.
ТТаЫе Обеспечивает доступ к таблицам базы данных.
TQuery Обеспечивает передачу команд на языке структурированных запросов SQL

серверу локальной или удаленной базы данных.

TStoredProc Разрешает выполнение хранимых процедур сервера удаленной базы данных.
TDatabase Эта компонента не участвует в организации доступа к базам данных, хотя предоставляет возможность управления в приложениях клиент/сервер.
TSession Предоставляет средства глобального управления групповых соединении с несколькими базами данных.
TBatchMove Разрешает выполнять пакетные операции над группами записей или целыми таблицами.
TUpdateSQL Предоставляет специальный механизм обновления данных, возвращаемых некоторыми запросами

SQL.

2.2.5 Компоненты вкладки Data Controls

Компоненты этой вкладки осуществляют включение в ваше приложение следующих элементов управления визуализацией и редактированием подсоединенной базы данных:

TDBGrid Отображает и позволяет редактировать записи таблицы или запроса базы данных на сетке.
TDBNavigator Используется для перемещений по записям таблицы или запроса базы данных и для выполнения операций по их просмотру и редактированию.
TDBText Отображает статический текст названия текущей записи таблицы или запроса базы данных.
TDBEdit Создает однострочную область редактируемого ввода в текущую запись таблицы или запроса базы данных.
TDBMemo Создает многострочную область редактируемого ввода (включая данные в формате BLOB) в текущую запись таблицы или запроса базы данных.
TDBImage Создает контейнер для представления графического изображения, которое хранится в поле текущей записи в формате BLOB.
TDBListbox Создает список, выбранный элемент которого становится новым значением поля текущей записи таблицы или запроса базы данных.
TDBComboBox Создает комбинацию области редактирования и выпадающего списка текстовых строк для изменения значения текущей записи в наборе данных.
TDBCheckBox Создает элемент управления с двумя состояниями, связанными с конкретным полем записи таблицы или запроса базы данных.
TDBRadioGroup Создает контейнер для группы логически взаимоисключающих радио-кнопок, связанных с конкретными полями записи таблицы или запроса базы данных.
TDBLookupList Создает список ссылок для заполнения полей данными из другой таблицы или запроса базы данных.
<
TDBLookup ComboBox Создает комбинацию области редактирования и выпадающего списка ссылок для заполнения полей данными из другой таблицы или запроса базы данных.
2.2.6 Компоненты вкладки Dialogs

Компоненты этой вкладки осуществляют включение в ваше приложение следующих стандартных диалоговых элементов

Windows:

TOpenDialog Открывает доступ к диалогу открытия файлов.
TSaveDialog Открывает доступ к диалогу сохранения файлов.
TFontDialog Открывает доступ к диалогу выбора шрифтов и их атрибутов.
TColorDialog Открывает доступ к диалогу выбора цветов.
TPrintDialog Открывает доступ к диалогу печати (выбор принтера, диапазона печатаемых страниц, числа копий и т.п.).
TPrinterSetup Dialog Открывает доступ к диалогу предварительных установок принтера перед печатью.
TFindDialog Открывает доступ к диалогу поиска текста.
TReplaceDialog Открывает доступ к диалогу поиска текста с заменой.
2.2.7 Компоненты вкладки System

Компоненты этой вкладки осуществляют включение в ваше приложение следующих специализированных системных элементов управления:

TTimer Вызывает возникновение события OnTimer по прошествии заданного временного интервала.
TPaintBox Предоставляет возможность рисования на форме внутри заданной прямоугольной области.
TFiIeListBox Перечисляет все файлы в текущем каталоге, доступные программе во время ее работы.
TDirectoryListBox Отображает древовидную структуру каталогов текущего диска, доступных программе во время ее работы.
TDriveComboBox Отображает комбинированный редактируемый список дисков, доступных программе во время ее работы.
TfilterComboBox Представляет комбинированный редактируемый список фильтров для выбора имен файлов с расширениями.
TMediaPlayer Отображает стандартную панель управления устройствами мультимедиа (звуковая плата, компакт диск, видеокамера, AVI плеер, MIDI секвенсор и др.), которые поддерживаются MCI-драйверами Windows.
TOIeContainer Организует связь с OLE объектами или непосредственно включает их в ваше приложение.
TddeClientConv Устанавливает режим динамического обмена данными

DDE клиента.
TDDEClientltem Определяет элемент динамического обмена данными

DDE клиента.
TDDEServerConv Устанавливает режим динамического обмена данными

DDE сервера.
TDDEServerItem Определяет элемент динамического обмена данными

DDE сервера.
<


 

2.3 Приложения управления базами данных

Если вы не чувствуете себя достаточно уверенно, чтобы сразу перейти к самостоятельному программированию приложении СУБД в среде C++Builder, просмотрите готовые примеры, входящие в комплект поставки системы. Обратите внимание на методику адаптации приложении применительно к специфике ваших задач. 1 ,,

Доступ к базам данных поддерживает его основа - высокопроизводительный механизм BDE (Borland Database Engine),

включающий 32-разрядные драйверы для баз данных dBASE, Paradox; Sybase, Oracle, DB2, Microsoft SQL Server, Informix, InterBase и Local Interbase. Кроме того C++Builder имеет быстродействующий механизм ODBC для связи с такими базами данных, как Excel, Access, FoxPro и Btrieve в архитектуре клиент/сервер. Поскольку в наших примерах используется только демонстрационная база данных BCDEMOS, удостоверьтесь предварительно, что ее локальный псевдоним (alias) установлен с помощью утилиты конфигурации BDE. Если вы располагаете другими источниками данных, укажите их.

2.3.1 Пример из существующего проекта

Данный пример демонстрирует работу компонент доступа TDBGrid, TDBText, TDBImage, TDataSource, TTable и TDBMemo, а также - компоненты стандартного диалога TSaveDialog. Уже на стадии проектирования вы сможете просматривать соответствующую таблицу базы данных и с помощью линейки прокрутки компоненты сетки TDBGrid открывать "живые" факты из жизни обитателей моря. Чтобы начать работу с существующим проектом приложения, выполните следующие действия:

По команде главного меню File | Open Project откройте диалог выбора проектов.

Войдите в каталог

\...\CBuilder\Examples\Dbtasks\FishFact.

Выберите проектный файл с именем Fish fact и нажмите кнопку Open



Open

(Рис.2.14).


Рис. 2.14. Пример приложения, использующего существующий проект.

Источник данных приложения определяется свойствами компоненты TTable:

свойство DatabaseName указывает на базу данных BCDEMOS, а свойство TableName - на таблицу BIOLIFE.



Если захотите, скомпилируйте и соберите этот пример. После запуска вы снова получите доступ к изображениям и описаниям рыб в установленной таблице базы данных (Рис. 2.15). Сохраните информацию о заинтересовавшей вас рыбе в виде текстового файла, открывая кнопкой

Save стандартный диалог компоненты TSaveDialog. Кнопка Exit осуществляет выход из приложения.



Рис. 2.15. Приложение FISH FACTS в работе.

2.3.2 Пример использования модулей данных

Архитектура приложений C++Builder для баз данных основана на применении технологии RAD и объектно-ориентированного программирования как к пользовательскому интерфейсу, так и к бизнес-логике баз данных. Модули данных (Data Modules) поддерживают естественное отделение кодов бизнес-логики обработки данных и компонент пользовательского интерфейса, размещенных на форме.

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

Реализация различных способов доступа к элементам баз данных сосредоточена в компонентах вкладки Data Access Палитры компонент. Эти интерфейсные элементы заключают в себе такие характеристики источника информации, как спецификации конкретной базы данных, таблиц, запросов и ссылок к полям в некоторой записи.

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

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

=> Выполните команду File | New из главного меню. => На вкладке Data Modules выберите значок



Customer Data, а затем нажмите

кнопку ОК.

=> Дважды щелкните мышью на таблице

Customers модуля данных. Откроется список Customerdata->Customers полей таблицы заказчиков (Рис. 2.16).



Рис. 2.16. Поля таблицы заказчиков

Customers модуля данных Customer Data.

=> Удерживая нажатой клавишу Shift, выберите нужные вам поля из списка. => Перетащите выбранные поля и разместите их на форме. => Перетащите компоненту навигатора базы данных DBNavigator

из вкладки Data Control Палитры и в ее свойстве DataSource укажите источник данных

CustomerData->CustomerSource.

Теперь вы сможете просматривать "живые" данные всех записей в таблице заказчиков уже на стадии проектирования формы приложения (Рис. 2.17). Для этого нажимайте кнопки со стрелками на панели, расположенной в верхней части списка полей таблицы заказчиков. С помощью Инспектора объектов модифицируйте по своему усмотрению свойства компонент полей (например, в свойствах Caption замените все названия на русскоязычные).



Рис. 2.17. Форма приложения для доступа к таблице заказчиков.

Когда вы скомпилируете и соберете приложение, вы увидите те же данные, что и на стадии проектирования.



Рис. 2.18. Приложение "Заказчики" в работе.
Теперь, пользуясь кнопками панели навигатора, вы сможете редактировать данные -вставлять новые записи, Bычеркивать ненужные, менять содержание полей и т.д. Рис. 2.18 показывает результат введения в таблицу атрибутов вымышленного отечественного заказчика (после нажатия кнопки "+"). Внимание:

На этом примере вы можете впервые столкнуться со сложностями в использовании русского шрифта при попытках модифицировать оригинальные таблицы демонстрационной базы данных BCDEMOS, входя щей в комплект C++Builder
Теперь, пользуясь кнопками панели навигатора, вы сможете редактировать данные -вставлять новые записи, Bычеркивать ненужные, менять содержание полей и т.д. Рис. 2.18 показывает результат введения в таблицу атрибутов вымышленного отечественного заказчика (после нажатия кнопки "+"). Внимание:



На этом примере вы можете впервые столкнуться со сложностями в использовании русского шрифта при попытках модифицировать оригинальные таблицы демонстрационной базы данных BCDEMOS, входя щей в комплект C++Builder

Standard. He думаю, что такое ограничение корпорация Borland ввела сознательно. Не относитесь к этой проблеме слишком серьезно - ведь нашей задачей является обучение современной методике программирования СУБД, для чего демонстрационная база дает достаточный экспериментальный материал (хотя и англоязычный), а вовсе не модификация самой BCDEMOS.

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

2.3.3 Пример использования Мастера форм

Прежде, чем начать работу с последним примером этой главы, просмотрите Словарь баз дачных (Database Dictionary),

выполнив команду главного меню Database | Explorer (Проводник базы данных). Открывшееся окно словаря (Рис. 2.19) состоит из двух панелей. В древовидном перечне левой панели найдите таблицу базы данных, которую вы собираетесь связать с формой проектируемого приложения. Для разработки приложения "Моя записная книжка" я создал в Excel таблицу с именем NOTEBOOK. He беда, если вы не захотите построить собственную рабочую таблицу в рамках Excel, Access, Paradox или какой-нибудь другой системы - при изучении примера можно воспользоваться англоязычным прототипом CLIENTS из базы данных BCDEMOS.

Описание выбранной таблицы представлено тремя вкладками правой панели. На вкладке

Definition вы найдете характеристики таблицы (дата, время создания, тип). Вкладка Enter SQL позволяет вводить и редактировать команды на языке структурированных запросов SQL к таблицам базы данных, расположенных на локальном или удаленном сервере. Если вы вводите команды изменения данных таблицы INSERT, UPDATE или DELETE, убедитесь, что опция меню Options | Live Queries не выбрана. Чтобы выполнить текущую команду SQL, нажмите кнопку с изображением молнии справа от поля редактирования. Вкладка Data показывает текущее содержание таблицы:





Рис. 2.19. Содержание таблицы NOTEBOOK а окне Проводника базы данных.

Для использования Мастера форм при создании приложения выполните следующие действия:

=> С помощью команды Database | Form Wizard из главного меню вызовите Мастер форм, который проведет вас по диалоговым страницам характеристик создаваемой формы.

=> На первой странице (Рис. 2.20) укажите, что создаете простую форму на основе компонентных объектов таблицы базы данных (Create a form using TTable objects). Нажмите кнопку Next.



Рис. 2.20. Первая страница диалога Мастера форм.

=> На второй странице (Рис. 2.21) найдите вашу собственную таблицу NOTEBOOK.DBF (или ее прототип

CLIENTS.DBF) из базы данных с псевдонимом BCDEMOS, которая будет использоваться формой приложения. В данном примере обе таблицы хранятся в каталоге CAProgram Files\Borland\CBuilder\Examples\DATA.

Нажмите кнопку Next.



Рис. 2.21. Вторая страница диалога Мастера форм.

=> На третьей странице (Рис. 2.22) выберите нужные вашему приложению поля таблицы из списка Available Fields и нажатием кнопки ">" перенесите их в список Ordered Selected Fields. В данном примере выбраны 5 полей. Нажмите кнопку Next.



Рис. 2.22. Третья страница диалога Мастера форм.

=^> На четвертой странице (Рис. 2.23) задайте расположение выбранных полей на форме - вертикально. Нажмите кнопку Next.



Рис. 2.23. Четвертая страница диалога Мастера форм.

=> На пятой странице (Рис. 2.24) задайте положение названий относительно полей - слева. Нажмите кнопку Next.



Рис. 2.24. Пятая страница диалога Мастера форм.

=> На шестой странице (Рис. 2.25) можно дополнительно потребовать создать для формы новый модуль данных. Нажмите кнопку

Finish, завершая разработку формы приложения базы данных под управлением Мастера форм.



Рис. 2.25. Шестая страница диалога Мастера форм.

Далее, как обычно, можно воспользоваться Инспектором объектов, чтобы адаптировать компоненты формы к более удобному для вас представлению (Рис. 2.26).





Рис. 2.26. Форма приложения, созданная Мастером форм.

Когда вы скомпилируете и соберете приложение, исходные данные таблицы появятся в том виде. как вы их видели в Словаре баз данных.



Рис. 2.27. Приложение "Моя записная книжка' и работе.
Теперь, пользуясь кнопками панели навигатора, вы сможете редактировать содержимое записной книжки - вставлять новые записи, вычеркивать ненужные, редактировать содержание полей и т.д. Рис. 2.27 отображает запись, которая стала начальной в результате вычеркивания первой записи в исходной таблице NOTEBOOK (после нажатия кнопки "-").

Естественно, что оригинальная таблица CLIENTS способна предоставить вам другие данные (Рис. 2.28).


Рис. 2.28. Работа приложения базы данных с таблицей CLIENTS.

В последнем примере Мастер форм проявил себя как чрезвычайно полезный для новичков и удобный в обращении встроенный инструмент

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

2.4 Итоги

C++Builder для операционных систем Windows 95 и NT

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