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

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

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

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

наследовать от TCustomButton.

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

Давайте вернемся к определению того, какие же свойства нам надо предоставить компоненту TAngleText. Прежде всего, нам нужно свойство для текста (Text), который мы собираемся поворачивать. Свойство Text — одно из базовых свойств, принадлежащих классу TCustomControl, так что здесь никакой работы для нас нет. Все, что нам надо, это представить это свойство (позже мы рассмотрим, как это сделать за пару секунд), и оно будет работать, как обещано. Следующее очевидное свойство, которое нам надо определить, это угол (Angle), на который будет повернут текст. Это свойство мы назовем Angle.

Разобравшись с двумя простейшими свойствами, давайте посмотрим, какие еще свойства нам надо определить для нашего компонента. Все компоненты VCL автоматически имеют свойства для обозначения позиции и родителя. Это свойства Left (левый отступ), Top (верхний отступ), Heigh (высота), Width (ширина) и Parent (родитель). Ни одно из этих свойств вам, разработчику компонентов, определять уже не надо.

Первое, о чем следует задуматься то, каким образом рисуется строка под углом. Для этого нам нужны три вещи. Во-первых, отображаемая строка. Это свойство Text нашего компонента. Во- вторых, нужен угол, на который строка будет повернута. Это уже определенное нами свойство Angle. И, наконец, нам нужна позиция, в которой будет отображаться строка, то есть базовая точка нашей строки. Мы могли бы определить эту точку автоматически, но это не самое лучшее решение. Некоторые пользователи могут пожелать, чтобы строка появлялась отцентрованной по вертикали, другие захотят отобразить ее вверху компонента, третьи внизу. Вместо того, чтобы самим решать это за всех, мы предоставим конечному пользователю (то есть программисту, который будет использовать наш компонент) определение базовой точки. С точкой как таковой работать тяжело, поэтому мы предоставим два свойства X-координату и Y-координату базовой точки.

Следующим после базовой точки аспектом, который нам надо рассмотреть, станет собственно отрисовка компонента. Для того, чтобы изменять отображение компонента, нам нужен шрифт для отображения. Мы могли бы просто использовать родительский шрифт, но это было бы неоправданным ограничением свободы пользователя. Поэтому мы представим свойство Font класса TCustomControl для конечного пользователя. Точно так же мы должны предоставить пользователю возможность изменять цвет фона компонента, чтобы компонент мог, если в этом есть необходимость, выделяться на форме, в которой расположен. Для этого мы представим свойство Color. Итак, на данный момент у нас есть шесть свойств, выбранных для компонента. Три из них предоставляет базовый класс TCustomControl (Font, Text и Color), а три должны быть воплощены нашим компонентом (Angle, XPos и YPos). Настало время перейти к собственно кодированию.

Воплощение нового компонента

CBuilder — не такой уж великий помощник в создании компонентов. Мастер компонентов (Component Wizard) может быть использован для создания самого простейшего скелета компонента, но после этого ничем помочь уже не может. Мы сделаем кое-что подобное самостоятельно чуть позже, а пока собственно создание компонента принесет вам кое-какую пользу и покажет, для чего и как служат отдельные части.

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

Мастер компонентов CBuilder служит для создания скелета компонента в CBuilder. Вы можете предположить, что подобный инструмент должен находиться в меню Tools (инструменты), но это не так. Выберите Component|New в главном меню CBuilder, и увидите окно Мастера компонентов, показанное на рис. 14.1. Это простейшее окно позволит вам определить имя компонента, базовый класс компонента и страницу палитры, в которой вы будете отображать компонент. Вот и все, что вы можете определить в Мастере компонентов. В нем нет полей ввода ни для свойств, которые вы хотите добавить в компонент, ни для добавляемых методов, ни для событий, которые должны обрабатываться. Все это вам придется определять самим, но не пугайтесь мы шаг за шагом проделаем весь процесс в этой главе.

Рис. 14.1. Мастер компонентов CBuilder

Для нашего примера введите имя компонента TAngleText. Выберите компонент TCustomControl в качестве базового класса компонента и оставьте предлагаемую по умолчанию страницу Samples в поле выбора страницы палитры. Нажмите кнопку OK, и компонент будет автоматически сгенерирован и добавлен в ваш проект. Это весьма полезно, так как дает нам возможность протестировать компонент прямо в проекте до того, как он будет сынсталлирован в системе. А отлаживать и тестировать компонент в проекте гораздо проще, чем делать это после того, как он сынсталлирован.

