1、简单一点的实现,直接用一个BUTTON来实现超链接效果,
给button添加响应函数,再添加一个OnSetCursor函数来控制光标在按钮上显示为 “手型”,
BOOL CMsCommTestDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
// TODO: 在此添加消息处理程序代码和/或调用默认
/***********************************************************************************************/
//(1).整个对话框控件光标进行编辑,对一批同类的控件进行控制
if (pWnd == GetDlgItem(IDC_BUTTON_OPEN_CLOSE))
// 重载WM_SETCURSOR消息,加上
SetCursor(AfxGetApp()->LoadCursor(IDC_HANDCURSOR));
return true;
// 把基类的::OnSetCursor(pWnd,nHitTest,message)去掉。
/***********************************************************************************************/
// (2).对单个的Button控件进行编辑
if (pWnd == GetDlgItem(IDC_BUTTON_MANUALSEND) || pWnd == GetDlgItem(IDC_BUTTON_LINKER))//判断光标的pWnd
{
SetCursor(AfxGetApp()->LoadCursor(IDC_HANDCURSOR)); //这个光标也是手动添加的
//这里加载的是系统自带的光标资源
// HCURSOR m_hCursor = LoadCursor(NULL,IDC_HAND);
// SetCursor(m_hCursor);
// 注:对VC6.0来说其IDC_HAND可能要手动重新添加一下
//这里加载的是手动添加的光标资源
// HCURSOR m_hHandCursor;
// m_hHandCursor=LoadCursor(AfxGetResourceHandle(),MAKEINTRESOURCE(IDC_HANDCURSOR));
// SetCursor(m_hHandCursor);
return TRUE; // 必须要有
}
return CDialog::OnSetCursor(pWnd, nHitTest, message);
}
void CMsCommTestDlg::OnButtonLinker()
{
// TODO: 在此添加控件通知处理程序代码
ShellExecute(NULL, NULL, _T("http://blog.csdn.net/longzhiten98"), NULL, NULL, SW_SHOWNORMAL);
}
2、手动添加一个CHyperLinker类来实现
在许多软件中,都有一个联系联系作者本人或者软件提供者的超链接,点击这个超链接可以向作者或软件提供者发送邮件或打开某个网页浏览信息,给软件的使用者带很大的方便。本文尝试设计和实现一个超级链接的功能,使它不仅能满足上面得功能,还能根据使用者的喜好在超链接的文本上采用不同的字体。
1.设计原理
CStatic类是从CWnd类继承出来的一个静态文本框类,它对应静态文本框控件。静态文本框控件常用来在对话框上显示软件信息或者是提示信息。本例采用重载CStatic类的方法,用类的成员函数完成上面的功能。
2.具体实现
使用类向导生成一个基类为CStatic的CHyperLinker类。
其中还需要利用向导添加一个相应函数PreSubclassWindow();
在CHyperLinker.h文件中,添加类的如下成员变量:
// Attributes
public:
COLORREF m_InitColor; // 超级链接开始时的文本颜色
COLORREF m_VisitedColor; // 超级链接被访问过的的文本颜色
COLORREF m_CoverColor; // 鼠标移动到超级链接文本框上的文本颜色
BOOL m_bAboveControl; // 记录当前鼠标是否停留在超级链接上方
BOOL m_bVisited; // 记录超级链接是否被访问过
BOOL m_bUnderLine; // 文本是否带下划线
CString m_sURL; // URL信息
CFont m_Font; // 字体
HCURSOR m_hLinkCursor; // 鼠标形状
在CHyperLinker.h文件中,添加类的如下成员函数声明(自己定义的):
// Operations
public:
// 设置对应文本框属性值
void SetAttrbute(CString url = "www.baidu.com", COLORREF InitColor = RGB(0,0,255),
COLORREF VisitedColor = RGB(255,0,0),
COLORREF CoverColor = RGB(125,125,0), BOOL bUnderLine = TRUE);
// shell 外部的程序
BOOL OpenUsingShellExecute();
// 设置字体
void SetFont(CFont *font);
// Generated message map functions // 添加的消息映射
protected:
//{{AFX_MSG(CHyperLinker)
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
在CHyperLinker.cpp中添加如下的函数定义:
CHyperLinker::CHyperLinker()
{
m_bAboveControl = FALSE;
m_bUnderLine = FALSE;
m_bVisited = FALSE;
}
CHyperLinker::~CHyperLinker()
{
}
BEGIN_MESSAGE_MAP(CHyperLinker, CStatic)
//{{AFX_MSG_MAP(CHyperLinker)
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONDOWN()
ON_WM_SETCURSOR()
ON_WM_CTLCOLOR_REFLECT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/
// CHyperLinker message handlers
void CHyperLinker::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CRect rect;
GetClientRect(rect); // 得到当前文本框的矩形区域
static BOOL bIsIn = FALSE; // 判断前一次鼠标是否已经在文本框区域
if (rect.PtInRect(point)) // 在区域内
{
m_bAboveControl = TRUE; // 记录鼠标已经停留在超级链接文本框的上方
if (!bIsIn) // 如果是第一次停留,则用其他颜色重绘文本
{
SetCapture(); // 设置鼠标捕获
bIsIn = TRUE;
Invalidate(); // 调用CtrlColor重绘文本
}
}
else
{
m_bAboveControl = FALSE; // 记录鼠标不在超级链接文本框的上方
if (bIsIn) // 如果是第一次离开区域,则用其他颜色重绘文本
{
ReleaseCapture(); // 释放鼠标捕获
bIsIn = FALSE;
Invalidate(); // 调用CtrlColor重绘文本
}
}
CStatic::OnMouseMove(nFlags, point);
}
void CHyperLinker::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
OpenUsingShellExecute(); // shell外部程序
m_bVisited = TRUE; // 表示应经点击过超级链接文本框
Invalidate(); // 调用CtrlColor重绘文本
CStatic::OnLButtonDown(nFlags, point);
}
// 设置静态文本控件上的光标图形
BOOL CHyperLinker::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
// TODO: Add your message handler code here and/or call default
HCURSOR LinkCurlor = ::AfxGetApp()->LoadCursor(IDC_CUR_HAND); //这里的IDC_CUR_HAND是需要手动添加一个光标资源
::SetCursor(LinkCurlor);
return TRUE;
return CStatic::OnSetCursor(pWnd, nHitTest, message);
}
//在CStatic类中,用ClassWizard重载消息“=WM_CTLCOLOR”的函数CtlColor(),注意:不要错误地重载名为“WM_CTLCOLOR”的消息,
//若重载了它会得不到想要的效果。
HBRUSH CHyperLinker::CtlColor(CDC* pDC, UINT nCtlColor)
{
// TODO: Change any attributes of the DC here
ASSERT(nCtlColor == CTLCOLOR_STATIC);
DWORD dwStyle = GetStyle();
if (!(dwStyle & SS_NOTIFY))
{
::SetWindowLong(m_hWnd, GWL_STYLE, dwStyle | SS_NOTIFY);
}
HBRUSH hbr = NULL;
if ((dwStyle & 0xFF) <= SS_RIGHT)
{
// modify the font to be underline
if (!((HFONT)m_Font))
{
LOGFONT lf;
GetFont()->GetObject(sizeof(lf), &lf);
lf.lfUnderline = m_bUnderLine;
m_Font.CreateFontIndirect(&lf);
}
pDC->SelectObject(&m_Font);
// set the text color
if (m_bVisited)
{
pDC->SetTextColor(m_VisitedColor);
}
else
{
if (m_bAboveControl)
{
pDC->SetTextColor(m_CoverColor);
}
else
{
pDC->SetTextColor(m_InitColor);
}
}
pDC->SetBkMode(TRANSPARENT);
hbr = (HBRUSH)::GetStockObject(HOLLOW_BRUSH);
}
// TODO: Return a non-NULL brush if the parent's handler should not be called
return hbr;
}
// 设置属性
void CHyperLinker::SetAttrbute(CString url, COLORREF InitColor, COLORREF VisitedColor,
COLORREF CoverColor, BOOL bUnderLine)
{
m_sURL = url;
m_InitColor = InitColor;
m_VisitedColor = VisitedColor;
m_CoverColor = CoverColor;
m_bUnderLine = bUnderLine;
}
// 使用Web启动默认的浏览器
BOOL CHyperLinker::OpenUsingShellExecute()
{
HINSTANCE hRun = ShellExecute(GetParent()->GetSafeHwnd(),
_T("open"), m_sURL, NULL, NULL, SW_SHOW);
if((int)hRun <= 32) //如果ShellExecute执行成功则其返回值将大于32,如果出错则会小于等于32.
{
AfxMessageBox(_T("提供的超级链接或者指定的文件无法执行"), MB_OK, 0);
return FALSE;
}
return TRUE;
}
void CHyperLinker::PreSubclassWindow()
{
// TODO: Add your specialized code here and/or call the base class
DWORD dwStyle = GetStyle();
::SetWindowLong(GetSafeHwnd(), GWL_STYLE, dwStyle | SS_NOTIFY); // 设置动态窗口属性
CStatic::PreSubclassWindow();
}
void CHyperLinker::SetFont(CFont *font)
{
// 设置字体
memcpy(&m_Font, font, sizeof(CFont));
// 根据字体的长度和宽度设置静态框的长度和宽度
CDC *pDC = GetDC();
CFont *pOldfont = pDC->SelectObject(&m_Font);
CString str;
GetWindowText(str);
CSize size = pDC->GetTextExtent(str, str.GetLength());
SetWindowPos(NULL, 0, 0, size.cx, size.cy, SWP_NOMOVE);
pDC->SelectObject(pOldfont);
ReleaseDC(pDC);
}
注:IDC_CUR_HAND是自己添加的鼠标资源,Windows NT 5.0以后的版本可已使用IDC_HAND
3.应用实例
利用MFC AppWizard 生成一个基于对话框的项目,在对话框上添加三个Static控件,修改ID分别为IDC_LINKER、IDC_LOCALFILE和IDC_NET,用Class Wizard 为这三个控件生成3个CHyperLinker对象(注意为CHyperLinker对象而非CStatic对象),在对话框InitDialog函数中添加如下的代码:
// TODO: Add extra initialization here
m_linker.SetAttrbute("http://blog.sina.com.cn/luoshuquan108");// 链接到我的博客
m_localfile.SetAttrbute("E:\\musics\\Helloween - Forever and One.mp3"); // 打开本地文件,这里注意路径为双斜杠 \\
CFont *font = new CFont;
font->CreatePointFont(200, "微软雅黑");
m_net.SetAttrbute("mailto:luoshuquan108@hotmail.com");// 给我发邮件
m_net.SetFont(font); // 设置字体
运行效果如下:
参考资料:《Visual C++ 网络通信编程使用案例精选》 人民邮电出版社 丁展 刘海英等编著
ISBN-7-115-12164-8/TP·3903