鄙人最近从事定制IE的开发,网页查找功能算个不小的功能点,当然你可以方便地显示浏览器自带的查找窗口,但是那与自己定制的浏览器就有点不和谐了.我一直用奇虎公司的360安全浏览器,很喜欢它的查找风格:显示一个工具栏,提供查找和高亮关键字的功能,尤其是高亮关键字的功能,鄙人觉得那是相当的实用.于是鄙人下决心也要实现那样的功能.网上无示例,唯有MSDN.
遍历网页元素,一般用树模型,用树模型遍历网页元素,以实现高亮功能,理论上可行,但是要实现查找功能就有点牵强了,关键在于保存查找的状态.因此这种方案直觉上就落了下乘了.于是鄙人苦寻MSDN,终于找到Markup Services模型,这种模型提供以流的方式遍历网页元素.(MSDN地址为:http://msdn.microsoft.com/en-us/library/bb508514(VS.85).aspx)
根据资料,鄙人将高亮功能封装成一个方法:高亮(黄色)显示指定文档中的指定关键字.(具体结合注释看代码)
void
HightlightKeyWord( IHTMLDocument2
*
pHtmlDoc, LPCTSTR lpszKeyWord )
{
ATLASSERT( ( pHtmlDoc != NULL ) && ( AtlIsValidString( lpszKeyWord )) );
CComPtr < IMarkupServices > spMarkService; // 服务接口
CComPtr < IMarkupContainer > spMarkContainer; // 容器接口
CComPtr < IMarkupPointer > spMarkPointerBegin, spMarkPointerEnd; // 查找位置指针
ATLASSERT(SUCCEEDED(pHtmlDoc -> QueryInterface( IID_IMarkupServices, ( void ** ) & spMarkService )));
ATLASSERT(SUCCEEDED(pHtmlDoc -> QueryInterface( IID_IMarkupContainer, ( void ** ) & spMarkContainer )));
// 创建位置指针
ATLASSERT(SUCCEEDED(spMarkService -> CreateMarkupPointer( & spMarkPointerBegin )));
ATLASSERT(SUCCEEDED(spMarkService -> CreateMarkupPointer( & spMarkPointerEnd )));
// IMarkupPointer::SetGravity设置可以决定:
// 当在IMarkupPointer位置处插入一元素后,IMarkupPointer对象是位于插入元素的左边还是右边(具体查看MSDN)
ATLASSERT(SUCCEEDED(spMarkPointerBegin -> SetGravity( POINTER_GRAVITY_Right )));
ATLASSERT(SUCCEEDED(spMarkPointerEnd -> SetGravity( POINTER_GRAVITY_Left )));
// 设置到IMarkupContainer容器开头
ATLASSERT(SUCCEEDED(spMarkPointerBegin -> MoveToContainer( spMarkContainer, TRUE )));
// 设置到IMarkupContainer容器结尾
ATLASSERT(SUCCEEDED(spMarkPointerEnd -> MoveToContainer( spMarkContainer, FALSE )));
while ( TRUE )
{
if ( S_OK != spMarkPointerBegin -> FindText( CT2OLE(lpszKeyWord), 0 , spMarkPointerEnd, NULL ) )
break ;
// 如果搜索到匹配文本,则自动设置spMarkPointerEnd指向匹配的位置
IHTMLElement * pNewElement;
// 创建一个<B></B> 标志,并设置背景为黄色
ATLASSERT(SUCCEEDED(spMarkService -> CreateElement(TAGID_B, L " STYLE=\ " background - color:yellow\ "" , & pNewElement)));
// 插入刚创建的标志到查找到的位置
ATLASSERT(SUCCEEDED(spMarkService -> InsertElement( pNewElement, spMarkPointerBegin, spMarkPointerEnd)));
// 继续查找
spMarkPointerBegin -> MoveToPointer( spMarkPointerEnd);
// 滚动元素 使元素显示在视野中
VARIANT var;
var.vt = VT_BOOL;
var.boolVal = VARIANT_FALSE; // 最为最后一行显示
pNewElement -> scrollIntoView( var );
}
}
{
ATLASSERT( ( pHtmlDoc != NULL ) && ( AtlIsValidString( lpszKeyWord )) );
CComPtr < IMarkupServices > spMarkService; // 服务接口
CComPtr < IMarkupContainer > spMarkContainer; // 容器接口
CComPtr < IMarkupPointer > spMarkPointerBegin, spMarkPointerEnd; // 查找位置指针
ATLASSERT(SUCCEEDED(pHtmlDoc -> QueryInterface( IID_IMarkupServices, ( void ** ) & spMarkService )));
ATLASSERT(SUCCEEDED(pHtmlDoc -> QueryInterface( IID_IMarkupContainer, ( void ** ) & spMarkContainer )));
// 创建位置指针
ATLASSERT(SUCCEEDED(spMarkService -> CreateMarkupPointer( & spMarkPointerBegin )));
ATLASSERT(SUCCEEDED(spMarkService -> CreateMarkupPointer( & spMarkPointerEnd )));
// IMarkupPointer::SetGravity设置可以决定:
// 当在IMarkupPointer位置处插入一元素后,IMarkupPointer对象是位于插入元素的左边还是右边(具体查看MSDN)
ATLASSERT(SUCCEEDED(spMarkPointerBegin -> SetGravity( POINTER_GRAVITY_Right )));
ATLASSERT(SUCCEEDED(spMarkPointerEnd -> SetGravity( POINTER_GRAVITY_Left )));
// 设置到IMarkupContainer容器开头
ATLASSERT(SUCCEEDED(spMarkPointerBegin -> MoveToContainer( spMarkContainer, TRUE )));
// 设置到IMarkupContainer容器结尾
ATLASSERT(SUCCEEDED(spMarkPointerEnd -> MoveToContainer( spMarkContainer, FALSE )));
while ( TRUE )
{
if ( S_OK != spMarkPointerBegin -> FindText( CT2OLE(lpszKeyWord), 0 , spMarkPointerEnd, NULL ) )
break ;
// 如果搜索到匹配文本,则自动设置spMarkPointerEnd指向匹配的位置
IHTMLElement * pNewElement;
// 创建一个<B></B> 标志,并设置背景为黄色
ATLASSERT(SUCCEEDED(spMarkService -> CreateElement(TAGID_B, L " STYLE=\ " background - color:yellow\ "" , & pNewElement)));
// 插入刚创建的标志到查找到的位置
ATLASSERT(SUCCEEDED(spMarkService -> InsertElement( pNewElement, spMarkPointerBegin, spMarkPointerEnd)));
// 继续查找
spMarkPointerBegin -> MoveToPointer( spMarkPointerEnd);
// 滚动元素 使元素显示在视野中
VARIANT var;
var.vt = VT_BOOL;
var.boolVal = VARIANT_FALSE; // 最为最后一行显示
pNewElement -> scrollIntoView( var );
}
}
既然提供高亮关键字的功能,当然也需要提供去除高亮的功能.
清除可调用IMarkupServices::RemoveElement 方法,传入高亮元素IHTMLElement对象。