Добавление родительских свойств

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

В заголовочном файле вашего компонента вы найдете строку __published. Все пункты, находящиеся в этой секции, будут отражены в Object Inspector среды CBuilder, когда компонент будет выделен на форме в окне редактора форм. Если вы добавляете описание вне этой секции, свойство будет доступно программисту во время исполнения (конечно, если оно будет находиться в секции public заголовочного файла), но не будет отображаться во время проектирования. Свойства, располагающиеся вне секции __published, известны как свойства, доступные только во время исполнения (runtime-only).

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

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

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

__published: __property Text; __property Font; __property Color;

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

Добавление новых свойств

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

__published:

__property double Angle={read=FAngle, write=FAngle, default=0};

__property int

XPos={read=FXPos, write=SetXPos};

__property int

YPos={read=FYPos, write=SetYPos};

В данном случае приведенные выше описания свойств определяют новые свойства для класса компонента, которые будут доступны во время проектирования. Свойство Angle определено как имеющее тип double. В общем виде формат выражения __property имеет следующий вид:

__property <тип> <ИмяСвойства>={[read=

<ФункцияЧтенияИлиЗначение>]

[,write=<ФункцияЗаписиИлиЗначение>][,default=<значение>]};

где <тип> — допустимый тип C++ для этого свойства. Обычно типом свойства является один из базовых типов C++, такой, как short, long, int и т. п.

<ИмяСвойства> — имя свойства; под этим именем свойство появится и в Object Inspector. <ФункцияЧтенияИлиЗначение> — это либо функция, которая будет использоваться для чтения значения свойства, или само значение. Мы остановимся на этом чуть позже. <ФункцияЗаписиИлиЗначение> — то же самое, что и функция чтения, но относится к изменению значения свойства.

<значение> — значения компонента по умолчанию, отображаемое в Object Inspector. Отметьте, что значения по умолчанию НЕ устанавливают собственно свойство компонента, они только отображаются в Object Inspector во время проектирования.

Так что же, самом деле, представляют из себя функции чтения (Read) и записи (Write)? Здесь мы подошли к самому критическому различию между свойством и переменной-членом класса (member variable). Несмотря на то, что в вашем коде, использующем компонент, свойства проявляют себя как простые переменные-члены класса, они, на самом деле, представляют из себя нечто большее. Переменные-члены класса просто позволяют пользователю присваивать значения свойствам компонента и модифицировать их. Вы можете не разрешить им напрямую присваивать

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

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

myComponent->SetArrayElement(3,12);

если мне куда больше нравится такая запись: myComponent->Array[3] = 12;

Первое значение (3) — это номер элемента массива или его значение? Вы не сможете сказать этого наверняка, не сверившись с документацией. Для случая с двумерным массивом дела обстоят и того хуже:

myComponent->Set2Darray(1,2,12);

Опять-таки, что здесь номер строки? Что здесь номер столбца? Что является присваеваемым значением? Представьте, что вместо этого можно написать просто:

myComponent->Array[1][2] = 12;

Не кажется ли вам, что такая запись повлечет за собой куда меньше ошибок? Ну конечно это так. Используя функции Read и Write подобные вещи пишутся проще. Кроме того, если вы не хотите, чтобы пользователь мог изменять значение свойства компонента, вы просто опускаете функцию Write, и пользователь не сможет его изменить. Не кажется ли вам, что это гораздо более приятно, чем беспокоиться о функциях доступа, использующих Set (установить) и Get (получить)? В качестве примечания замечу, что вы на самом деле можете опустить функцию Read, оставив пользователю возможность изменять значение свойства посредством функции Write. Не зная уж, зачем вам может понадобиться предоставление пользователю этакого черного ящика, но возможность такая есть.

Замечание

Значение по умолчанию может быть определено при помощи предложения default= в выражении, определяющем свойство (то есть выражении __property). Но это не установит значение свойства в значение, указанное в этом предложении, а только поместит его в Object Inspector, когда ваш компонент будет впервые создан. Если вы хотите инициализировать значение при помощи предложения default=, вам придется установить значение свойства в конструкторе класса.

