Главная » C++, C++ Builder » Реализация карт сообщений C++ Builder

0

На рис. 4.9 представлена форма, которая покажет мощь системы карт сообщений в CBuilder. Для создания этой формы добавьте панель состояния в верхнюю часть формы, установив свойство Alignment (выравнивание) панели состояния в alTop. Это заставит  панель  состояния  «отъесть» часть пространства формы и урежет клиентскую область формы. Это необходимо, так как если мы разместим панель состояния внизу, то при  вертикальной прокрутке формы (чем мы собираемся заниматься) панель состояния будет находится на дне виртуальной формы, то  есть  довольно далеко. Сейчас панель состояния будет видна всегда, и ее можно использовать для отображения информации о текущем состоянии формы.

Рис. 4.9. Форма примера карт сообщений

Позаботившись о панели состояния, следующим шагом нам надо установить полосы прокрутки у формы, чтобы мы могли получать от них данные. Чтобы заставить форму отображать полосы прокрутки, выберите форму в Object Inspector. Найдите свойство VertScrollBar  (вертикальная полоса прокрутки) и щелкните дважды в левой части таблицы Object Inspector. Это раскроет свойство для показа подсвойств.  Поменяйте подсвойство Range (диапазон)  на 1000; этого достаточно, чтобы полоса прокрутки появилась.

Перейдите к свойству HorzScrollBar (горизонтальная  полоса прокрутки) и повторите операцию. Когда вы закончите, у формы появятся обе полосы прокрутки — вертикальная и горизонтальная. Теперь перейдите к панели состояния и щелкните справа от свойства Panels (секции). Мы собираемся добавить две небольших секции для отображения виртуальных позиций строки и столбца в форме. Добавьте три секции в панель состояния. Оставьте пустым текст в секциях.

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

Общий синтаксис карты сообщений таков: BEGIN_MESSAGE_MAP

MESSAGE_HANDLER(message,  function) END_MESSAGE_MAP(object)

где message — сообщение Windows, которое вы хотите обработать. Обычно сообщения Windows выглядят примерно так: WM_xxx; function — функция на уровне объекта, которую вы хотите использовать для обработки сообщения. Функции, обрабатывающие сообщения,  обычно  имеют один параметр — ссылку на объект типа TMessage; object — класс, для которого вы определяете эту карту сообщений (TForm, TListBox, …).

Мы хотели бы добавить два обработчика сообщений вертикальной и горизонтальной прокрутки формы. Модифицируйте заголовочный файл (Unit1.h)  для формы следующим  образом. Сначала сделайте изменения (выделены подсветкой), а потом мы обсудим, что эти изменения делают:

//———————————————————-

#ifndef Unit1H

#define Unit1H

//———————————————————-

#include <vcl\Classes.hpp>

#include <vcl\Controls.hpp>

#include <vcl\StdCtrls.hpp>

#include <vcl\Forms.hpp>

#include <vcl\ComCtrls.hpp>

//———————————————————-

class TForm1 : public TForm

{

__published:  // IDE-managed Components TStatusBar *StatusBar1;

void __fastcall HandlePaint(TObject *Sender); private: // User declarations

void __fastcall HandleVScroll(TMessage& Msg); void __fastcall HandleHScroll(TMessage& Msg); int FnStartLine;

int FnStartCol;

public:   // User declarations

__fastcall TForm1(TComponent* Owner); BEGIN_MESSAGE_MAP MESSAGE_HANDLER(WM_VSCROLL,HandleVScroll) MESSAGE_HANDLER(WM_HSCROLL,HandleHScroll)

// Можете добавить сюда

// любое количество дополнительных обработчиков

END_MESSAGE_MAP(TForm)

};

//———————————————————–

extern TForm1 *Form1;

//———————————————————–

#endif

Первая часть исправлений объявляет два метода (HandleVScroll и  HandleHScroll),  которые  мы будем использовать как обработчики сообщений в этой форме. Оба метода принимают по одному параметру — ссылке на объект типа TMessage, который содержит входную информацию о сообщении. Заметьте, что так как это обработчики сообщений и поэтому  перекрывают обработчики в низлежащей VCL, то нужно использовать для этих методом модификатор __fastcall.

Переменные FnStartLine и FnStartCol (члены класса TForm1) будут использованы для хранения того, насколько далеко мы прокрутили форму соответственно в вертикальном и горизонтальном направлении. Также эти переменные будут использоваться для отображения информации в панели состояния и для определения того, что будет прорисовано на форме.

Прорисовка формы

Обычно вы обрабатываете прокрутку формы, потому что вы хотите управлять  прорисовкой текста, графики или других данных на форме. Для этого мы переопределим прорисовку формы, добавив обработчик события OnPaint. В Object Inspector добавьте обработчик события OnPaint и дайте ему имя HandlePaint. Перейдите в редактор и добавьте в обработчик события HandlePaint следующий код:

void __fastcall TForm1::HandlePaint(TObject *Sender)

{

int x = 0; int y = 0;

for ( int i=FnStartLine; i<100; ++i)

{

String s = "Это строка " + String(i);  int nHeight = Canvas->TextHeight( s ); Canvas->TextOut( x, y, s);

y += Height;

}

}

