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



Создание модуля компонента



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

Чтобы начать работу над новым компонентом, надо активизировать процесс создания нового приложения (команда File | New | Application), в меню Component выбрать команду New Component и в поля диалогового окна New Component (рис. 6.1) ввести информацию о создаваемом компоненте.



Рис. 6.1. Начало работы над новым компонентом


В поле Ancestor type надо ввести базовый тип создаваемого компонента. Для разрабатываемого компонента базовым компонентом является стандартный компонент Edit (поле ввода-редактирования). Поэтому базовым типом разрабатываемого компонента является тип TEdit.

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

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

В результате щелчка на кнопке ОК будет сформирован модуль компонента, состоящий из двух файлов: файла заголовка (листинг 6.1) и файла реализации (листинг 6.2).

Листинг 6.1. Файл NkEdit.h

#ifndef NkEditH
#define NkEditH
#include <SysUtils.hpp>


#include <Classes.hpp>
#include <Controls.hpp>


#include <StdCtrls.hpp>
class PACKAGE TNkEdit : public TEdit {
private: protected: public:
__fastcall TNkEdit(TComponent* Owner);
__published:
};
#endif


Листинг 6.2. Файл NkEdit.cpp

#include <vcl.h>
#pragma hdrstop
#include "NkEdit.h"
 #pragma package(smart_init)
static inline void ValidCtrCheck(TNkEdit *) {
new TNkEdit(NOLL); }
__fastcall TNkEdit::TNkEdit(TComponent* Owner)
: TEdit(Owner) { }
namespace NkEdit {
void __fastcall PACKAGE Register()
{
TComponentClass classes[l] = {__classid(TNkEdit)};
RegisterComponents("Samples", classes, 0) ; } }

В файле заголовка NkEdit.h находится объявление нового класса. В файл реализации NkEdit.cpp помещена функция Register, которая обеспечивает регистрацию, установку значка компонента на указанную вкладку палитры компонентов.

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

В листингах 6.3 и 6.4 приведены файлы заголовка и реализации компонента NkEdit после внесения всех необходимых изменений.

Листинг 6.3. nkedit.h

#ifndef NkEditH
 #define NkEditH
#include <SysUtils.hpp>
#include <Classes.hpp>
#include <Controls.hpp>
 #include <StdCtrls.hpp>
class PACKAGE TNkEdit : public TEdit
{
private:
bool FEnableFloat; // разрешен ввод дробного числа
// диапазон
float FMin; // нижняя граница
float FMax; // верхняя граница
/* функция SetNumb используется для изменения содержимого
поля редактирования */
void __fastcall SetNumb(float n);
/* Функция GetNumb используется
для доступа к полю редактирования */
float __fastcall GetNumb(void);
/* эти функции обеспечивают изменение
границ диапазона допустимых значений */
bool __fastcall SetMin(float min);
bool __fastcall SetMax(float max) ;
protected:
public:
__fastcall TNkEdit(TComponent* Owner);
 // конструктор
/* Свойство Numb должно быть доступно только во время
работы программы. Поэтому оно объявлено в секции public.
Если надо, чтобы свойство было доступно
во время разработки формы и его значение
 можно было задать в окне Object Inspector,
то его объявление нужно поместить в секцию published
*/
__property float Numb = {read = GetNumb }; //, write = SetNumb};
// Функция обработки события KeyPress DYNAMIC 
void __fastcall KeyPress(char Skey);
published:
// объявленные здесь свойства доступны в Object Inspector
__property bool EnableFloat = { read = FEnableFloat,
write = FEnableFloat };
__property float Min = {read = FMin,
write = SetMin };
__property float Max = {read = FMax,
write = SetMax }; };
#endif

Листинг 6.4. nkedit.cpp 

