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

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

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

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

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

Что мы узнали в этой главе?

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

·Потоки реализуются выбором команды New Thread Object в пункте меню CBuilder FileдNew.

·Потоки выполняются, пока их не остановят командой Terminate или не приостановят методом Suspend. Приостановленные потоки потом можно запускать вновь вызовом метода Resume.

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

·Если вы хотите работать с объектом VCL, находящимся на форме, не принадлежащей потоку, то вам нужно использовать метод потока Synchronize для вызова метода, работающего с объектом

VCL.

·Чтобы быть уверенным, что поток не запустится до того, как завершится выполнение конструктора, вызывайте конструктор потока с параметром флагом suspend, равным true,

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

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

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

Глава 14. Создание новых компонентов

Процесс разработки компонентов

Проектирование компонента

Свойства, методы и события

Мастер компонентов

Ручное тестирование компонентов

Инсталляция

Компоненты одна из наиболее восхитительных частей среды CBuilder. Они позволяют создавать приложения методом drag-and-drop, на ходу менять свойства, в общем, осуществлять по- настоящему объектно-ориентированную разработку. Компоненты лежат в основе системы CBuilder, они придают гибкость самой среде разработки. Без компонентов не было бы и CBuilder, и мир был бы гораздо более грустным местом. В этой главе мы рассмотрим создание собственных компонентов от проектирования до отладки. Мы рассмотрим некоторые аспекты инсталляции,

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

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

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

Второй режим компонентов период исполнения. Во время исполнения компонент функционирует в работающем приложении. Они должны правильно отображать (отрисовывать) себя, обрабатывать вызовы методов и эффективно взаимодействовать с другими компонентами. Несмотря на то, что все компоненты являются видимыми во время проектирования (иначе как бы вы могли их отобрать?), они не обязательно должны быть видимы во время исполнения. Компоненты баз данных, такие, как TTable, TQuery и TDataSet не видны во время исполнения, но, тем не менее, выполняют весьма важные задачи.

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

Процесс разработки компонентов

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

варьироваться в зависимости от универсальности разрабатываемого компонента и степени важности защиты системы от сбоя компонента. Ниже приведен общий план этого процесса; чуть позже мы подробно остановимся на каждом пункте:

Определите проблему, которую пытаетесь разрешить.

Найдите частное решение этой проблемы.

Сделайте решение более глобальным.

Спроектируйте компонент для осуществления глобального решения.

Сделайте компонент как можно более гибким.

Воплотите идею компонента в жизнь.

Отладьте компонент.

Протестируйте компонент.

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

программиста, который будет использовать этот компонент).

Проделайте работу по представлению компонента (файлы помощи, иконки, определение

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

палитр и т. п.).

Проинсталлируйте компонент.

Используя накопленные знания, вернитесь к первому шагу.

Как вы видите, разработка компонентов это непрекращающиеся поиски решения и формулировки проблемы. На самом деле шансы за то, что в день окончания работы над компонентом вы возьметесь переписать все заново, достаточно велики, так что в последнем пункте плана гораздо меньше юмора, чем кажется на первый взгляд. В своей исторической книге по разработке программных продуктов «The Mythical Man-Month» Фрэд Брукс призывает писать первую версию программы изначально как черновик, поскольку все равно придется переписывать. Подобный подход вполне подходит для разработки компонентов. Простые на первый взгляд шаги проектирования, разработки и отладки, а затем и использования компонента могут завести вас очень далеко в сторону по сравнению с вашей изначальной идеей. Если вы решили, едва закончив, переписать компонент заново (используя, естественно, многое из первой попытки, что существенно облегчит задачу), то, скорее всего, во второй раз результат понравится вам куда больше. Компоненты и приложения, не переписанные после самой первой версии заново, обычно в результате доделываются так ужасно, что даже сам их разработчик не может опознать свое детище. Уж поверьте мне. Я сам пробовал столько раз, что теперь даже не думаю, что у меня что- нибудь получится с первого раза.

Процесс разработки компонентов в деталях

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

Определение проблемы, которую вы хотите разрешить

Трудно сосчитать, сколько раз я сталкивался с кодом, содержащим ошибки. Ошибки варьируются от абсолютно идиотских (типа деления на 0) до прямо-таки грандиозных, связанных с тонкостями внутреннего устройства операционной системы Windows (а иногда даже и MS-DOS). И все же большинство ошибок возникает из-за того, что программист не до конца понимает, чего же он хочет добиться.

