|
C++ Builder
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Downloads Web-design |
|
ИСПОЛЬЗОВАНИЕ
И СОЗДАНИЕ
ВИЗУАЛЬНЫХ
КОМПОНЕНТ Эта
глава
посвящена
основе
построения
приложений
в 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,
добавляя
лишь
несколько строк
к
.обработчикам
ключевых
событии компонент.
Используйте
объекты
всегда, когда
это
возможно;
твердо
сопротивляйтесь
позыву
написать
новый код то
тех пор, пока
все другие
возможности
не будут
исчерпаны. Вам
потребуется
оперативное
владение устройством
Библиотеки
Визуальных
Компонент.
Глубина
необходимых
программистам
знаний о
составе и
функциональных
характеристиках
Библиотеки
определяется
тем, как вы
собираетесь
ее
использовать.
С помощью
команды
главного
меню Help | VCL Reference вы
можете
получать
сведения из
справочной
службы в
процессе
работы с
Библиотекой. 6.1.1 VCL
для
прикладных
программистов Программист
создает
законченное
приложение
посредством
интерактивного
взаимодействия
с
интегрированной
визуальной
средой C++Builder,
используя
компоненты VCL для
создания
интерфейса
программы с
пользователем
и с другими
управляющими
элементами:
обслуживания
баз данных,
контролируемого
ввода
параметров
и т.д.
Характерная
для C++Builder
методика
визуального
стиля
разработки
программного
обеспечения
не применяется
множеством
других
систем
программирования. Программисты
должны
знать
свойства,
методы и
события,
присущие
используемым
компонентам.
Более того,
понимание
архитектуры
VCL позволяет
совершенствовать
вашу программу
в тех местах,
где
ощущается
необходимость
развития
существующих
или создания
новых
компонент.
Прежде, чем
изобретать
новый
элемент,
удостоверьтесь,
как принято, не
создал ли
уже кто-то
компоненту
с нужными вам
характеристиками. 6.1.2 VCL
для
системных
программистов Системные
программисты
развивают
существующую
Библиотеку
либо
добавляя в
нее новые
элементы,
либо
расширяя
функциональность
уже
имеющихся
компонент.
Разработчики
компонент
должны
иметь более
глубокие
знания о
внутреннем
устройстве VCL,
нежели
прикладные
программисты.
Нужно четко представлять
себе, какой
прием
быстрее приведет
к
поставленной
цели:
развитие
имеющейся
или
написание
новой
компоненты.
Написание
компонент
представляет
собой более
традиционную
задачу
программирования
и сопряжено
с большими
условностями,
нежели
визуальное
создание
приложений. Варианты
C++Builder Professional и C++Builder Client/Server Suite
поставляются
вместе с
исходными
текстами VCL.
Наличие
исходных текстов
облегчает
задачу
программистов,
которые
занимаются
разработкой
новых
компонент и
расширением
функциональных
возможностей
уже имеющихся
компонент
Библиотеки. Для
создания
новых
компонент
можно с одинаковым
успехом
пользоваться
средствами C++Builder
или Delphi, однако
если
разработанные
компоненты
предлагаются
для
внешнего
применения,
автор
обязан удостовериться,
что они
работают в
рамках обеих
систем. 6.1.3
Компоненты VCL Компоненты
это
строительные
кирпичи, из которых
конструируется
интерфейс
программы с
пользователем,
с помощью
которых
"здание"
программы
приобретает
новый
внешний
облик и
скрытые особенности.
Для
прикладного
программиста
любая
компонента VCL
представляет
собой объект,
который
можно
"перетащить"
из вкладок
Палитры
компонент
(Рис. 6.1) на
форму
создаваемого
приложения.
Поместив
компоненту
на форму,
можно
манипулировать
ее
свойствами (посредством
Редактора
форм) и кодом
(с помощью
Редактора
кода),
придавая
компоненте
специфическое
поведение. Для
разработчика
компоненты
представляют
собой объекты
на 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
показывает
родительскую
иерархию
некоторой
формы. Многие
свойства
видимых
компонент
(например. 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++
устанавливаются
следующие
обобщенные
группы
типов
компонентных
свойств:
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 еще
и следующие
стандартные
события:
Чтобы
стандартные
события
вашей
компоненты
были видимы
Инспектору
объектов на
стадии
проектирования
или во время
выполнения
программы,
вы должны
переопределить
свойства
событии в
секции 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,
которые вы
использовали
бы в обычной
программе
на языке С:
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
предназначены
для
изменения
фокуса,
обслуживания
событий
клавиатуры
и
отображения
потомков
компоненты:
Методы
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) или от
существующего
компонентного
класса.
Компонеитой
может стать
практически
любой
элемент
вашей программы,
поведением
которого вы
хотите управлять
на стадии
проектирования.
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
будут
способствовать
успешному решению
поставленных
задач |
|
Новости |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Design by: