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

         

Разбор кода


Идея работы компонента проста и уже знакома вам по последнему примеру предыдущей главы. Имеется битовая матрица (TBitmap), которая служит для буферизации вывода на экран строки текста. При перерисовывании ее на канву компонента выходящие за его пределы части битовой матрицы автоматически отсекаются. При каждой перерисовке позиция битовой матрицы сдвигается влево на пиксел. Когда строка совсем уйдет с экрана, восстанавливается ее исходная позиция — за правым краем компонента.

Конструктор и деструктор

Конструктор создает операцией new битовую матрицу и устанавливает значения некоторых полей и свойств (Width — унаследованное и уже опубликованное свойство). После этого он вызывает функцию Setup ().

Обратите внимание на строку со свойством ControlStyie. Оно относится к классу Set, который моделирует встроенный тип множеств языка Pascal. Перегруженная операция “ вводит элемент в множество. Стиль компонента определяет, в частности, как будет выполняться его перерисовка. Если не установить csOpaque, весь компонент перед перерисовкой, т. е. вызовом функции Paint (), о которой речь пойдет ниже, будет очищаться и текст строки будет заметно мерцать.

Деструктор удаляет выделенную в конструкторе битовую матрицу.

Метод Setup()

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

Метод копирует свойство компонента Font в соответствующее свойство канвы битовой матрицы, определяет ширину и высоту образа текстовой строки и устанавливает по ним размеры матрицы. Устанавливается также цвет фона, и строка выводится на битовую матрицу методом ее канвы TextOut () . Образ строки готов. Справа от текста в битовой матрице имеется по крайней мере одна колонка пикселов, закрашенных фоновым цветом. Благодаря этому обеспечивается очистка пространства компонента, “появляющегося” из-под конца строки при движении ее влево.

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




Методы DoDrawTextQ и PaintQ





DoDrawText () производит вывод битовой матрицы на канву компонента, вызывая ее метод Draw () . Попутно он проверяет, не была ли измена ширина компонента и, если это так, вызывает Setup () и очищает компонент, вызывая FillRect (). Методу передается прямоугольник, задающих координаты экранной области компонента (области клиента). Setup(), конечно, производит в данном случае массу лишних операций, но ради простоты логики можно поступиться его изяществом и эффективностью, которая в данном случае не важна. Изменение ширины — единичное редкое действие.



Кстати об эффективности. Вывод образа текста на экран с буферизацией в битовой матрице был выбран потому, что копирование матрицы должно происходить очень быстро, по идее, быстрее, чем непосредственный вывод текста методом Text0ut(). Однако я этого не проверял. Если читатель захочет поэкспериментировать, он может сравнить эффективность методов Draw (), TextOut () и Text?ect (). Это полезное упражнение.

DoDrawText () вызывается из метода Paint (). Виртуальный метод Paint () вызывается, в свою очередь, по сообщениям Windows WM PAINT, a также в результате вызова Refresh () , Repaint (), Update () или Invalidate (). Наш компонент никогда не перерисовывает себя, непосредственно вызывая Paint () . Перед вызовом Paint () производится инициализация канвы компонента и ей выделяется контекст устройства Windows. Без этого наша функция DoDrawText () работать не будет.



Set-функции



Функции SetStartedf) и SetTickRate () устанавливают значения соответствующих свойств. Свойство Started управляет статусом строки — бежит она или стоит на месте. Если его значение меняется с false на true, инициализируется поле маркера времени, свойства NextTick.

Свойство TickRate задает интервал срабатывания “таймера” строки. Set-функция проверяет, не присваивается ли свойству отрицательное число или ноль. Проверка допустимости присваиваемых данных является еще одним важным аспектом механизма свойств.



Метод Tick()



Это единственный, не считая конструктора и деструктора, открытый метод компонента. Именно он обеспечивает “бег” строки по экрану. Если строка остановлена или время нарисовать ее в следующей позиции еще не подошло, метод немедленно возвращает управление. Если же строка запущена и текущий счетчик миллисекунд сравнялся или перешел за маркер времени NextTick, вызывается Repaint () , маркер времени сдвигается на интервал TickRate и определяется следующая позиция строки.



Если строка вышла за пределы компонента, восстанавливается ее начальная позиция и вызывается функция PassComplete () .



Функция PassCompleteQ



Наш компонент может генерировать событие OnPassComplete. Инициирует событие функция PassComplete (). При вызове этой функции из метода Tick() она проверяет, присвоено ли значение (указатель-замыкание) свойству OnPassComplete. Если присвоено, то через свойство вызывается установленная пользователем процедура обработки события со вторым аргументом — переменной stop, в которой пользовательский обработчик может передать true, чтобы остановить строку. Другими словами, если строка ушла с экрана, обработчик события может немедленно запретить возобновление цикла, модифицировав свой параметр-ссылку.



Обработка сообщений



Наш компонент может обрабатывать сообщения cm_fontchanged и CM_TEXTCHANGED, передаваемых ему при изменении соответственно свойств Font и Caption. Это внутренние сообщения приложения С++Вuider, не связанные с сообщениями Windows.

Для обработки обоих этих сообщений мы предусмотрели единственную функцию CMChange() Она вызывает Setup () для обработки изменившихся свойств и затем Repaint () , немедленно перерисовывающую компонент.

Чтобы привязать данные конкретные сообщения к данной процедуре обработки, в классе должен быть реализован виртуальный метод Dis?ат:сЬ (), распределяющий сообщения по назначенным для них обработчикам. В конце определения класса в файле CTickTape.h вы видите четыре макроса “таблицы сообщений”. Они генерируют метод Dispatch () примерно такого вида:

void _fastcali CTickTape::Dispatch(void* Message)

{

switch (((TMessage*)Message)->Msg) { case CM_TEXTCHANGED:

case CM_FOMTCHANGED:

CMChanged(*(TMessage*)Message) ;

breaks; default :

TGraphicControl::Dispatch(Message) ;

} }

Я его несколько “оптимизировал”, поскольку для обоих событий вызывается, одна и та же функция и нет смысла дублировать код для двух меток case. Оператор switch сравнивает идентификатор сообщения Msg с пунктами “таблицы” и вызывает в случае совпадения CMChanged. Если сообщение не опознано, вгдзывается Dispatch () базового класса.


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