Написание компонентов не только сродни написанию любого другого кода, но и имеет дополнительные особенности. Если вы сделаете ошибку в описании метода одного из созданных вами классов C++ в своем приложении, возникнут серьезные проблемы, но они будут ограничены приложением, в котором появились. Если вы в какой-то момент обнаружили, что вам требуется дополнительные, или просто другие, параметры для метода, вопрос только в изменении описания метода и последующем изменении приложения. Однако если ваш класс является частью библиотеки, то выяснится, что изменение отразится на нескольких приложениях, использующихся в вашей компании. Теперь, если обратиться компоненту, то станет ясно, что одно мельчайшее изменение может затронуть сотни приложений, разработанных десятками компаний (если предположить, что вы кому-то продали свой компонент). Из-за таких вот маленьких исправлений мы и сходим с ума.

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

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

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

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

Определите частное решение проблемы

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

Зачастую воплощение в жизнь частного решения проблемы это все, что вам понадобится. Вы можете никогда не перейти к следующему шагу (обобщению), но вы, по крайней мере, рассмотрите проблему и представите письменное заключение по ней. После того, как вы нашли частное решение проблемы, можете вынести его на обсуждение коллег. Может статься, вы разрешили проблему, а может быть, ваше решение не работает, принимая во внимания все обстоятельства. Например, вашим решением могла стать проверка слова под курсором и перескакивание в другой файл справки, содержащий это слово. Ваши коллеги могли бы указать вам на то, что перескакивание со слова «тег» из документа по программированию страниц HTML в документ об основах программирования это вряд ли то, чего хотел бы пользователь.

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

Выработка обобщенного решения

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

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

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

Фрэд Джонс столкнулся с проблемой при написании приложения на CBuilder. Ему требуется

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

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

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

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

Что же не правильно? Фрэд решал частную задачу по написанию компонента для фильтрования данных для конкретного поля. Но, к сожалению, Фрэд не осуществил следующего шага обобщения решения. Если бы он рассмотрел проблему чуть более широко, он бы понял, что гораздо проще было бы разрешить пользователю самому задавать фильтр для поля множество допустимых символов. Вы можете удивиться, почему Фрэд не использовал компонент Masked Edit, поставляющийся с CBuilder. Дело в том, что этот компонент не предоставляет той гибкости, которая нужна Фрэду. Маска задается жестко один раз, так что если бы я захотел ввести 1.234, или 123.4, или 12.45, я бы не смог написать маску, которая позволила бы это. Компонент поле редактирования с фильтром, воспринимающий значения 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, сможет сделать все, что надо. Как только будут появляться новые требования, Фрэду надо будет изменить значение фильтра, чтобы добавить новый компонент на новую форму.

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

Проектирование компонента для воплощения обобщенного решения

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

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

воплощения, собственно написание компонента станет достаточно простой вещью.

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

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

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

Сделайте проект компонента наиболее гибким

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

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

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

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

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

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

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

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

Отладка компонента

После того, как разработка компонента закончена, начинается его отладка. В этой части мы посмотрим, как изначально отладить компонент, и как работать с ним после инсталляции.

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

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

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

Как я только что сказал, отладка и тестирование это разные вещи. Так что же такое тестирование? Это проверка не только того, что компонент делает вмененные ему в обязанность вещи, но и того, что он не делаем ничего такого, что делать в принципе не должен. Отладка это проверка того, что правильно введенные значения повлекут за собой правильный результат, а тестирование это зачастую проверка того, что неправильно введенные значения так же приведут к правильному результату (или правильной работе).

Когда вы создаете компонент, вы должны очень широко его протестировать. Это означает гораздо большее, чем проверка того, что введенные значения вызывают правильную реакцию. То есть если я постулирую, что некоторое поле должно лежать в пределах от 1 до 10, то ввод 11, 0 или - 32768 не должен вызывать проблем. И если одно свойство зависит от другого, то компонент не должен обрушиться, если второе поле не задано. Это означает проверку граничных условий для свойств и методов.

Граничные условия это экстремальные ограничения на вводимые значения. Если число должно быть целым и положительным, то для него граничными значениями будут 0, -1, 32767 и -32768. Вам также надо выбрать одно из лежащих между ними допустимых значений, например 1234, и проверить, все ли работает как должно. Если у вас используется какой-нибудь сложный алгоритм, в котором возникают проблемы со значениями внутри допустимого диапазона, то тестирование приведенных выше пяти значений будет более полезным, чем просиживание по 12 часов за клавиатурой и тестирование все подряд значений, какие только придут в голову.

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

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

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

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

Описание интерфейса компонента

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

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

Не перегружайте пользователя документацией. Делайте вашу документацию простой и сжатой, но в то же время понятной. Например, если вы разрабатываете компонент для работы с датами, то можете запостулировать, что все поймут, что представляет свойство Month (месяц), не так ли? А вот и нет. В том, лежат ли значения, обозначающие месяцы, в пределах от 1 до 12 или же от 0 до 11, есть огромная разница. Ваша документация обязана донести эту информацию до пользователей, тем более, что это может выглядеть очень просто, например:

