C++ Программирование в среде С++ Builder 5

         

Код компонента


Создание визуального компонента — процесс сам по себе не визуальный. Все сводится к написанию кода для свойств и методов класса компонента. Здесь вам может очень помочь ClassExplorer, автоматически или, скорее, полуавтоматически генерирующий базовый код. С двумя его диалогами — для полей и методов — вы уже познакомились в предыдущей главе. Правда, чтобы можно было вводить в класс компонента поля, методы и свойства средствами обозревателя классов, нужно сначала создать проект, который будет этот компонент использовать. Создайте новое приложение и присоедините к его проекту модуль CTickTape.cpp (это делается либо в контекстном меню менеджера проектов, либо выбором Project | Add to Project... в главном меню). Созданное приложение станет потом тестовой программой для проверки работоспособности нашего компонента. Пока же с ним ничего делать не нужно.

Registei-() и ValidCtrCheck()

C++Builder уже создал заготовку компонента — файл CTickTape.cpp. Он содержит на данный момент пустой конструктор и две функции — Registerf) и ValidCtrCheck():

static inline void ValidCtrCheck(CTickTape *)

{

new cricKTapenull);

}

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

_fastcall CTickTape::CTick(TComponent*Ownet)

: TGraphicControl(Owner) { }

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

namespace Cticktape {

void _fastcall PACKAGE Register()

(



TComponentClass classes[1] =

{_classid(CTickTape)};

RegisterComponents("Samples", classes, 0);

}

}

Процедура Register () вызывается при регистрации компонента в палитре C++Builder. Первый ее оператор создает массив компонентов (метаклассов), состоящий в нашем случае из единственного элемента.

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

Ввод пользовательского кода

Завершенный код компонента показан в нижеприведенных листингах 15.1 и 15.2.




Листинг 15.1. Класс компонента телетайпной ленты — CTickTape.h







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

#ifndef CTickTapeH

#define CTickTapeH

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

#include <SysUtils.hpp>

#include <Controls.hpp>

#include <Classes.hpp>

#include <Forms.hpp>

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

typedef void _fastcall (_closure *TPassCoitipleteEvent)

(System::TObject *Sender, boolS stop);

