Чтение онлайн

ЖАНРЫ

Программирование на Visual C++. Архив рассылки

Jenter Алекс

Шрифт:

 }

 STDMETHOD(GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames,

LCID lcid, DISPID FAR* rgDispId) {

return S_OK;

 }

 STDMETHOD(Invoke)(DISPID dispIdMember, REFIID riid, LCID lcid,

WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,

EXCEPINFO * pExcepInfo, UINT * puArgErr) {

if (DISPID_VALUE == dispIdMember) (m_pT->*m_pFunc)(m_id, pVarResult);

else TRACE(_T("Invoke dispid = %d\n"), dispIdMember);

return S_OK;

 }

public:

 static LPDISPATCH CreateHandler(T* pT,

EVENTFUNCTIONCALLBACK pFunc, DISPID id) {

CHtmlEventObject<T>* pFO = new CHtmlEventObject<T>;

pFO->m_pT = pT;

pFO->m_pFunc = pFunc;

pFO->m_id = id;

return reinterpret_cast<LPDISPATCH>(pFO);

 }

protected:

 T* m_pT;

 EVENTFUNCTIONCALLBACK m_pFunc;

 DISPID m_id;

 long m_cRef;

};

Как

применять этот класс? Проще простого.

Шаг 1. Создаем свою функцию обработчик по прототипу onevent(dispid id, VARIANT* pVarResult). В принципе ее можно разместить где угодно. Я предпочитаю создавать ее в классе представления, наследнике CHtmlView. При этом все обработчики сосредоточены в одном месте и не нужно беспокоится о взаимодействии с классом документа.

Шаг 2. Регистрируем ее в качестве обработчика интересующего нас события. Для этого через вызов CHtmlEventObject::CreateObject создаем экземпляр нашего COM-объекта. Передаем в него адрес функции обработчика и собственный идентификатор события. После этого передаем ссылку на него интересующему нас элементу.

// Создаем объект-обработчик

LPDISPATCH dispFO = CHtmlEventObject<CEventView>::CreateHandler(this, OnKeyDown, 1);

VARIANT vIn;

V_VT(&vIn) = VT_DISPATCH;

V_DISPATCH(&vIn) = dispFO;

// устанавливаем обработчик document.onkeydown

hr = pHtmlDoc->put_onkeydown(vIn);

Здесь есть одна тонкость. Зарегистрировать обработчик можно только тогда, когда документ уже загружен, иначе GetHtmlDocument вернет NULL. Для этого можно отслеживать событие OnDocumentComplete. Ну вот собственно и все.

Получаем информацию о событии

Рассмотрим еще раз прототип функции обработчика

OnEvent(DISPID id, VARIANT* pVarResult);

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

pVarResult нужно, если не требуется обработки по умолчанию. При этом достаточно в pVarResult вернуть VARIANT_FALSE.

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

Вот его краткое описание из MSDN:

Методы IHTMLEventObj

get_altKey Состояние клавиши Alt
get_button Возвращает информацию о нажатых кнопках мыши
get_cancelBubble Возвращает будет ли продолжена обработка события вверх по иерархии обработчиков
get_clientX Возвращает горизонтальную позицию курсора мыши относительно клиентской области окна
get_clientY Возвращает вертикальную позицию курсора мыши относительно клиентской области окна
get_ctrlKey Состояние клавиши Ctrl
get_fromElement Возвращает
указатель на интерфейс IHTMLElement позволяющий получить доступ к элементу с которого "ушел" курсор мыши при событиях onmouseover или onmouseout.
get_keyCode Возвращает код нажатой клавиши
get_offsetX Возвращает горизонтальную позицию курсора относительно контейнера элемента
get_offsetY Возвращает позицию курсора относительно контейнера элемента
get_qualifier Возвращает идентификатор события
get_reason Возвращает состояние передачи данных для объекта источника данных
get_returnValue Возвращаемое значение события или диалога
get_screenX Горизонтальная координата относительно координат экрана
get_screenY Вертикальная координата относительно координат экрана
get_shiftKey Состояние клавиши Shift
get_srcElement Возвращает указатель на интерфейс IHTMLElement послуживший источником событий
get_srcFilter Возвращает объект фильтр возбудивший событие onfilterchange
get_toElement Возвращает указатель на интерфейс IHTMLElement позволяющий получить доступ к элементу с на который "пришел" курсор мыши при событиях onmouseover или onmouseout
get_type Возвращает строковое название события
get_x Возвращает горизонтальную позицию мыши относительно родительского объекта в иерархии, позиционированного с помощью атрибутов CSS
get_y Возвращает вертикальную позицию мыши относительно родительского объекта в иерархии, позиционированного с помощью атрибутов CSS
put_cancelBubble Задать будет ли продолжена обработка события вверх по иерархии обработчиков
put_keyCode Задать код нажатой клавиши
put_returnValue Задать возвращаемое событием значение

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

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

void CMyHtmlView::OnKeyDown(DISPID id, VARIANT* pVarResult) {

 HRESULT hr;

 LPDISPATCH pDispatch = GetHtmlDocument;

 if (pDispatch != NULL) {

IHTMLDocument2* pHtmlDoc;

hr = pDispatch->;

QueryInterface(__uuidof( IHTMLDocument2), (void**)&pHtmlDoc);

IHTMLWindow2* pWindow;

IHTMLEventObj* pEvent;

hr = pHtmlDoc->get_parentWindow(&pWindow);

ASSERT(SUCCEEDED(hr));

hr = pWindow->get_event(&pEvent);

ASSERT(SUCCEEDED(hr));

// Определяем нажатую клавишу

long nKey;

hr = pEvent->get_keyCode(&nKey);

ASSERT(SUCCEEDED(hr));

// Если Enter не хотим обрабатывать дальше

if (nKey == VK_RETURN) {

V_VT(pVarResult) = VT_BOOL;

Поделиться с друзьями: