MFC 中创建简单超链接

MFC SDI程序在菜单的最后通常会有一个帮助的菜单项,点击后弹出一个关于程序基本信息的对话框(CAboutDlg),想在这个界面添加一条超链接,指向指定的网页,这个网页上存放介绍这个程序更多的信息。查资料说API函数使用ShellExecute可以实现,试了一下,没有成功,这种方法后续再补充。先介绍一下另外一种实现方法(注:这种方法也也是在网上搜集整理的)。

步骤如下:

1) 新建一个MFC单文档应用程序,命名为test。

2) 打开解决方案视图,在头文件中按照步骤:右键---添加---新建项---头文件(.h),命名为HyperLink.h ,在这个头文件中添加下面的代码:

//***************************************************************************

// Description  : Hyper Link Static Class

//  File Name  : HyperLink.H

//  Created   : 

// Email   : 

//***************************************************************************

#if !defined(AFX_HYPERLINK_H__D1625061_574B_11D1_ABBA_00A0243D1382__INCLUDED_)

#define AFX_HYPERLINK_H__D1625061_574B_11D1_ABBA_00A0243D1382__INCLUDED_

#if _MSC_VER >= 1000

#pragma once

#endif // _MSC_VER >= 1000

/////////////////////////////////////////////////////////////////////////////

// CHyperLink window

class CHyperLink : public CStatic

{

// Construction/destruction

public:

    CHyperLink();

    virtual ~CHyperLink();

public:

    enum UnderLineOptions { ulHover = -1, ulNone = 0, ulAlways = 1};

// Attributes

public:

    void SetURL(CString strURL);

    CString GetURL() const;

    void SetColours(COLORREF crLinkColourCOLORREF crVisitedColour

                    COLORREF crHoverColour = -1);

    COLORREF GetLinkColour() const;

    COLORREF GetVisitedColour() const;

    COLORREF GetHoverColour() const;

    void SetVisited(BOOL bVisited = TRUE);

    BOOL GetVisited() const;

    void SetLinkCursor(HCURSOR hCursor);

    HCURSOR GetLinkCursor() const;

    void SetUnderline(int nUnderline = ulHover);

    int  GetUnderline() const;

    void SetAutoSize(BOOL bAutoSize = TRUE);

    BOOL GetAutoSize() const;

// Overrides

    // ClassWizard generated virtual function overrides

    //{{AFX_VIRTUAL(CHyperLink)

 public:

    virtual BOOL PreTranslateMessage(MSGpMsg);

 virtual BOOL DestroyWindow();

 protected:

    virtual void PreSubclassWindow();

 //}}AFX_VIRTUAL

// Implementation

protected:

    HINSTANCE GotoURL(LPCTSTR urlint showcmd);

    void ReportError(int nError);

    LONG GetRegKey(HKEY keyLPCTSTR subkeyLPTSTR retdata);

    void PositionWindow();

    void SetDefaultCursor();

// Protected attributes

protected:

    COLORREF  m_crLinkColourm_crVisitedColour;     // Hyperlink colours

    COLORREF  m_crHoverColour;                       // Hover colour

    BOOL   m_bOverControl;                        // cursor over control?

    BOOL   m_bVisited;                            // Has it been visited?

    int    m_nUnderline;                          // underline hyperlink?

    BOOL   m_bAdjustToFit;                        // Adjust window size to fit text?

    CString   m_strURL;                              // hyperlink URL

    CFont   m_UnderlineFont;                       // Font for underline display

    CFont   m_StdFont;                             // Standard font

    HCURSOR   m_hLinkCursor;                         // Cursor for hyperlink

    CToolTipCtrl m_ToolTip;          // The tooltip

    UINT   m_nTimerID;

    // Generated message map functions

protected:

    //{{AFX_MSG(CHyperLink)

    afx_msg HBRUSH CtlColor(CDCpDCUINT nCtlColor);

    afx_msg BOOL OnSetCursor(CWndpWndUINT nHitTestUINT message);

    afx_msg void OnMouseMove(UINT nFlagsCPoint point);

 afx_msg void OnTimer(UINT nIDEvent);

 afx_msg BOOL OnEraseBkgnd(CDCpDC);

