MFC:超链接文本(重绘CStatic)

本文介绍了一个自定义的CXHyperLink控件实现方法,该控件基于CStatic控件扩展,支持设置URL、颜色、下划线等特性,并详细展示了如何在对话框中使用这个控件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

头文件 XHyperLink.h:

#ifndef XHYPERLINK_H
#define XHYPERLINK_H
extern UINT WM_XHYPERLINK_CLICKED;

class CXHyperLink : public CStatic
{
public:
    CXHyperLink();
    virtual ~CXHyperLink();

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

public:
    void SetURL(CString strURL);
    CString GetURL() const
    {
        return m_strURL;
    }

    void EnableURL(BOOL bFlag) { m_bIsURLEnabled = bFlag; }
    BOOL IsURLEnabled() const { return m_bIsURLEnabled; }

    void SetColours(COLORREF crLinkColour, COLORREF crVisitedColour, COLORREF crHoverColour = -1);

    COLORREF GetLinkColour() const
    {
        return m_crLinkColour;
    }

    COLORREF GetVisitedColour() const
    {
        return m_crVisitedColour;
    }

    COLORREF GetHoverColour() const
    {
        return m_crHoverColour;
    }

    void SetBackgroundColour(COLORREF crBackground);
    COLORREF GetBackgroundColour() const
    {
        return m_crBackground;
    }

    void SetVisited(BOOL bVisited = TRUE);
    BOOL GetVisited() const
    {
        return m_bVisited;
    }

    void SetLinkCursor(HCURSOR hCursor);
    HCURSOR CXHyperLink::GetLinkCursor() const
    {
        return m_hLinkCursor;
    }

    void SetUnderline(int nUnderline = ulHover);
    int GetUnderline() const
    {
        return m_nUnderline;
    }

    void SetAutoSize(BOOL bAutoSize = TRUE);
    BOOL GetAutoSize() const
    {
        return m_bAdjustToFit;
    }

    void SetNotifyParent(BOOL bFlag) { m_bNotifyParent = bFlag; }
    BOOL GetNotifyParent() const { return m_bNotifyParent; }

    void EnableTooltip(BOOL bFlag)
    {
        m_bToolTip = bFlag;
        m_ToolTip.Activate(m_bToolTip);
    }
    BOOL IsTooltipEmabled() const
    {
        return m_bToolTip;
    }

    void SetAlwaysOpenNew(BOOL bFlag)
    {
        m_bAlwaysOpenNew = bFlag;
    }
    BOOL GetAlwaysOpenNew() const
    {
        return m_bAlwaysOpenNew;
    }

    void SetWindowText(LPCTSTR lpszString);

public:
    static HINSTANCE GotoURL(LPCTSTR url, int showcmd,  BOOL bAlwaysOpenNew = FALSE);

public:
    virtual BOOL PreTranslateMessage(MSG* pMsg);
    virtual BOOL DestroyWindow();

protected:
    virtual void PreSubclassWindow();

    static LONG GetRegKey(HKEY key, LPCTSTR subkey, LPTSTR retdata);
    void NotifyParent();
    void PositionWindow();
    void ReportError(int nError);
    void SetDefaultCursor();

protected:
    COLORREF        m_crLinkColour;        // Hyperlink colours
    COLORREF        m_crVisitedColour;
    COLORREF        m_crHoverColour;    // Hover colour
    COLORREF        m_crBackground;        // background color
    CBrush            m_Brush;            // background brush
    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;
    BOOL            m_bIsURLEnabled;    // TRUE = navigate to url
    BOOL            m_bNotifyParent;    // TRUE = notify parent
    BOOL            m_bToolTip;            // TRUE = display tooltip
    BOOL            m_bAlwaysOpenNew;    // TRUE = always open new browser window

protected:
    afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor);
    afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    afx_msg void OnTimer(UINT nIDEvent);
    afx_msg void OnClicked();
    DECLARE_MESSAGE_MAP()
};

#endif //XHYPERLINK_H
源文件 XHyperLink.cpp:
#include "stdafx.h"
#include "XHyperLink.h"
#include "atlconv.h"        // for Unicode conversion

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define TOOLTIP_ID 1

#ifndef IDC_HAND
#define IDC_HAND MAKEINTRESOURCE(32649)   // From WINUSER.H
#endif

UINT WM_XHYPERLINK_CLICKED = ::RegisterWindowMessage(_T("WM_XHYPERLINK_CLICKED"));

BEGIN_MESSAGE_MAP(CXHyperLink, CStatic)
    ON_WM_CTLCOLOR_REFLECT()
    ON_WM_SETCURSOR()
    ON_WM_MOUSEMOVE()
    ON_WM_TIMER()
    ON_CONTROL_REFLECT(STN_CLICKED, OnClicked)
    ON_WM_ERASEBKGND()
END_MESSAGE_MAP()

CXHyperLink::CXHyperLink()
{
    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_strURL          = _T("");
    m_nTimerID        = 100;
    m_bNotifyParent   = FALSE;            // TRUE = notify parent
    m_bIsURLEnabled   = TRUE;            // TRUE = navigate to url
    m_bToolTip        = TRUE;            // TRUE = display tooltip
    m_crBackground    = (UINT) -1;        // set to default (no bg color)
    m_bAlwaysOpenNew  = FALSE;            // TRUE = always open new browser window
}

CXHyperLink::~CXHyperLink()
{
    TRACE(_T("in CXHyperLink::~CXHyperLink\n"));

    if (m_hLinkCursor)
        DestroyCursor(m_hLinkCursor);
    m_hLinkCursor = NULL;
    m_UnderlineFont.DeleteObject();
    if (m_Brush.GetSafeHandle())
        m_Brush.DeleteObject();
}

BOOL CXHyperLink::DestroyWindow()
{
    KillTimer(m_nTimerID);
    return CStatic::DestroyWindow();
}

BOOL CXHyperLink::PreTranslateMessage(MSG* pMsg)
{
    m_ToolTip.RelayEvent(pMsg);
    return CStatic::PreTranslateMessage(pMsg);
}

void CXHyperLink::PreSubclassWindow()
{
    DWORD dwStyle = GetStyle();
    ::SetWindowLong(GetSafeHwnd(), GWL_STYLE, dwStyle | SS_NOTIFY);

    if (m_strURL.IsEmpty())
        GetWindowText(m_strURL);

    CString strWndText;
    GetWindowText(strWndText);
    if (strWndText.IsEmpty())
    {
        ASSERT(!m_strURL.IsEmpty());    // Window and URL both NULL. DUH!
        SetWindowText(m_strURL);
    }

    CFont* pFont = GetFont();
    if (!pFont)
    {
        HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
        if (hFont == NULL)
            hFont = (HFONT) GetStockObject(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 = (BYTE) TRUE;
    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
    if (m_bToolTip)
    {
        CRect rect;
        GetClientRect(rect);
        m_ToolTip.Create(this);
        m_ToolTip.AddTool(this, m_strURL, rect, TOOLTIP_ID);
    }

    CStatic::PreSubclassWindow();
}

void CXHyperLink::OnClicked()
{
    m_bOverControl = FALSE;
    int result = HINSTANCE_ERROR + 1;
    if (m_bIsURLEnabled)
    {
        result = (int)GotoURL(m_strURL, SW_SHOW, m_bAlwaysOpenNew);
    }

    m_bVisited = (result > HINSTANCE_ERROR);
    if (!m_bVisited)
    {
        MessageBeep(MB_ICONEXCLAMATION);     // Unable to follow link
        ReportError(result);
    }
    else
    {
        SetVisited();                        // Repaint to show visited colour
    }

    NotifyParent();
}

#ifdef _DEBUG
HBRUSH CXHyperLink::CtlColor(CDC* pDC, UINT nCtlColor)
#else
HBRUSH CXHyperLink::CtlColor(CDC* pDC, UINT /*nCtlColor*/)
#endif
{
    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);

    if (m_Brush.GetSafeHandle())
    {
        pDC->SetBkColor(m_crBackground);
        return (HBRUSH) m_Brush;
    }
    else
    {
        return (HBRUSH)GetStockObject(NULL_BRUSH);
    }
}

void CXHyperLink::OnMouseMove(UINT nFlags, CPoint 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(nFlags, point);
}

void CXHyperLink::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 CXHyperLink::OnSetCursor(CWnd* /*pWnd*/, UINT /*nHitTest*/, UINT /*message*/)
{
    if (m_hLinkCursor)
    {
        ::SetCursor(m_hLinkCursor);
        return TRUE;
    }
    return FALSE;
}

BOOL CXHyperLink::OnEraseBkgnd(CDC* pDC)
{
    CRect rect;
    GetClientRect(rect);
    if (m_crBackground != (UINT)-1)
        pDC->FillSolidRect(rect, m_crBackground);
    else
        pDC->FillSolidRect(rect, ::GetSysColor(COLOR_3DFACE));

    return TRUE;
}

void CXHyperLink::SetURL(CString strURL)
{
    m_strURL = strURL;

    if (::IsWindow(GetSafeHwnd()))
    {
        PositionWindow();
        m_ToolTip.UpdateTipText(strURL, this, TOOLTIP_ID);
    }
}

void CXHyperLink::SetColours(COLORREF crLinkColour, COLORREF 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();
    }
}