Как видите, мы просто отображаем строки текста на рабочем пространстве формы. Строки текста отображают номер строки, начиная с текущей стартовой строки и увеличиваясь до 100 отображенных строк. Каждая строка текста будет изображена на отдельной строке формы, так как мы увеличиваем вертикальную (y) координату на высоту предыдущей строки.

Добавляем обработчик вертикальной прокрутки

Обработка вертикальной прокрутки — не слишком сложная работа, если вы понимаете, как выглядят сообщения, которые вы получаете. Обычно если вы хотите обработать сообщения в виде карты сообщений, то вам нужно что-нибудь знать о том, как выглядят сообщения в Windows API. Например, для сообщения прокрутки секция WParam объекта TMessage будет содержать код, показывающий, что сделал пользователь. Это код может показывать или одинарное перемещение в полосе прокрутки(вверх или вниз), или перемещение на страницу (вверх или вниз), или перетаскивание указателя на полосе прокрутки. Мы не собираемся возиться с перетаскиванием указателя в этом примере, так как это не очень важно, пока у вас не так уж и много текста для обработки. Мы займемся прокруткой вверх и вниз на одну строку или страницу, так как мы всего лишь отображаем случайные строки текста на форме. Вот полный код для  обработчика вертикальной прокрутки:

void __fastcall TForm1:HandleVScroll(TMessage& Msg)

{

int nStartPos = FnStartLine;

switch( Msg.WParam )

{

case SB_LINEUP: if ( FnStartLine ) FnStartLine–; break;

case SB_LINEDOWN:

FnStartLine++; break;

case SB_PAGEDOWN: FnStartLine += 10; break;

case SB_PAGEUP:

if ( FnStartLine < 10 ) FnStartLine = 0;

else

FnStartLine —= 10; break;

}

// Если позиция изменилась, перерисовывать! if ( FnStartLine != nStartPos)

Invalidate();

StatusBar1->Panels->Items[0]->Text  =

"Ряд: " + String(FnStartLine); StatusBar1->Panels->Items[1]->Text  =

"Кол: " + String(FnStartCol);

}

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

Обработка горизонтальной прокрутки

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

void __fastcall TForm1:HandleHScroll(TMessage& Msg)

{

int nStartPos = FnStartCol;

switch( Msg.WParam )

{

case SB_LINEUP: if ( FnStartCol ) FnStartCol–; break;

case SB_LINEDOWN: FnStartCol++;

break;

case SB_PAGEDOWN: FnStartCol += 10; break;

case SB_PAGEUP:

if ( FnStartCol < 10 ) FnStartCol = 0;

else

FnStartCol —= 10;

break;

}

StatusBar1->Panels->Items[0]->Text  =

"Ряд: " + String(FnStartLine); StatusBar1->Panels->Items[1]->Text  =

"Кол: " + String(FnStartCol);

}

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

__fastcall TForm1::TForm1(TComponent *Owner)

: TForm(Owner)

{

FnStartLine = 0;

FnStartCol  = 0;

}

Вот и все относительно этого примера карт сообщений. Как видите, обработка карт сообщений не особо сложна. Вы просто добавляете элементы в карту, точно так же, как вы бы это делали в Visual C++ или Borland C++. В CBuilder нет встроенной поддержки автоматического добавления элементов в карту сообщений, в основном потому, что добавление элемента в карту сообщений должно быть последним прибежищем отчаявшихся, а не первым шагом,  как это происходит в каркасных системах.

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

Создание списка, прорисовываемого его владельцем

Хотя VCL — довольно мощная система, существует ряд приложений, которым нужен доступ к таким вещам, которые не реализованы в VCL напрямую. Одна из таких дополнительных вещей — возможность использовать список Windows с небольшими изменениями. Некоторые приложения хотят изменить цвет каждого элемента в списке, другим нужно изменять шрифт, используемый при отображении элементов списка, а некоторым даже нужно рисовать что-то типа изображения или картинки вместе с текстом в списке, чтобы дать краткое описание данных, хранящихся в этом элементе списка. Система VCL делает написание таких вещей  удивительно  простым,  учитывая, что  вы что-нибудь знаете о  сообщениях Windows и  нужных вызовах API.  В  этом примере  мы покажем вам, как настроить список для отображения элементов в таком виде, который вам нужен, включая изменение шрифта, цвета, отображение картинки вместе с каждым элементом в списке. Есть на самом деле два пути, которыми вы можете реализовать те виды изменений, о которых мы здесь говорим. Во-первых, вы можете обрабатывать прорисовку списка в форме, на которой он расположен.  Этот  тип  списка  обычно  зависит  от  формы.  Второй  тип  списка,  имеющий  такое поведение,  реализуется  на  уровне  компонентов.  Наследуя  новый  компонент  от  стандартного списка Windows (реализуется через TCustomListBox), вы можете потом с легкостью использовать этот список во многих формах и многих приложениях. В этом примере мы разберемся с первым случаем: прорисовка списка в форме, на которой он живет.

Источник: Теллес М. – Borland C++ Builder. Библиотека программиста – 1998

По теме:

  • Комментарии