 //}}AFX_MSG

    afx_msg void OnClicked();

    DECLARE_MESSAGE_MAP()

};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}

// Microsoft Developer Studio will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_HYPERLINK_H__D1625061_574B_11D1_ABBA_00A0243D1382__INCLUDED_)

3) 再添加对应的源文件。步骤:在解决方案视图中,右键点击源文件---添加---新建项---C++文件(.cpp),命名为 HyperLink.cpp ,在这个头文件中添加下面的代码:

// HyperLink.cpp : implementation file

// HyperLink static control. Will open the default browser with the given URL

// when the user clicks on the link.

#include "stdafx.h"

#include "HyperLink.h"

#include "atlconv.h"    // for Unicode conversion - requires #include <afxdisp.h> // MFC OLE automation classes

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

#define TOOLTIP_ID 1

/////////////////////////////////////////////////////////////////////////////

// CHyperLink

CHyperLink::CHyperLink()

{

m_hLinkCursor       = NULL;                 // No cursor as yet

m_crLinkColour      = RGB(  0,   0, 238);   // Blue

m_crVisitedColour   = RGB( 85,  26, 139);   // Purple

m_crHoverColour     = RGB(255,   0,   0);   // Red

m_bOverControl      = FALSE;                // Cursor not yet over control

m_bVisited          = FALSE;                // Hasn't been visited yet.

m_nUnderline        = ulHover;              // Underline the link?

m_bAdjustToFit      = TRUE;                 // Resize the window to fit the text?

m_nTimerID          = 100;

m_strURL.Empty(); 

}

CHyperLink::~CHyperLink()

{

m_UnderlineFont.DeleteObject();

}

/////////////////////////////////////////////////////////////////////////////

// CHyperLink overrides

BOOL CHyperLink::DestroyWindow() 

{

KillTimer(m_nTimerID);

return CStatic::DestroyWindow();

}

