An improved hyperlink control

The CHyperlink example project dialog  Download Source Code and Demo


Introduction

After having tried some hyperlink controls, I felt the necessity to write my own control that was more flexible and had a more consistent programming interface. My intention was to create an hyperlink that could be used not only with text but also with icons and bitmaps, and that supported dynamic modification of its style and font. Moreover, I wanted that my control had the look and feel of an usual web page hyperlink. Why cannot hyperlinks have the input focus? Why cannot I move the focus from an hyperlink to another using the "tab" key as if they were normal dialog buttons and activate them pressing the spacebar?

Well, here is an hyperlink control that makes all these beautiful things possible. It was realized with the help of some articles written by Paul DiLascia on MSJ and Stuart Patterson on Windows Developer's Journal. It's rightful to tell that I think at my control as an improvement of the homonymous control developed by Chris Maunder, whose work was excellent.

Comparison with existing hyperlinkcontrols

In this section, I summarize the main features that distinguish my control from other similar controls you can find in this site. I hope this will help you to decide which code suits your needs better.

  • You can set the hyperlink on any type of static control (bitmaps and icons above all!).
  • The hyperlink can get the input focus (a special color is used to show the focus state) and can be activated with the spacebar like normal dialog buttons.
  • The hyperlink maintains the correct aspect when you change its style, text or font.
  • Control resizing works correctly even if it has a nonclient border.
  • Simplified programming interface.

Using the control

To use the hyperlink control, first create a static control with your resource editor (text, icon, or bitmap), then give it a control ID (e.g. IDC_HYPERLINK). If you want your control to be able to get the focus, you have to set the "tabstop" style, since for static controls it is not the default. I advice to set it only with text controls, which can change color when focused. Then, attach it to a member variable of type CHyperLink (ClassWizard makes this very simple). Don't forget to include the "HyperLink.h" file in your dialog class implementation file. The member function SetURL() allows to specify the link URL. However, setting an explicit URL is not obligatory for text controls: if you specify a caption text, this is taken as URL. Vice versa, if you don't specify a caption text, but 'manually' set the URL with SetURL(), then the text is set equal to the URL. For all other types of static controls instead, you have the responsibility to set the URL using SetURL() (usually in the OnInitDialog() member function of your dialog class), or otherwise a debug assertion will occur. The default link colors are blue, dark cyan, purple and red, respectively for normal, focused, visited and "cursor over" states.

Customizing the hyperlink

The hyperlink styles are static class constants. They are shown in the following table

Style Meaning Default
StyleUnderline The link is underlined YES
StyleAutoSize The control resizes itself automatically when text or font changes YES
StyleUseHover The link use the "hand over" color NO
StyleDownClick The link is activated when mouse button "goes down" NO
StyleGetFocusOnClick The link gets the input focus when clicked NO
StyleNoHandCursor The link doesn't use the default hand cursor NO
StyleNoActiveColor The link doesn't change color when activated (i.e. when it get the focus) NO
  • To modify link style call the member function ModifyLinkStyle(dwRemove, dwAdd) where dwRemove is a bitwise OR of the styles you want to remove and dwAdd is a bitwise OR of the styles you want to add (strange but true!).

Setting the StyleAutoSize, the control will automatically resize itself to fit the size of the caption (even while it is visible!). The resizing occurs also if you set a new window caption text or font. Remember that this style applies to text controls only. For icons and bitmaps, auto-resizing is a default characteristic, and StyleAutoSize becomes meaningless. The resizing will honour the SS_CENTERIMAGE, SS_LEFT, SS_RIGHT and SS_CENTER static control flags. If you don't want the style change to be dinamically applied to the control, ModifyLinkStyle() has a third optional boolean parameter: just set it to FALSE (the default is TRUE).

  • To mark/unmark a link as visited call the SetVisited() member function.
  • To modify link colors, call the SetColors() member function, in the following way:
    SetColors(crLinkColor, crActiveColor, crVisitedColor, crHoverColor);

The last parameter is optional: if not specified the system default highlight color will be used. Alternatively, fill a HYPERLINKCOLORS structure (a typedef defined in "HyperLink.h") and pass it to the overloaded version of SetColors(). This structure is also used by GetColors() to retrieve the current link colors.
SetColors() is a static member function: the color change has effect on all instances of CHyperLink and you need to redraw your control in order that the new colors to be applied.

  • To set a mouse cursor different from the default hand, call SetLinkCursor(). This function requires a unique argument: the handle of a new cursor. It is a static function and has effect on all hyperlinks, just like SetColors().

All the "set" functions above have their natural "get" counterparts. See the following section.

Operations for CHyperLink:

Here is an excerpt from the class declaration


