Таблицы откликов [MESSAGE_MAP, MESSAGE_HANDLER]

В VCL определены некоторые стандартные события для компонентов. Можно заметить, что эти события похожи на стандартные сообщения Windows. Однако не все сообщения Windows можно найти в VCL, и не все сообщения VCL реализованы в WinAPI. Например, в WinAPI нет сообщения, аналогичному OnClick, с другой стороны, в VCL нет события WM_DROPFILES, которое мы использовали в одном из предыдущих шагов.

Стандартные сообщения компонентов наследуются по иерархии. Изначально каждое из сообщений базируется все же на сообщениях Windows. Чтобы поймать такое сообщение, необходимо создать таблицу откликов. Тот, кто работал с другими версиями библиотек под Windows, например, OWL или MFC знаком с такими таблицами. Например, OWL приложение создает таблицу типа DEFINE_RESPONSE_TABLE1, а MFC приложение - BEGIN_MESSAGE_MAP...END_MESSAGE_MAP. Сходным образом создаются таблицы и в C++Builder.

В данном классе создается секция protected и в нее вписывается таблица откликов:

BEGIN_MESSAGE_MAP
...
MESSAGE_HANDLER(<сообщение Windows>, <тип сообщения>, <имя процедуры обработчика>)
...
END_MESSAGE_MAP(<класс-родитель>)

Процедура-обработчик должна быть перед этим определена как void <имя функции>(<тип сообщения>& Msg). Сообщения Windows можно посмотреть в MS SDK, а типы сообщений прописаны (если у Вас вариант Enterprise) в файле CBuilder5\Source\Vcl\messages.pas. В этой папке хранятся исходники VCL.

Как пример можно привести такой вариант. В компонентах VCL не описано стандартное событие на нажатие правой кнопкой мыши. Вместо этого рекомендуется использовать TPopupMenu и OnContextPopup. Однако иногда необходимо само событие. В примере будут описаны события нажаттие правой кнопкой (RMouseDown), отпускание правой кнопки (RMouseUp), и собственно щелчок (RMouseClick).

//unit1.h----------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TLabel *Label1;
private:
public: // User declarations
__fastcall TForm1(TComponent* Owner);

protected:
void __fastcall WmRButtonDown(TWMRButtonDown& Msg);
void __fastcall WmRButtonUp(TWMRButtonUp& Msg);
virtual void __fastcall RMouseClick(TObject* Sender);
virtual void __fastcall RMouseDown(TObject* Sender);
virtual void __fastcall RMouseUp(TObject* Sender);
bool fMouseDown;
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_RBUTTONDOWN,TWMRButtonDown,WmRButtonDown)
MESSAGE_HANDLER(WM_RBUTTONUP,TWMRButtonUp,WmRButtonUp)
END_MESSAGE_MAP(TForm);
};

//unit1.cpp----------------
void __fastcall TForm1::WmRButtonDown(TWMRButtonDown& Msg)
{
fMouseDown=true;
RMouseDown(this);
}
void __fastcall TForm1::WmRButtonUp(TWMRButtonUp& Msg)
{
if(fMouseDown)
{
RMouseClick(this);
fMouseDown=false;
};
RMouseUp(this);
}
void __fastcall TForm1::RMouseClick(TObject* Sender)
{
Application->MessageBox("Right button clicked","Test",MB_OK);
}

void __fastcall TForm1::RMouseDown(TObject* Sender)
{
Label1->Caption="Right Button down"; //TODO: Add your source code here
}

void __fastcall TForm1::RMouseUp(TObject* Sender)
{
Label1->Caption="Right Button up"; //TODO: Add your source code here
}

Здесь приведены и заголовочный и кодовый файлы. Таким образом разработчики компонентов определяют события для своих творений. Сначала вызывается WinAPI связанный метод объекта, который,в свою очередь, вызывает один из виртуальных методов, которые могут быть переопределены в потомках. В данном случае чисто демонстрационный пример выводит по щелчку окно сообщения, а Label1 отображает текущее состояние правой кнопки.

 

Читайте также:
  • Класс TFileStream. Понятие потока VCL.
    Сначала я бы хотел бы дать некоторое вступление по поводу поточных классов VCL. Эти классы есть некоторое подобие альтернативы поточным классам C++. Как обычно в таких случаях с VCL, основной TStream класс никто впрямую не использует, от него можно только наследовать. Прямым потомком TStream явл...
  • Файловый ввод-вывод.
    fstream Инкапсулирует стандартный ввод-вывод. Я не буду рассматривать расширения этого класса под UNIX, ведь все равно программируем под Windows. Эти самые расширения касаются в основном прав доступа, по умолчанию 666 - allow all. В общем техника работы с этим классом такова. Сначала создается эк...
  • TRegistry
    Чтобы легче было разбираться с Хелпом, скажу, что понятие Key означает не параметр, как можно было подумать, а раздел. Каждый раздел является подразделом главного раздела, которые мы рассмотрели в предыдущем Шаге. Чтобы понятней было, скажу, что иерархия напоминает файловую систему, где HKEY_* - ...
  • Класс списка строк TStringList и его связь с INI-файлами [TStringList, TIniFile]
    Класс TStringList является потомком класса TStrings, используемого в некоторых компонентах VCL, оперирующих текстом. Однако для использования вне объектов класс TStrings не подходит, поскольку не имеет собственного конструктора. Для этих целей используется TStringList, расширяющий функциональнос...
  • Списочные классы [TList, оператор dynamic_cast]
    Списочные классы C++ Builder хранят указатели типа void*, которые могут адресовать любые объекты. Для того, чтобы воспользоваться таким указателем, необходимо выполнить преобразование типа. Преобразования можно выполнить двумя способами - статическим в стиле обычного C++ и динамическим (расширен...