BOOL CHyperLink::PreTranslateMessage(MSGpMsg

{

m_ToolTip.RelayEvent(pMsg);

return CStatic::PreTranslateMessage(pMsg);

}

void CHyperLink::PreSubclassWindow() 

{

// We want to get mouse clicks via STN_CLICKED

DWORD dwStyle = GetStyle();

::SetWindowLong(GetSafeHwnd(), GWL_STYLEdwStyle | SS_NOTIFY);

// Set the URL as the window text

if (m_strURL.IsEmpty())

GetWindowText(m_strURL);

// Check that the window text isn't empty. If it is, set it as the URL.

CString strWndText;

GetWindowText(strWndText);

if (strWndText.IsEmpty()) 

{

ASSERT(!m_strURL.IsEmpty());    // Window and URL both NULL. DUH!

SetWindowText(m_strURL);

}

CFontpFont = GetFont();

if (!pFont)

{

HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);

if (hFont == NULL)

hFont = (HFONTGetStockObject(ANSI_VAR_FONT);

if (hFont)

pFont = CFont::FromHandle(hFont);

}

ASSERT(pFont->GetSafeHandle());

// Create the underline font

LOGFONT lf;

pFont->GetLogFont(&lf);

m_StdFont.CreateFontIndirect(&lf);

lf.lfUnderline = (BYTETRUE;

m_UnderlineFont.CreateFontIndirect(&lf);

PositionWindow();        // Adjust size of window to fit URL if necessary

SetDefaultCursor();      // Try and load up a "hand" cursor

SetUnderline();

// Create the tooltip

CRect rect

GetClientRect(rect);

m_ToolTip.Create(this);

m_ToolTip.AddTool(thism_strURLrectTOOLTIP_ID);

CStatic::PreSubclassWindow();

}

BEGIN_MESSAGE_MAP(CHyperLinkCStatic)

//{{AFX_MSG_MAP(CHyperLink)

ON_WM_CTLCOLOR_REFLECT()

ON_WM_SETCURSOR()

ON_WM_MOUSEMOVE()

ON_WM_TIMER()

ON_CONTROL_REFLECT(STN_CLICKEDOnClicked)

ON_WM_ERASEBKGND()

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////

// CHyperLink message handlers

void CHyperLink::OnClicked()

{

m_bOverControl = FALSE;

int result = (int)GotoURL(m_strURLSW_SHOW);

m_bVisited = (result > HINSTANCE_ERROR);

if (!m_bVisited)

{

MessageBeep(MB_ICONEXCLAMATION);     // Unable to follow link

ReportError(result);

}

else 

SetVisited();                        // Repaint to show visited colour

}

HBRUSH CHyperLink::CtlColor(CDCpDCUINT nCtlColor

{

ASSERT(nCtlColor == CTLCOLOR_STATIC);

if (m_bOverControl)

pDC->SetTextColor(m_crHoverColour);

else if (m_bVisited)

pDC->SetTextColor(m_crVisitedColour);

else

pDC->SetTextColor(m_crLinkColour);

// transparent text.

pDC->SetBkMode(TRANSPARENT);

return (HBRUSH)GetStockObject(NULL_BRUSH);

}

void CHyperLink::OnMouseMove(UINT nFlagsCPoint point

{

if (!m_bOverControl)        // Cursor has just moved over control

{

m_bOverControl = TRUE;

if (m_nUnderline == ulHover)

SetFont(&m_UnderlineFont);

Invalidate();

SetTimer(m_nTimerID, 100, NULL);

}

CStatic::OnMouseMove(nFlagspoint);

}

void CHyperLink::OnTimer(UINT nIDEvent

{

CPoint p(GetMessagePos());

ScreenToClient(&p);

CRect rect;

GetClientRect(rect);

if (!rect.PtInRect(p))

{

m_bOverControl = FALSE;

KillTimer(m_nTimerID);

if (m_nUnderline != ulAlways)

SetFont(&m_StdFont);

rect.bottom+=10;

InvalidateRect(rect);

}

CStatic::OnTimer(nIDEvent);

}

BOOL CHyperLink::OnSetCursor(CWnd/*pWnd*/UINT /*nHitTest*/UINT /*message*/

{

if (m_hLinkCursor)

{

::SetCursor(m_hLinkCursor);

return TRUE;

}

return FALSE;

}

BOOL CHyperLink::OnEraseBkgnd(CDCpDC

{

CRect rect;

GetClientRect(rect);

pDC->FillSolidRect(rect, ::GetSysColor(COLOR_3DFACE));

return TRUE;

}

/////////////////////////////////////////////////////////////////////////////

// CHyperLink operations

void CHyperLink::SetURL(CString strURL)

{

m_strURL = strURL;

if (::IsWindow(GetSafeHwnd())) 

{

PositionWindow();

m_ToolTip.UpdateTipText(strURLthisTOOLTIP_ID);

}

}

CString CHyperLink::GetURL() const

return m_strURL;   

}

void CHyperLink::SetColours(COLORREF crLinkColourCOLORREF crVisitedColour,

COLORREF crHoverColour /* = -1 */

m_crLinkColour    = crLinkColour

m_crVisitedColour = crVisitedColour;

if (crHoverColour == -1)

m_crHoverColour = ::GetSysColor(COLOR_HIGHLIGHT);

else

m_crHoverColour = crHoverColour;

if (::IsWindow(m_hWnd))

Invalidate(); 

}

COLORREF CHyperLink::GetLinkColour() const

return m_crLinkColour

}

COLORREF CHyperLink::GetVisitedColour() const

{

return m_crVisitedColour

}

COLORREF CHyperLink::GetHoverColour() const

{

return m_crHoverColour;

}

void CHyperLink::SetVisited(BOOL bVisited /* = TRUE */

m_bVisited = bVisited

if (::IsWindow(GetSafeHwnd()))

Invalidate(); 

}

BOOL CHyperLink::GetVisited() const

return m_bVisited

}

void CHyperLink::SetLinkCursor(HCURSOR hCursor)

m_hLinkCursor = hCursor;

if (m_hLinkCursor == NULL)

SetDefaultCursor();

}

HCURSOR CHyperLink::GetLinkCursor() const

{

return m_hLinkCursor;

}

void CHyperLink::SetUnderline(int nUnderline /*=ulHover*/)

{

if (m_nUnderline == nUnderline)

return;

if (::IsWindow(GetSafeHwnd()))

{

if (nUnderline == ulAlways)

SetFont(&m_UnderlineFont);

else

SetFont(&m_StdFont);

Invalidate(); 

}

m_nUnderline = nUnderline;

}

int CHyperLink::GetUnderline() const

return m_nUnderline

}

void CHyperLink::SetAutoSize(BOOL bAutoSize /* = TRUE */)

{

m_bAdjustToFit = bAutoSize;

if (::IsWindow(GetSafeHwnd()))

PositionWindow();

}

BOOL CHyperLink::GetAutoSize() const

return m_bAdjustToFit

}

// Move and resize the window so that the window is the same size

// as the hyperlink text. This stops the hyperlink cursor being active

// when it is not directly over the text. If the text is left justified

// then the window is merely shrunk, but if it is centred or right

// justified then the window will have to be moved as well.

void CHyperLink::PositionWindow()

{

if (!::IsWindow(GetSafeHwnd()) || !m_bAdjustToFit

return;

// Get the current window position

CRect WndRectClientRect;

GetWindowRect(WndRect);

GetClientRect(ClientRect);

ClientToScreen(ClientRect);

CWndpParent = GetParent();

if (pParent)

{

pParent->ScreenToClient(WndRect);

pParent->ScreenToClient(ClientRect);

}

// Get the size of the window text

CString strWndText;

GetWindowText(strWndText);

CDCpDC = GetDC();

CFontpOldFont = pDC->SelectObject(&m_UnderlineFont);

CSize Extent = pDC->GetTextExtent(strWndText);

pDC->SelectObject(pOldFont);

ReleaseDC(pDC);

// Adjust for window borders

Extent.cx += WndRect.Width() - ClientRect.Width(); 

Extent.cy += WndRect.Height() - ClientRect.Height(); 

// Get the text justification via the window style

DWORD dwStyle = GetStyle();

// Recalc the window size and position based on the text justification

if (dwStyle & SS_CENTERIMAGE)

WndRect.DeflateRect(0, (WndRect.Height() - Extent.cy)/2);

else

WndRect.bottom = WndRect.top + Extent.cy;

if (dwStyle & SS_CENTER)   

WndRect.DeflateRect((WndRect.Width() - Extent.cx)/2, 0);

else if (dwStyle & SS_RIGHT

WndRect.left  = WndRect.right - Extent.cx;

else // SS_LEFT = 0, so we can't test for it explicitly 

WndRect.right = WndRect.left + Extent.cx;

// Move the window

SetWindowPos(NULLWndRect.leftWndRect.topWndRect.Width(), WndRect.Height(), SWP_NOZORDER);

}

/////////////////////////////////////////////////////////////////////////////

// CHyperLink implementation

// The following appeared in Paul DiLascia's Jan 1998 MSJ articles.

// It loads a "hand" cursor from the winhlp32.exe module

void CHyperLink::SetDefaultCursor()

{

if (m_hLinkCursor == NULL)                // No cursor handle - load our own

{

// Get the windows directory

CString strWndDir;

GetWindowsDirectory(strWndDir.GetBuffer(MAX_PATH), MAX_PATH);

strWndDir.ReleaseBuffer();

strWndDir += _T("");

// This retrieves cursor #106 from winhlp32.exe, which is a hand pointer

HMODULE hModule = LoadLibrary(strWndDir);

if (hModule) {

HCURSOR hHandCursor = ::LoadCursor(hModuleMAKEINTRESOURCE(106));

if (hHandCursor)

m_hLinkCursor = CopyCursor(hHandCursor);

}

FreeLibrary(hModule);

}

}

LONG CHyperLink::GetRegKey(HKEY keyLPCTSTR subkeyLPTSTR retdata)

{

HKEY hkey;

LONG retval = RegOpenKeyEx(keysubkey, 0, KEY_QUERY_VALUE, &hkey);

if (retval == ERROR_SUCCESS) {

long datasize = MAX_PATH;

TCHAR data[MAX_PATH];

RegQueryValue(hkeyNULLdata, &datasize);

lstrcpy(retdata,data);

RegCloseKey(hkey);

}

return retval;

}

void CHyperLink::ReportError(int nError)

{

CString str;

switch (nError

{

case 0:                       str = "The operating system is out\nof memory or resources."break;

case SE_ERR_PNF:              str = "The specified path was not found."break;

case SE_ERR_FNF:              str = "The specified file was not found."break;

case ERROR_BAD_FORMAT:        str = "The .EXE file is invalid\n(non-Win32 .EXE or error in .EXE image)."break;

case SE_ERR_ACCESSDENIED:     str = "The operating system denied\naccess to the specified file."break;

case SE_ERR_ASSOCINCOMPLETE:  str = "The filename association is\nincomplete or invalid."break;

case SE_ERR_DDEBUSY:          str = "The DDE transaction could not\nbe completed because other DDE transactions\nwere being processed."break;

case SE_ERR_DDEFAIL:          str = "The DDE transaction failed."break;

case SE_ERR_DDETIMEOUT:       str = "The DDE transaction could not\nbe completed because the request timed out."break;

case SE_ERR_DLLNOTFOUND:      str = "The specified dynamic-link library was not found."break;

case SE_ERR_NOASSOC:          str = "There is no application associated\nwith the given filename extension."break;

case SE_ERR_OOM:              str = "There was not enough memory to complete the operation."break;

case SE_ERR_SHARE:            str = "A sharing violation occurred. ";

default:                      str.Format(_T("Unknown Error (%d) occurred."), nError); break;

}

str += _T("Unable to open hyperlink:\n\n"/*+ str*/;

AfxMessageBox(strMB_ICONEXCLAMATION | MB_OK);

}

HINSTANCE CHyperLink::GotoURL(LPCTSTR urlint showcmd)

{

TCHAR key[MAX_PATH + MAX_PATH];

// First try ShellExecute()

HINSTANCE result = ShellExecute(NULL_T("open"), urlNULL,NULLshowcmd);

// If it failed, get the .htm regkey and lookup the program

if ((UINT)result <= HINSTANCE_ERROR)

{

if (GetRegKey(HKEY_CLASSES_ROOT_T(".htm"), key) == ERROR_SUCCESS

{

lstrcat(key_T(""));

if (GetRegKey(HKEY_CLASSES_ROOT,key,key) == ERROR_SUCCESS)

{

TCHAR *pos;

pos = _tcsstr(key_T("\"%1\""));

if (pos == NULL) {                     // No quotes found

pos = _tcsstr(key_T("%1"));      // Check for %1, without quotes 

if (pos == NULL)                   // No parameter at all...

pos = key+lstrlen(key)-1;

else

*pos = '\0';                   // Remove the parameter

}

else

{

*pos = '\0';                       // Remove the parameter

}

lstrcat(pos_T(" "));

lstrcat(posurl);

USES_CONVERSION;

result = (HINSTANCEWinExec(T2A(key),showcmd);

}

}

}

return result;

}

4) 在资源视图中,打开Dialog目录下的IDD_ABOUTBOX,在恰当的位置放一个静态文本框控件,将他的ID改为 IDC_LINK,属性框中的caption中添加你需要显示的文字。

5) 找到CAboutDlg定义的源文件(test.cpp),先添加 #include "HyperLink.h" ,再在类CAboutDlg中添加超链接控件的声明 public: CHyperLink  m_cHyperhttp; 再将这个控件和ID为 IDC_LINK的静态文本框关联。实现方法是在类CAboutDlg的成员函数DoDataExchange(CDataExchange* pDX)中添加代码:DDX_Control(pDX,IDC_LINK,m_cHyperhttp)

6) 最后在这个类的初始化(构造)函数中添加:

    CString cStrURL= L"http://www.baidu.com";//网页

    CString cStr=L"mailto:[email protected]";//邮箱

    m_cHyperhttp.SetURL(/*cStrURL*/cStr);//链接/*百度*/邮箱

    m_cHyperhttp.SetUnderline(false);//去掉下划线

注:在默认邮件客户端中打开新邮件窗口,并自动填入收件人地址。若指定多个收件人地址,则收件人地址之间必须用分号或逗号分隔开。运行程序,点击添加静态文本框的区域(有识别)即可链接到设定的网页。

(其他实现方法后续再做总结)

你可能感兴趣的:(超链接,mfc,静态文本控件)