// Operations
public:	
	static void GetColors(HYPERLINKCOLORS& linkColors);

	static HCURSOR GetLinkCursor();
	static void SetLinkCursor(HCURSOR hCursor);
    
	static void SetColors(COLORREF crLinkColor, COLORREF crActiveColor, 
	   		   COLORREF crVisitedColor, COLORREF crHoverColor = -1);
	static void SetColors(HYPERLINKCOLORS& colors);

	void SetURL(CString strURL);
	CString GetURL() const;

	DWORD GetLinkStyle() const;
	BOOL ModifyLinkStyle(DWORD dwRemove, DWORD dwAdd, BOOL bApply=TRUE);	
    
	void SetWindowText(LPCTSTR lpszText);
	void SetFont(CFont *pFont);
	
	BOOL IsVisited() const;
	void SetVisited(BOOL bVisited = TRUE);
	
	// Use this if you want to subclass and also set different URL
	BOOL SubclassDlgItem(UINT nID, CWnd* pParent, LPCTSTR lpszURL=NULL) {
		m_strURL = lpszURL;
		return CStatic::SubclassDlgItem(nID, pParent);
	}

Implementation details

Some notes about implementation. I used the MFC message reflection to set the text color for the control (see the ON_WM_CTLCOLOR_REFLECT() macro in the message map). Message reflection can be a very complicated argument. Briefly, many controls notifies some event messages to their parent window, so that the latter has a chance to handle them. When the parent window sends back the message to the control we have the so-called message reflection. This mechanism is well implemented in MFC. Reflected messages appear preceded by an equal sign in ClassWizard.

Reading the code, you may be surprised that the control works without the SS_NOTIFY style. Normally, a static control does not get mouse events unless it has the SS_NOTIFY style. However, as Paul DiLascia asserts, handling the WM_NCHITTEST message and making the OnNcHitTest() functions returns the hit-test value HTCLIENT achieves the same effect as SS_NOTIFY, but requires fewer lines of code and is more reliable than turning on SS_NOTIFY in OnCtlColor because Windows doesn't send WM_CTLCOLOR to bitmap static controls.

For dynamic text and font modification I supplied special versions of SetFont() and SetWindowText() functions. These functions perform their operations while the window is kept hidden to maintain the correct link aspect.

Author's note

I'm continuously working to improve this control. I'll be grateful to you if you mail me your comments, advices, or bug apparition reports!.

Latest additions

  • Link styles are now static class constants.
  • Colors and cursor and their relative get/set functions, are now static class members.
  • Many bug fixes in resizing and color management.

What's new in this release

This release was compiled and tested with Visual C++ 5.00. Uwe Kleim reported me a bug in the ModifyLinkStyle() member function and now it has been fixed. Thanks Uwe!

Last updated: 11 November 1998



