在实现的过程中,我想过几种方式。因为我的图片是使用图片框控件显示的,也就是作为一个子窗口控件显示。
所以第一种方式就是,在主窗口中检测移动鼠标,先获取图片控件在主窗口的矩形区域,然后检测鼠标移动事件OnMouseMove,检测当期光标所在的点坐标是否在图片控件的矩形区内。然而当鼠标移到图片控件上之后,主窗口检测不到鼠标移动事件了,因此这种方法失败。
失败的原因:因为图片控件截获了鼠标移动消息,且没有将消息返回给主窗口,所以,主窗口检测不到鼠标移动,而宣告失败。
试图解决:可以给图片控件的鼠标移动消息传递给父窗口,然而,因为只是作为一个控件嵌入到父窗口,所以没法传递消息。如果你知道,请告诉我。所以,你可以重载图片控件,然后将鼠标移动事件传递给父窗口,并做好坐标转换,转换到父窗口客户区的坐标。然而,重载了图片控件,就可以在重载的控件类中对图片控件进行响应,此时图片控件就是一个完整的窗口了,因为它有对用的窗口类了。此时,还有必要将消息传递给父窗口吗?当然没有了。我们可以将鼠标移动的消息直接在重载的图片控件类中处理了,这样更简单,传递给父窗口的目的是因为子窗口控件没有自己的处理的窗口类,才用得上传递。既然现在已经有了窗口类,传递给父窗口处理已经失去了意义,而且没必要,效率很低。甚至找不到理由这样做。
然而重载控件,似乎比较麻烦。我想,这个应该有一个更好的解决方法。所以,继续尝试。
第二种方法就是,不使用图片控件了,直接设置背景图片,并指定图片的位置为左上角,设置背景图片的第二个参数指定。如何设置背景图片,在网站搜索“设置背景图片”即可搜到相关文章,不在此多述。然后检测主窗口的鼠标移动事件,根据背景图片的大小,来检测鼠标是否进入,进入则设置光标的形状为手型。代码如下:
CRect RectPic(0,0,500,250);
if(PtInRect(RectPic, point))
{
SetCursor(LoadCursor(NULL, IDC_HAND));
}
这个是容易实现了,可是单击主窗口打开网页这又变得麻烦了。或者说要在图片显示的这个区域单击主窗口才会打开网页,而在其他地方不会打开网页。那么如此一来,太复杂了点吧。所以这个想法又放弃了。
最后想到了MFC应该提供了这种设置光标的机制。然后查询窗口的消息,发现有一个标准窗口消息WM_SETCURSOR,可以直接搞定这个需求。在主窗口添加这个消息的响应,响应函数为OnSetCursor,然后在函数里面判断要设置光标的子窗口控件是不是当前光标所在的控件,如果是则设置光标,不是就不用管。代码如下:
BOOL CipDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if(pWnd == GetDlgItem(IDC_PIC) || pWnd == GetDlgItem(IDC_INFO))
{
SetCursor(LoadCursor(NULL,IDC_HAND));
return TRUE;
}
return CDialog::OnSetCursor(pWnd, nHitTest, message);
}
我这里的IDC_PIC是图片控件的ID,IDC_INFO是文字标签控件ID。设置好后,要返回,不然就被默认的光标覆盖了。返回TRUE表示你已经处理好了,不用默认处理了。对于MFC,都是这个套路,返回TRUE表示你已经处理,MFC就不会再处理了。如果返回FALSE,表示你没有处理或者不处理。不手动返回,则继续使用默认处理。使用了默认的处理,你的工作等于白费了。
而给图片控件文字标签控件,添加单击响应事件,需要先设置控件属性Notify为TRUE,这样单击标签事件才会生效,双击标签即可添加单击事件响应。
综上,可以看出,最后一种是行得通,也是最简单的,也是标准的实现。以上的一些分析思路,仅作为大家学习的一个参考思路,可以提高一点分析问题的能力。如果有不正确或者不准确的地方,或者遗漏的地方,请指正。