void CXHyperLink::SetBackgroundColour(COLORREF crBackground)
{
    m_crBackground = crBackground;
    if (m_Brush.GetSafeHandle())
        m_Brush.DeleteObject();
    m_Brush.CreateSolidBrush(m_crBackground);
}

void CXHyperLink::SetVisited(BOOL bVisited /* = TRUE */)
{
    m_bVisited = bVisited;

    if (::IsWindow(GetSafeHwnd()))
        Invalidate();
}

void CXHyperLink::SetLinkCursor(HCURSOR hCursor)
{
    m_hLinkCursor = hCursor;
    if (m_hLinkCursor == NULL)
        SetDefaultCursor();
}

void CXHyperLink::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;
}

void CXHyperLink::SetAutoSize(BOOL bAutoSize /* = TRUE */)
{
    m_bAdjustToFit = bAutoSize;

    if (::IsWindow(GetSafeHwnd()))
        PositionWindow();
}

void CXHyperLink::SetWindowText(LPCTSTR lpszString)
{
    ASSERT(lpszString);
    if (!lpszString)
        return;
    CStatic::SetWindowText(_T(""));
    RedrawWindow();
    CStatic::SetWindowText(lpszString);
    PositionWindow();
}

void CXHyperLink::PositionWindow()
{
    if (!::IsWindow(GetSafeHwnd()) || !m_bAdjustToFit)
        return;

    CRect WndRect, ClientRect;
    GetWindowRect(WndRect);
    GetClientRect(ClientRect);

    ClientToScreen(ClientRect);

    CWnd* pParent = GetParent();
    if (pParent)
    {
        pParent->ScreenToClient(WndRect);
        pParent->ScreenToClient(ClientRect);
    }

    CString strWndText;
    GetWindowText(strWndText);

    CDC* pDC = GetDC();
    CFont* pOldFont = pDC->SelectObject(&m_UnderlineFont);
    CSize Extent = pDC->GetTextExtent(strWndText);
    pDC->SelectObject(pOldFont);
    ReleaseDC(pDC);

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

    DWORD dwStyle = GetStyle();

    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
        WndRect.right = WndRect.left + Extent.cx;

    SetWindowPos(NULL, WndRect.left, WndRect.top, WndRect.Width(), WndRect.Height(), SWP_NOZORDER);
}