Я надеюсь, вы поняли, почему следует использовать функции Read и Write в вашем компоненте, но теперь встает вопрос как их использовать? Если вас не волнует то, какое значение пользователь установит для свойства (как это не волнует нас в случае свойства Angle), то вы можете просто присвоить самой переменной значение функции Read или Write. Для свойства Angle мы так и поступим. В случае же, если вы хотите каким-то образом фильтровать вводимые значения, вы присваиваете функцию-член класса нашей функции. Давайте пока добавим в класс компонента переменные для свойств, чтобы вам было проще воспринимать происходящее. В секцию приватных объявлений (private) заголовочного файла добавьте следующие строки:

private:

double FAngle; int FXPos;

int FYPos;

Эти переменные-члены класса не более чем нормальные переменные C++, к которым вы, наверное, привыкли, работая с классами C++. У конечного пользователя (программиста) нет к ним

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

прямого доступа. Является общепринятым использование префикса F при работе с переменными, которые представляют свойства компонента. Это наследие оригиналов компонентов Delphi, но тем не менее весьма полезное для использования соглашение.

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

pAngleText->Angle = 90.0;

то этот код автоматически присваивает переменной-члену класса FAngle значение 90.0. Это происходит без вашего участия при посредстве базового класса и компилятора С++, встроенного в CBuilder. В то же время, когда программист пишет строку кода следующего содержания:

pAngleText->XPos = 100;

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

virtual void __fastcall SetXPos(int XPos ); virtual void __fastcall SetYPos(int YPos );

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

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

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

Вот как выглядит воплощение этих двух методов:

void __fastcall TAngleText::SetXPos(int XPos )

{

if ( XPos < 0 || XPos > Width ) return;

FXPos = XPos;

}

void __fastcall TAngleText::SetYPos(int YPos )

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

{

if ( YPos < 0 || YPos > Height ) return;

FYPos = YPos;

}

Как видно из приведенного кода, функция просто проверяет, что заданные вами значения лежат внутри границ компонента. Это весьма распространенный случай. Если значение является допустимым, переменной-члену класса присваивается новое значение. Если значение не является допустимым, метод просто возвращает управление. Что же происходит с переменной-членом класса в этом случае? Ничего. Вы надежно защитили собственно свойство компонента от получения некорректных данных, причем гораздо лучше и проще, чем Set и Get.

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

__fastcall TAngleText::TAngleText(TComponent* Owner) : TCustomControl(Owner)

{

FXPos = -1;

FYPos = -1;

Angle = 0;

}

Обратите внимание, что мы не инициализировали, не получали, не устанавливали свойств Text, Font или Color. Эти свойства относятся к компонентам низкого уровня и инициализируются там. Правда, вы могли бы инициализировать их в своем собственном конструкторе, что заместило бы установки базового класса.

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

Отрисовка управляющего элемента

Наиболее важным аспектом каждого компонента является внешний вид его управляющего элемента. Для компонента, весь смысл которого состоит только в визуальном отображении чего-то (строки, в нашем случае), он приобретает еще более важное значение. В случае компонента, наследующего от TCustomControl, метод обработчик, вызываемый для отображения управляющего элемента, называется Paint. Метод Paint не требует параметров, так как вам приходится использовать свойство класса компонента Canvas для собственно рисования. Это также позволяет компоненту при необходимости отображать себя прямо на принтер.

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

Для начала надо определить, какой метод компонента вам надо заместить. Это можно сделать,

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

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

virtual void __fastcall Paint(void);

Обратите внимание на использование ключевого слова virtual. Только виртуальные методы могут быть замещены наследующим классом. К счастью, большинство обработчиков в классах CBuilder воплощены в виде виртуальных методов.

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

TAngleText:

void __fastcall TAngleText::Paint(void)

{

// Устанавливаем угол поворота текста

LOGFONT LogRec; GetObject(Font->Handle,sizeof(LogRec),&LogRec);

//Примечание: угол в десятках градусов

LogRec.lfEscapement = Angle * 10.0;

//Проверяем, задана ли позиция по умолчанию if (FXPos == -1 )

FXPos = Width / 2; if (FYPos == -1 ) FYPos = Height / 2;

Canvas->Font->Handle = CreateFontIndirest(&LogRec); Canvas->Brush->Color = Color;

Canvas->TextOut( FXPos, FYPos, Text );

}

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

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

Тестирование компонента

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

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

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

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

Для тестирования нашего компонента мы будем использовать форму, показанную на рис. 14.2. Как вы видите, форма состоит из рамки рисования (paintbox) и двух кнопок. Кнопку используются для увеличения (>) и уменьшения (<) угла в управляющем элементе AngleText, который мы собираемся расположить на форме.