#include <vcl.h>
#pragma hdrstop
#include "NkEdit.h"
#pragma package(smart_init)
static inline void ValidCtrCheck(TNkEdit *) {
new TNkEdit(NULL); }
// конструктор
__fastcall TNkEdit::TNkEdit(TComponent* Owner)
: TEdit(Owner) {
// конструктор имеет прямой доступ к полям компонента
Text = "0";
FMin = 0;
FMax = 100;
FEnableFloat = true; }
namespace Nkedit
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[l] = {__classid(TNkEdit)};
RegisterComponents("Samples", classes, 0); } }
void __fastcall TNkEdit::SetNumb(float n)
{
Text = FloatToStr(n);
}
// возвращает значение, соответствующее строке,
// которая находится в поле редактирования
float __fastcall TNkEdit::GetNumb(void)
if (Text.Length())
return StrToFloat(Text); else return 0;
}
// функция обработки события KeyPress в поле компонента NkEdit
void __fasteall TNkEdit::KeyPress(char &Key)
{
// Коды запрещенных клавиш заменим нулем, в результате чего
 // эти символы в поле редактирования не появятся switch (Key)
{ case '0' :
case '1'
case '2'
case '3'
case '4'
case '5'
case '6'
case '7'
case '8'
case '9' break;
case '.' case ', '
Key = DecimalSeparator;
if (Text.Pos(DecimalSeparator) || (! FEnableFloat))
Key = 0; break;
case '-' : // знак "минус"
if (Text.Length()|I(FMin >= 0))
// минус уже введен или FMin >= О Key = 0; break;
case VKJ3ACK: // клавиша <Backspace> break;
default : // остальные символы запрещены
Key = 0; }
if ((Key >='0') && (Key <= '9')) {
/* Проверим, не приведет ли ввод очередной
цифры к выходу числа за границы диапазона.
 Если да, то заменим введенное
число на максимальное или минимальное*/
AnsiString st = Text + Key;
if (StrToFloat(st) < FMin) {
Key = 0;
Text = FloatToStr(FMin); } if (StrToFloat(st) > FMax) {
Key = 0;
Text = FloatToStr(FMax); } }
// вызвать функцию обработки события KeyPress базового класса
TEdit::KeyPress(Key);
}
// устанавливает значение поля FMin
bool __fastcall TNkEdit::SetMin(float min)
{
if (min > FMax) return false;
FMin = min; return true;
}
// устанавливает значение поля FMin
bool __fastcall TNkEdit::SetMax(float max)
{
if ( max < FMin) return false;
FMax = max; return true;
}

В объявлении класса TNkEdit добавлены объявления полей FEnabiedFloat, FMin и FMax. Имена полей, согласно принятому в C++ Builder соглашению, 'начинаются с буквы F (от Field, поле). Поле FEnabledFioat хранит признак возможности ввода в поле редактирования дробного числа. Поля FMin и FMax хранят границы диапазона. Доступ к полям обеспечивают соответствующие свойства: EnabiedFloat, Min и мах. Так как объявления этих свойств находятся в секции published, то они будут доступны в окне Object Inspector. Свойство Numb, представляющее собой число, которое находится в поле редактирования, объявлено в секции public, поэтому оно доступно только во время работы программы. Здесь следует обратить внимание на то, что у свойства Numb нет соответствующего поля. Значение этого свойства вычисляется во время работы программы путем преобразования в число значения свойства Text базового компонента. Свойства Min и мах получают доступ к полям данных для чтения напрямую, для записи — посредством функций SetMin и SetMax. Свойство EnabдedFдoat получает доступ к полю FEnabledFloat для чтения и записи напрямую. Так как компонент NkEdit должен обеспечить фильтрацию символов (в поле редактирования должны отображаться только цифры и, в случае, если значение свойства EnabiedFloat равно true, десятичный разделитель), то в объявление класса добавлено объявление функции KeyPress, которая предназначена для обработки соответствующего события.

Реакцию компонента NkEdit на нажатие клавиши клавиатуры определяет функция TNkEdit::KeyPress. В качестве параметра эта функция получает код нажатой клавиши. Перед вызовом функции TEdit: :KeyPress, которая обеспечивает обработку события Keypress базовым компонентом, код нажатой клавиши проверяется на допустимость. Если нажата недопустимая клавиша, то код символа заменяется на ноль. Допустимыми для компонента NkEdit, в зависимости от его настройки, являются цифровые клавиши, разделитель целой и дробной частей числа (в зависимости от настройки Windows, точка или запятая), "минус" и клавиша <Backspase>.

Здесь следует вспомнить, что в тексте программы дробная часть числовой константы отделяется от целой части точкой. Во время работы программы при вводе исходных данных пользователь должен использовать тот символ, который задан в настройке Windows. В качестве разделителя обычно используют запятую (стандартная для России настройка) или точку. Приведенная процедура обработки события onKeypress учитывает, что настройка Windows может меняться, и поэтому введенный пользователем символ сравнивается не с константой, а со значением глобальной переменной Decimalseparator, которая содержит символ-разделитель, используемый в Windows в данный момент.


Книжный магазин