void CXHyperLink::SetDefaultCursor()
{
    if (m_hLinkCursor == NULL)
    {
        TRACE(_T("loading from IDC_HAND\n"));
        m_hLinkCursor = AfxGetApp()->LoadStandardCursor(IDC_HAND);

        if (m_hLinkCursor == NULL)
        {
            TRACE(_T("loading from winhlp32\n"));

            // Get the windows directory
            CString strWndDir;
            GetWindowsDirectory(strWndDir.GetBuffer(MAX_PATH), MAX_PATH);
            strWndDir.ReleaseBuffer();

            strWndDir += _T("\\winhlp32.exe");

            HMODULE hModule = LoadLibrary(strWndDir);
            if (hModule)
            {
                HCURSOR hHandCursor = ::LoadCursor(hModule, MAKEINTRESOURCE(106));
                if (hHandCursor)
                {
                    m_hLinkCursor = CopyCursor(hHandCursor);
                }
                FreeLibrary(hModule);
            }
        }
    }
}

LONG CXHyperLink::GetRegKey(HKEY key, LPCTSTR subkey, LPTSTR retdata)
{
    HKEY hkey;
    LONG retval = RegOpenKeyEx(key, subkey, 0, KEY_QUERY_VALUE, &hkey);

    if (retval == ERROR_SUCCESS)
    {
        long datasize = MAX_PATH;
        TCHAR data[MAX_PATH];
        RegQueryValue(hkey, NULL, data, &datasize);

        _tcscpy_s(retdata, MAX_PATH + 1, data);

        RegCloseKey(hkey);
    }

    return retval;
}

void CXHyperLink::ReportError(int nError)
{
#ifdef XHYPERLINK_REPORT_ERROR

    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 = "Unable to open hyperlink:\n\n" + str;
    AfxMessageBox(str, MB_ICONEXCLAMATION | MB_OK);

#else

    UNUSED_ALWAYS(nError);

#endif    // XHYPERLINK_REPORT_ERROR
}

void CXHyperLink::NotifyParent()
{
    if (m_bNotifyParent)
    {
        CWnd *pParent = GetParent();
        if (pParent && ::IsWindow(pParent->m_hWnd))
        {
            pParent->SendMessage(WM_XHYPERLINK_CLICKED, GetDlgCtrlID());
        }
    }
}

HINSTANCE CXHyperLink::GotoURL(LPCTSTR url, int showcmd, BOOL bAlwaysOpenNew /*= FALSE*/)
{
    if (!url || url[0] == _T('\0'))
        return (HINSTANCE) HINSTANCE_ERROR + 1;

    TCHAR key[MAX_PATH*2];

    TCHAR *verb = _T("open");
    if (bAlwaysOpenNew)
        verb = _T("new");
    HINSTANCE result = ShellExecute(NULL, verb, url, NULL,NULL, showcmd);

    if ((UINT)result <= HINSTANCE_ERROR)
    {
        if (GetRegKey(HKEY_CLASSES_ROOT, _T(".htm"), key) == ERROR_SUCCESS)
        {
            _tcscat_s(key, _T("\\shell\\open\\command"));

            if (GetRegKey(HKEY_CLASSES_ROOT,key,key) == ERROR_SUCCESS)
            {
                TCHAR *pos;
                pos = _tcsstr(key, _T("\"%1\""));
                if (pos == NULL)
                {
                    pos = _tcsstr(key, _T("%1"));        // Check for %1, without quotes
                    if (pos == NULL)                    // No parameter at all...
                        pos = key + _tcslen(key)-1;
                    else
                        *pos = _T('\0');                // Remove the parameter
                }
                else
                {
                    *pos = _T('\0');                    // Remove the parameter
                }

                _tcscat(pos, _T(" "));
                _tcscat(pos, url);

                USES_CONVERSION;
                result = (HINSTANCE) WinExec(T2A(key),showcmd);
            }
        }
    }

    return result;
}

用法:

在对话框头文件中添加一个继承CXHyperLink的变量:    CXHyperLink m_ctrlWebStatic;

m_ctrlWebStatic.SetWindowText(_T("百度"));
m_ctrlWebStatic.SetURL(_T("www.baidu.com"));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值