Month: Номер месяца в дате; значения целые, от 0 до 11.

Эта строка сообщит мне все, что я хочу знать. Составляющее Day (день) вообще не является таким уж очевидным. Не понятно это день недели или день месяца? Присваивание свойствам более определенных имен существенно облегчит жизнь. Назовите свойство DayOfMonth (день месяца), и никто уже не подумает, что это день недели. Правда, вопрос о том, отсчитываются ли значения этого свойства от 0 или от 1, все еще останется открытым. Будьте последовательны, и люди вас поймут. Лучшим комплиментом для создателя компонентов может служить тот факт, что программист не смотрит в документацию потому, что все компоненты работают по одному принципу.

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

Разнообразная мелкая работа

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

Инсталляция компонента

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

Хотя инсталляцией компонента занимается среда разработки (IDE), для вас тоже есть чем заняться. Как мы увидим в этой главе, в CBuilder есть два варианта тестирования компонента. В основном вы будете тестировать компонент в его изначальном виде до инсталляции (это займет гораздо меньше времени). В этой главе я покажу, как тестировать компонент до инсталляции.

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

Совет

Может показаться, что нет способов сынсталлировать компонент, не имея исходного кода или объектного файла для него. Это не совсем так. Неправда и то, что можно сынсталлировать в VCL CBuilder только один компонент за раз. Если вы выйдете из IDE и создадите библиотечный файл (library file) для своих компонентов, то сможете добавить сразу несколько компонентов, либо компонент, состоящий из нескольких файлов. Правда, этот метод потребует дополнительных усилий. Вам придется добавить в свой компонент новый модуль с именем, совпадающим с именем библиотечного файла, содержащий функции Register для всех компонентов библиотеки. Для того, чтобы понять, как это должно выглядеть, обратите внимание на библиотеку comps.lib, находящуюся в директории прилагаемого компакт-диска, относящейся к данной главе. Вы найдете там модуль comps.cpp, содержащий функцию Register для этой библиотеки, заключенную в отдельную именованную область (namespace).

С новыми силами все с начала!

По-настоящему хорошие компоненты никогда не бывают дописаны до конца в будущем вы будете обновлять их, подправлять, добавлять в них новые возможности; так что, закончив создание компонента, оглянитесь на проделанную работу и постарайтесь оценить, что же при этом изучили. Сплошь и рядом оказывается, что процесс создания компонента открыл вам глаза на то, как надо проектировать и создавать компонент на самом деле. Помните, — разработать один пробный «на выброс» — все равно так и получится?

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

Компонент AngleText (повернутый текст)

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

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

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

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

должен делать и как. То есть сформулировать проблему. Так зачем же мы создаем компонент? В случае компонента AngleText проблема, которую мы попытаемся разрешить, состоит в отображении вертикальной строки текста для подписи под осью ординат (Y). Для разрешения этой проблемы мы должны повернуть строку на 90 градусов от горизонтали. Это и будет частным решением.

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

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

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

Выбор свойств

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

Когда вы создаете компонент, вы наследуете его от базового класса VCL. Этот выбор базового класса влияет на свойства, доступные вам при написании компонента. Все компоненты должны по крайней мере наследовать от TComponent, базового класса всех компонентов в VCL, который не предоставляет почти что никаких возможностей. В качестве альтернативы вы можете выбрать базовый класс компонента, который будет делать большую часть работы за вас. От выбора класса зависит, какую часть работы будете делать вы и какая часть будет сделана за вас. Как правило, вы будете выбирать класс самого высокого уровня, который удовлетворяет критериям вашего компонента. То есть вы не будете наследовать от класса комбинированного списка, если хотите написать новую кнопку. Вы, скорее всего, выберите класс TButton.

Итак, все, о чем мы говорили, сводится к следующему для того, чтобы определить свойства для класса, надо сначала выбрать базовый класс компонента. Но для того, чтобы выбрать базовый класс компонента, надо сначала понять, какими же собственно свойствами должен обладать наш компонент. Похоже на замкнутый круг, не правда ли? Не волнуйтесь все не так плохо, как кажется. Выбрать класс, от которого наш компонент будет наследовать, куда проще, чем кажется на первый взгляд. Если вы хотите создать визуальный компонент, который должен будет сам себя отрисовывать, вам надо наследовать от одного из классов TCustomxxx. Если вы работаете над компонентом, который представляет из себя кнопку, но с некоторыми изменениями (например, кнопку, у которой событие нажатия повторяется, если кнопка мыши остается нажатой на этой кнопке в течение определенного промежутка времени то есть как на клавиатуре), вам стоит

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