class PACKAGE CTickTape : public TGraphicControl { private:

int FTickRate;

unsigned long FNextTick;

bool FStarted;

bool needsFill;

int storeWidth;

int position;

Graphics::TBitmap* bm;

TPassCompleteEvent POnPassComplete;

void _fastcall SetStartcd(bool value);

void fastcall SetTickRate(int value);

void _fastcall CMChanged(Messages::TmeasageS message) ;

protected:

virtual void _fastcall Setup ();

virtual void_fastcall DoDrawText(TRect rect, long flags);

virtual void fastcall Paint();

virtual void fastcall PassComplete();

public:

_fastcall CTickTape(TComponent* Ownersvirtual void fastcall Tick();

_fastcall -CTickTape();

_property unsigned long NextTick = {

read=FNextTick, write=FNextTick };

_property bool Started =

{ read=FStarted, write=SetStarted };

_published:

property Caption;

property Font;

_property ParentFont;

_property int TickRate = { read=FTickRate,

write-SetTickRate, default=10};

_property TPassCompleteEvent OnPassComplete = { read=FOnPassComplete, write^FOnPassComplete };

BEGIN_MESSAGE_MAP

VCL_MESSAGE_HANDLER(CM_FONTCHANGED,

TMessage, CMChanged) ;

VCL_MESSAGE_HANDLER(CM_TEXTCHANGED,

TMessage, CMChanged) ;

END_MESSAGE_MAP(TGraphicControl) ;

};

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

#endif



Листинг 15.2. Модуль компонента — CTickTape.cpp







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

// CtickTape.срр: Модуль компонента "Бегущая строка".

//

#include <vcl.h>

#pragma hdrstop

#include "CTickTape.h"

#pragma Package (smart_init)

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

// VolidCtrCheck is used to assure that the components

//createddonot have any pure virtual functions.



static in void ValidCtrCheck (CTickTape *)

{

new CTickTape (NULL);

}

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

_fastcall CTickTape: :CTickTape (TComponent* Owner)

:TGraphicControl (Owner)

{

Width = 100;

FTickRate = 10;

ControlStyle << csOpaque;

bm = new Graphics::TBitmap ;

Setup ();

}

_fastcall CTickTape::~CTickTape () {

delete bm;

}

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

namespace Cticktape {

void _fastcall PACKAGE Register() {

TComponenfcClass classes[1] =

{_classid(CTickTape)};

RegisterComponents("Samples", classes, 0) ;

} I

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

// Установка параметров битовой матрицы.

//

void _fastcall CTickTape::Setup() {

AnsiString text = Caption;

bm->Canvas->Font = Font;

Height = bm->Canvas->TextHeight(text);

storeWidth = Width;

bm->Width = bm->Canvas->TextWidth(text) + 1;

bm->Height = Height;

bm->Canvas->Brush->Color = Color;

bm->Canvas->TextOut(0, 0, text + " ");

if (ComponentState.Contains(csDesigning))

position = 0;

else

position =г Width;

needsFill = true;

}

void_fastcall CTickTape::DoDrawText(TRect rect, long flags) {

if (Width != storeWidth) Setup() ;

if (needsFill) {

Canvas->Brush->Color = Color;

Canvas->FillRect(rect);

needsFill = false; .

} Canvas->Draw(position, 0, bm) ;

}

void _fastcall CTickTape::Paint() {

TRect rect - ClientRect;

DoDrawText(rect, 0);

}

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

// Сдвиг строки на пиксел, если истек

// очередной интервал ожидания.

//

void _fastcall CTickTape::Tick()

{

if ( ! FStarted || (GetTickCount () < FNextTicK) ) return;

FNextTick += FTickRate;

Repaint () ;

if (~position < - bm->Width) {

position = Width;

PassComplete ();

}

}

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

// Set-функции.

//

void _fastcall CTickTape::SetStarted(bool value)

{

if (value == FStarted) return;

FStarted = value;

if (value)

FNextTick = GetTickCount ();

}

void _fastcall CTickTape::SetTickRate (int value)



{

if (value > 0) FTickRate = value;

}

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

// Отработка сообщений FontCbanged и TextChanged.

//

void _fastcall CTickTape::CMChanged(Messages::

TMessage& message)

{

Setup () ;

Repaint () ;

}

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

// Событие OnPassComplete.

//

void_fastcall CTickTape:: PaseComplite()

{

if (OnPassComplete) { bool stop = false;

OnPassComplete (this", stop);

Started = [stop];

} }

Если вы хотите собственноручно повторить все этапы создания этого компонента, то, воспользовавшись услугами обозревателя классов и руководствуясь листингами, введите в класс следующие элементы:

  • поля needsFill, storeWidth, position и bm;


  • методы Setup(),DoDrawText(),Paint(),PassComplete(),CMChanged (), Tick () и деструктор;




    • свойства NextTick, Started, TickRate и OnPassComplete (последнее будет событием компонента).


    Не забудьте также ввести код тела конструктора.

    В файл CTickTape.h введите typedef замыкания TPassComplete-Event и четыре строки с макросами, которые вы видите в самом конце определения класса. Переобъявите в разделе _published свойства Caption, Font и ParentFont. Это защищенные свойства класса TControl. Если подходить к делу написания компонента совсем серьезно, можно и должно было бы переобъявить и другие унаследованные свойства и, возможно, ввести еще какие-то другие, но для демонстрации этих трех вполне достаточно. Даже ParentFont, пожалуй, лишнее.

    Вот, кажется, и все. Сохраните компонент (оба файла). Теперь мы рассмотрим, как он работает.


    Содержание раздела