Comments

  • clarisonic coupled with in pink blossom type is truly bonny

    Posted by iouwanzi on 06/05/2013 08:04pm

    [url=http://www.miaclarisonicaustralia.org/]clarisonic mia online[/url] Producenter frembringer deres egne beats på nettet åbner ubegrænsede samarbejdsmuligheder med hensyn til designere på et stramt budget. Den særlige udseende tilgængelig er utallige der en bred vifte af friske rekorder på markedet hver dag derude sted. I tilfælde af at du synes at købe overgår, anmeld af din web selskabet samt høre deres varer. Du er i stand til at Google eller måske Ask tilstande såsom “internet-producenter” eller “køb er bedre end online” og masser af troværdige producent internetsider vil helt sikkert producere.En anden tendens jeg opdager i trap rekorder kunne være den store brug af rumklang omkring den primære enhed. Der er typisk en enkelt pind ud værktøj put, der har en velvoksen reverb effekt sige for eksempel en grand violin, guitar, samt synth. I de fleste tilfælde en let melodi, der gentager flere gange samt modulerer op eller ned. Processen mod kaos er meget simpelt, så prøv ikke at under vurdere de grunde, der kan placeres i dette. beats [url=http://www.australiaclarisonic.com/clarisonic-mia]clarisonic mia[/url] Hestekræfter samt reggae hele verden har kombineret såvel som resultatet er den nye Doctor Dre laptop. Med ferier her og også Dr. Dre laptop annoncer viser konstant på tv, er alle spekulerer på, om de skal købe det faktiske H. s.. Misundelse (den bestemte specialiserede navn med den personlige computer).Over-the-ear hovedtelefoner er fantastisk for ejendom bliver opmærksomme samt vejledning i at lukke ud lyde som du sover. On-ear typer bør også være behageligt, sammen med delikat ekstra polstring og robust konstruktion. Bare om de mest væsentlige ting sammen med on-ear design er at sikre, at de er installeret til brug sammen med stikkene i dine gadgets. [url=http://www.miaclarisonicaustralia.org/]clarisonic mia australia[/url] Derudover skal du få en dobbelt-strenget fly adapter sammen med en kvart tomme adapter til brug med dit hjem audio teknik. Endvidere vil en hård skal rejse sag med en tilsluttet karabiner, er beskyttet. Rekorder også komme som har en oprydning klud til at sikre, at de leder efter positive.Skulle du være bekymret for lyd og vises, vil du elske denne særlige laptop. Allerførste, vil denne pc giver dig ekstra at behandle din egen lyd resultat. Der er normalt sofistikerede antal audio muligheder, du vil aldrig afsløre sammen med andre pc’er.Søg efter gadgets er specielt designet til brug med elektriske mp3 enheder. I betragtning af at over-ear typer kan være store, søge efter versioner med neodymium varme. Næsten dine motiver udføre magneter synes vidunderlige, de har en tendens til at være mindre og lettere.

    Reply
  • Glattejern til ethvert behov,Pas pÃ¥ dit GHD glattejern

    Posted by wanzixiao on 05/30/2013 04:52am

    [url=http://www.ghdfladjerntilbud.webs.com/]ghd fladjern tilbud[/url] Alle GHD IV Pink Styler er af høj kvalitet og prisen er meget reasonable.There er forskellige stilarter for dig at select.Key funktioner i GHD Hårudglatningsmiddel omfatter: mere lydhør, dybt affjedret keramiske plader, at varme op endnu hurtigere. Hørbar bip, der fortæller dig, jernet er varmt og klar til brug. Længere og mere holdbar Kablet har et forbedret design for at mindske potentielle skader, som du stil med jern. Auto-justering af spænding betyder, at du kan bruge dit jern i noget land. Sikkerhed funktioner, herunder automatisk slukker efter 15 minutter uden aktivitet, og en gysen funktion, der forhindrer fugt beskadige din strygejern, når de er blevet efterladt i et koldt sted natten over. [url=http://www.glattejernghdpris.webs.com/]glattejern ghd pris[/url] De fleste af damerne blindt har særskilte fodtøj området inde i det vilde hår generelt ender forårsager god skade hovedsagelig blot fordi dybest set afhentning låser inden det vilde hår vedrørende hairstyling. Samt hjælp vedrørende GHD Frizzy hår hår-styling stål, men for at blive urolige denne form for besvær. Først og fremmest fordi de præcise god hår dage Straighener faktisk ekspert produkt, som er helt sikkert desuden nedtonet, der har tendens til at idéen let at have din krøllede hår direkte fundamentalt har tendens til at den høje temperatur i den nøjagtige samme tilgang, fordi det effektivt oplysninger med formindske hoved af hår. [url=http://www.glattejernghd.bloguedobebe.com/]Billigt Glattejern[/url] Din særskilt web-site kan være din person i den vigtigste form for bare at leve netto web-sites inden for de britiske øer denne særlige tilbyder en utrolig mængde af krøllet hår behandling metode variabler ved hjælp af en række forskellige producenter. Disse former for god hår dag krøllet hår produkter igennem flere situationer tilbydes i form af faldende gebyrer. Denne unikke God hår dag Power Suppressor er normalt normalt en stærk tilstrækkeligt godkendt vilde hår terapi om at samle meget følsom med hinanden med sårede Lokker.

    Reply
  • You pine on the side of some tomato basil and mozzarella. To indoor from, these slippers are as well-lighted and manueverable as sneakers.

    Posted by Soaceddew on 04/20/2013 05:21am

    Has upright released several different color Democratic Inneva Woven shoes, Nike recently with another direction to bring shoes with different styling to all [url=http://fossilsdirect.co.uk/glossarey.cfm]nike huarache[/url] eyes. This brings special issue Unfastened Inneva Woven is a Fair-skinned Call of works in the series, represents shoes Italian made the assurance. Latest Safe from Inneva Woven clouded and pornographic are available in two color schemes, to hand-knit Woven vamp in extension to infiltrated Italy's [url=http://markwarren.org.uk/property-waet.cfm]nike air max 90[/url] finest crafts, for the moment gives athletes closed to the foot of relieve, the most distinguished affair is the goal of Free 5 configuration, barefoot be aware it pass on allure cannot be ignored. Nike Disburden Inneva Woven SP White Identify Compact on Walk 16 at outlets about the [url=http://northernroofing.co.uk/roofins.cfm]nike free run uk[/url] trade-mark on the shelves, and on in stock in narrow sort, interested friends should produce results fasten attention to Nike announced the news.

    Reply
  • onMouseMove bug

    Posted by prakashp5562 on 12/17/2006 05:07pm

    Change the font of the dialog to Tahoma 8.  Now on Mousemove you find that - the text gets disturbed.
    
    Resolution: 
    Add 	ON_WM_ERASEBKGND() in the message map
     
    BOOL CHyperLink::OnEraseBkgnd(CDC* pDC) 
    {
        CRect rect;
        GetClientRect(rect);
        pDC->FillSolidRect(rect, ::GetSysColor(COLOR_3DFACE));
    
        return TRUE;
    }

    Reply
  • how to add hyper link in menu item

    Posted by Legacy on 06/03/2003 12:00am

    Originally posted by: khalil

    I want to add hyper link in menu item so plz tell me how i can add hyper link in menu item

    Reply
  • Won't work in About-Dialog.

    Posted by Legacy on 09/04/2002 12:00am

    Originally posted by: P

    Hi

    I tried to use this nice control in an aboutdialog - but it won't work !
    Any ideas how to do that ?

    Thanks
    P

    Reply
  • Hyperlink in a textbox?

    Posted by Legacy on 06/26/2002 12:00am

    Originally posted by: WH

    How can i place a hyperlink in a textbox?

    Reply
  • Load IDC_HAND on Win2k & XP

    Posted by Legacy on 01/04/2002 12:00am

    Originally posted by: Thomas Baust

    First, your control is great.
    
    

    But, it is better to load system's IDC_HAND Cursor on Win2k & XP. If the system can't find IDC_HAND (i.e. Win9x), hLinkCursor will NULL, and simply continue with the orginal code. So i have changed SetDefaultCursor:

    void CHyperLink::SetDefaultCursor()
    {
    if (g_hLinkCursor == NULL) // No cursor handle - load
    {
    HCURSOR hHandCursor = ::LoadCursor(NULL,MAKEINTRESOURCE(32649)); // try to load system cursor
    if (hHandCursor)
    g_hLinkCursor = CopyCursor(hHandCursor);

    if (g_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("\\winhlp32.exe");
    // This retrieves cursor #106 from winhlp32.exe, which is a hand pointer
    HMODULE hModule = LoadLibrary(strWndDir);
    if (hModule) {
    hHandCursor = ::LoadCursor(hModule, MAKEINTRESOURCE(106));
    if (hHandCursor)
    g_hLinkCursor = CopyCursor(hHandCursor);
    }
    FreeLibrary(hModule);
    }
    }
    }

    Reply
  • Error on a DLL

    Posted by Legacy on 08/23/2000 12:00am

    Originally posted by: Rod

    There is an error when I use your code in a DLL.
    
    

    I have to use the line:

    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    So the dll can load its resources.

    It works the first time I load the dialog.

    But the second time it crashes here:

    BOOL CGdiObject::Attach(HGDIOBJ hObject)
    {
    ASSERT(m_hObject == NULL); // only attach once, detach on destroy
    if (hObject == NULL)
    return FALSE;
    CHandleMap* pMap = afxMapHGDIOBJ(TRUE); // create map if not exist
    ASSERT(pMap != NULL);
    pMap->SetPermanent(m_hObject = hObject, this);
    return TRUE;
    }

    Exactly at this line:

    ASSERT(m_hObject == NULL); // only attach once, detach on destroy

    Does any one know why? and how to solve it?

    Reply
  • I would like to use your control to hold multi line text in multi colors.

    Posted by Legacy on 11/03/1999 12:00am

    Originally posted by: Phil

    Please forgive me for hacking your code. I love your control but I want it to do two more things.

    1st display multiple lines of text.
    2nd show at least two colors per line.

    I'm a pretty good C programmer, but a little new to C++ and Windows, so I included my code change in the hopes of getting your opinion.

    Secondly, can the control display more than one color? If so could you give me some hints?

    Thanks.


    void CHyperLink::AdjustWindow()
    {
    ...
    // Get the extent of window text
    CString strWndText;
    GetWindowText(strWndText);

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

    //Code I added starts here.
    //Count the number of line returns
    char* pszLineCount = strWndText.GetBuffer(0);
    short nLineCount = 1;
    while(*pszLineCount != NULL) {
    if(*pszLineCount == '\n')
    nLineCount++;
    pszLineCount++;
    }
    strWndText.ReleaseBuffer();
    //Expand the width by the number of line returns.
    Extent = CSize(Extent.cx , Extent.cy * nLineCount);

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • On-demand Event Event Date: October 29, 2014 It's well understood how critical version control is for code. However, its importance to DevOps isn't always recognized. The 2014 DevOps Survey of Practice shows that one of the key predictors of DevOps success is putting all production environment artifacts into version control. In this webcast, Gene Kim discusses these survey findings and shares woeful tales of artifact management gone wrong! Gene also shares examples of how high-performing DevOps …

Most Popular Programming Stories

More for Developers

RSS Feeds