Рис. 14.2. Форма для тестирования компонента AngleText

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

void __fastcall TForm1::FormCreate(TObject *Sender)

{

pAngleText = new TAngleText(this); pAngleText->Parent = this; pAngleText->Top = PaintBox1->Top; pAngleText->Left = PaintBox1->Left; pAngleText->Width = PaintBox1->Width; pAngleText->Height = PaintBox1->Height; pAngleText->Angle = 0; pAngleText->Font = Font; pAngleText->Color = Color; pAngleText->Text = "Проба пера";

}

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

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

повернуты.

После того, как все установлено, при запуске формы в поле рамки рисования должна появиться наша строка текста Проба пера»). Для того, чтобы иметь возможность изменять угол, добавьте два обработчика для кнопок увеличения и уменьшения угла. Обработчику кнопки увеличения угла (>) должен соответствовать следующий код:

void __fastcall TForm1::IncrementClick(TObject *Sender)

{

// Увеличение на 10 градусов pAngleText->Angle += 10.0;

}

Как вы можете видеть, поскольку свойство Angle расценивается как переменная-член класса, для ее изменения можно применять даже оператор +=. Остальная часть метода не представляет особого интереса в ней просто добавляется 10 градусов к текущему значению угла. Точно так же, с кнопкой уменьшения угла (<) должен быть связан метод DecrementClick, выглядящий следующим образом:

void __fastcall TForm1::DecrementClick(TObject *Sender)

{

// Уменьшение на 10 градусов pAngleText->Angle += 10.0;

}

Последним шагом написания теста будет добавление экземпляра класса TAngleText в заголовочный файл формы. Добавьте заголовочный файл для TAngleText в заголовочный файл формы, открыв последний (щелкнув правой кнопкой мыши и выбрав Open Source/Header File в появившемся всплывающем меню) и затем выбрав в основном меню пункт File|Include Unit Hdr. Выберите из списка модуль TAngleText, а затем добавьте следующую строку в раздел приватных объявлений заголовочного файла формы:

private: // User declarations

TAngleText *pAngleText;

Скомпилируйте и запустите приложение, и вы увидите компонент AngleText, отображенный в центре формы, примерно как показано на рис. 14.3.

Рис. 14.3. Компонент AngleText во время исполнения теста

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

Теперь можно начинать тестирование. Нажмите кнопку увеличения угла. Как видите... ничего не произошло. Почему? Здесь кроется наша первая ошибка. Пытаясь найти источник проблемы мы обнаружим, что свойство Angle нашего компонента действительно изменяется (это можно увидеть в отладчике), но управляющий элемент на меняет положения текста. Почему? Хороший способ что-то понять в данной ситуации это минимизировать окно формы, а потом вернуть его в нормальный размер. Текст внезапно повернется. Следовательно, проблема кроется в том, что компонент не перерисовывается должным образом. Собственно говоря, в данном случае проблема в том, что он вообще никак не перерисовывается.

Можно предложить два решения этой проблемы. Во-первых, мы можем вынудить пользователя перерисовывать компонент при нажатии кнопки. Это приведет к появлению всюду в коде пользователя следующих строк:

pAngleText->Angle += 10.0;

pAngleText->Repaint();

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

Для того, чтобы справиться с этой проблемой самостоятельно, нам надо знать, когда изменяется угол, и при его изменении перерисовывать компонент. Метод Write свойств компонента вызывается, когда пользователь пытается изменить это свойство. Мы можем изменить компонент так, чтобы он сам перерисовывал себя, когда свойство Angle компонента изменяется. Измените заголовочный файл компонента TAngleText следующим образом:

class TAngleText : public TCustomControl

{

private:

double FAngle; int FXPos;

int FYPos; protected:

virtual void __fastcall Paint(void);

virtual void __fastcall SetXPos(int XPos ); virtual void __fastcall SetYPos(int YPos ); virtual void __fastcall SetAngle(double Angle ); public

__fastcall TAngleText(TComponent* Owner); __published:

__property double Angle={read=FAngle, write=SetAngle}; __property int XPos={read=FXPos, write=SetXPos}; __property int YPos={read=FYPos, write=SetYPos}; __property Text;

__property Font; __property Color; };

А теперь добавьте код и в исходный файл компонента: void __fastcall TAngleText::SetAngle(double Angle)

{

if ( Angle != FAngle )

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