在许多软件中,都有一个联系联系作者本人或者软件提供者的超链接,点击这个超链接可以向作者或软件提供者发送邮件或打开某个网页浏览信息,给软件的使用者带很大的方便。本文尝试设计和实现一个超级链接的功能,使它不仅能满足上面得功能,还能根据使用者的喜好在超链接的文本上采用不同的字体。
1.设计原理
CStatic类是从CWnd类继承出来的一个静态文本框类,它对应静态文本框控件。静态文本框控件常用来在对话框上显示软件信息或者是提示信息。本例采用重载CStatic类的方法,用类的成员函数完成上面的功能。
2.具体实现
使用类向导生成一个基类为CStatic的CHyperLinker类。
在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);
::SetCursor(LinkCurlor);
return TRUE;
return CStatic::OnSetCursor(pWnd, nHitTest, message);
}
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;
}
BOOL CHyperLinker::OpenUsingShellExecute()
{
HINSTANCE hRun = ShellExecute(GetParent()->GetSafeHwnd(),
_T("open"), m_sURL, NULL, NULL, SW_SHOW);
if((int)hRun <= 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对象,在对话框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); // 设置字体
运行效果如下:
![[转载]VC超级链接的设计与实现 [转载]VC超级链接的设计与实现](https://i-blog.csdnimg.cn/blog_migrate/01fc8edfd0a1e79b60364f7016eb1737.jpeg)
参考资料:《Visual C++ 网络通信编程使用案例精选》 人民邮电出版社 丁展 刘海英等编著
ISBN-7-115-12164-8/TP·3903