Hyperlink class (3)

This class provides a window which supports an image, or a
piece of text, or both, and which can be clicked. The window
provides feedback as you move the mouse over it. Clicking the
window acts like double-clicking a file in Windows Explorer, in
that it will open the specified document or folder, or run the
specified program, or launch a browser and go to the specified
URL, or launch a mail client to send an e-mail to the specified
address. It is intended for use mostly as a link to an URL or
e-mail address, but can be used for other purposes such as
launching a ReadMe file. Although this is its main purpose, it is
possible to derive a new class from CHyperlink and
override the OnClick() method so that you can perform your
own action when the left mouse button is clicked. A similar
override (OnRClick() ) is provided for clicking the right
mouse button, although the default does nothing. You might want
to display a popup menu when the user right-clicks.

There are other hyperlink classes on CodeGuru at the moment,
but the others don’t seem to support changing the image at run time; mine is
slightly more configurable, and is not limited to dialogue boxes (it will
work on form views and other windows, with some restrictions on window
colour mentioned in the documentation) or URLs (firing up a ReadMe.TXT on
the hard drive, for example). Mine makes more effort to allow the appearance
to be changed, i.e., text alignment and positioning; the fact that it can
support text AND / or an image rather than one or the other only; the
picture can be loaded transparently; easier font manipulation, etc. It also
supports the ability to derive from it and override the behaviour when you
left or right click – so you can produce a pop-up menu, for example, or have
it open a different window (in your app, not necessarily a browser window)
instead of the default ‘go to URL’ behaviour.

The image can be from a resource in your project, or from a
file. It can be loaded transparently, if desired – the first
pixel will be taken as the background colour to make transparent.
Note, though, that for this to work your parent window must not
change the background brush or do any painting over the
background which changes its colour from the default (as chosen
in the display properties ‘Appearance’ tab). Only bitmaps are
supported in this revision of the class. You do not have to have
an image – by default it has none. Note also, though, that the
larger the image gets, the more it will flicker as you move the
mouse on or off of it – keep it fairly small.

The accompanying text, if any, can be aligned to the left,
right or centre; it can be positioned above, below or
superimposed over the image at the top, middle or bottom. It can
be wrapped (the default), or you can force it not to wrap. Its
font can be user-selected, or you can apply simple discrete
changes such as size, font name, effects (only bold or italic
supported), or both. Note, though, that for this to work you must
use a TrueType font and you must set the AllowModsToFont
flag. If you have a font which is not TrueType (for example, the
default if you select no font of your own is System), the tweaks
to the font will have no effect even if the flag is set, since
the font can’t support those changes. You do not have to have
text at all. Note, though, that if you attempt to have no image
and no text either, it will be forced to have text – if you have
set the text to an empty string, it will default to ‘Click here’.

The highlight can be the image only (it gains a border in the
active text colour), the text only (it changes to the active text
colour and gains an underline), or both. The colours for the
inactive text, active text and (text) background can be selected,
including transparent for the background.

The target of the link does not need to be explicitly set (by
default, there is none). If the text of the hyperlink (whether
text is being displayed or not) represents a valid URL / document
/ executable / e-mail address (basically, anything which can be
launched from Windows Explorer), that text will be used as the
link target. For an e-mail address (anything with ‘@’ in it),
‘mailto:’ will be added to the front if necessary. You can, of
course, set any link you want. If the link cannot be activated
(no program associated with the file type, for example), clicking
the link will have no effect.

All of these parameters can be changed once the window is
showing; the change will be reflected immediately. You can find
out how big the smallest window needed to show the full hyperlink
with the current settings must be by calling CalculateRequiredSize()
with a CRect object – but the window MUST have already
been created when you call this, otherwise you will get an
assertion (it does not have to be showing, though). This allows
you to find out how much space is needed so that you can plan
around it.

 

Supported methods:

void CalculateRequiredSize(CRect& rctHyperlink)
Call this once the settings have been entered and the hyperlink
object has been created, but before it is shown, to determine how
much space it requires to show fully. If you supply more space
than the window requires, the hyperlink area will be centred. If
you do not supply enough space, it will still be centred but will
be clipped outside the window. Note that no matter how big the
window you create is, the link will only appear active if the
mouse is moved over the image or the text. For the text, moving
anywhere within the rectangle which fully encloses the text will
cause the link to appear active – if this rectangle is narrower
than the image, then the whole width of the image is part of the
active area – I might change this behaviour if people feel it
should only be as wide as the text. Note, though, that if the
text wraps and some lines are smaller than others, the active
rectangle is ALWAYS at least the width of the longest line – this
would be near impossible to change.

void OnClick(void) (override)
Called when the left mouse button is clicked over the image or
text. The default action is to activate the link specified by the
object.

void OnRClick(void) (override)
Called when the right mouse button is clicked over the image or
text. There is no default action.

Note: The window uses the standard CWnd Create() method.
This is designed so that you can change the window class if
desired, although pay attention to the information given in
SetTransparentImage()
regarding the colour of the window background.

The text which appears in the hyperlink is the standard
window caption, so either specify a caption in the
Create()
call or call
SetWindowText() on the object.

 

Image Functions

void GetBitmapRect(CRect& rctBitmap)
Use this to retrieve the rectangle occupied by the bitmap. Note
that if the text is superimposed over the top of the image, this
rectangle will overlap that returned by GetTextRect().

void SetBitmapFilename(CString strFilename)
Sets the full path and filename of the bitmap to use. It can be
an empty string to remove any image from the hyperlink. This
method and SetBitmapID() are mutually exclusive – calling
this method also removes any bitmap ID currently stored. Default
is an empty string.

void SetBitmapID(UINT uID)
Sets the project resource ID of the bitmap to use. It can be 0 to
remove any image from the hyperlink. This method and SetBitmapFilename()
are mutually exclusive – calling this method also removes any
bitmap filename currently stored. Default is 0.

void SetNoBitmap(void)
An alternative method to remove any image from the hyperlink.
This removes any bitmap resource ID or filename currently stored.

void SetTransparentBitmap(BOOL bTransparent = TRUE)
Call this to indicate whether or not the bitmap should be
displayed transparently. This is achieved by taking the colour of
the first pixel of the bitmap and replacing all further
occurrences of that colour with the window background colour. For
CDialog-derived or CFormView-derived windows, this
is the button face colour as chosen in the display properties
‘Appearance’ tab. For any other window base class, this is the
normal window background colour chosen in Appearance. CPropertyPage
is CDialog-derived, and so will correctly display the
background – if you want to put one of these windows on the CPropertySheet
itself, you will not be able to use transparency since CPropertySheet
is not derived from CDialog. Other special window classes
may have the same problem – always check the class hierarchy to
determine if transparency will work. Default is FALSE.

 

Text Functions

void GetTextRect(CRect& rctText)
Use this to retrieve the rectangle occupied by the text. Note
that if the text is superimposed over the top of the image, this
rectangle will overlap that returned by GetBitmapRect().

COLORREF GetBackColour(void)
COLORREF GetTextColour(void)
COLORREF GetActiveTextColour(void)

These are used to retrieve the colours used for the background of
the text area, for the inactive text, and for the active text
(mouse is over the hyperlink). Note that the background colour
can be HL_BACKCOLOUR_TRANSPARENT. Note also that if the text is
being superimposed over the image (position is top, middle or
bottom), then the background of the text is transparent
regardless of the background colour setting – but the actual
setting will be returned anyway. See below for defaults.

void SetBackColour(COLORREF dwColour)
void SetTextColour(COLORREF dwColour)
void SetActiveTextColour(COLORREF dwColour)

These are used to change the colours used for the background of
the text area, for the inactive text, and for the active text
(mouse is over the hyperlink). The background colour can be
HL_BACKCOLOUR_TRANSPARENT to leave the pixels underneath blank
areas unaltered. Note that if the text is being superimposed over
the image (position is top, middle or bottom), then the
background of the text is transparent regardless of the
background colour setting – but the actual setting is retained
anyway. Note also that the border used to highlight the image is
always the same as the active text colour. Default background
colour is transparent. Default inactive text colour is black.
Default active text colour is bright green.

void SetTextPosition(UINT uPosition, UINT uAlignment)
Indicates where the text should appear, and how. Position can be
HL_TEXTPOS_NONE (no text showing), HL_TEXTPOS_ABOVE or
HL_TEXTPOS_BELOW for separate text, or HL_TEXTPOS_TOP,
HL_TEXTPOS_MIDDLE or HL_TEXTPOS_BOTTOM for text superimposed over
the image. Alignment can be HL_TEXTALIGN_LEFT,
HL_TEXTALIGN_CENTRE or HL_TEXTALIGN_RIGHT. Default position is
below. Default alignment is centred.

Note that if the text is narrower than the image, the text
will be aligned relative to the image as expected; but if the
text is wider than the image, the image will be aligned relative
to the text – therefore, the text will appear centred in the
hyperlink window with the image’s right-hand edge aligned with
the text’s right-hand edge (for HL_TEXTALIGN_RIGHT). Similar
rules apply if the text is taller than the image. The rectangle
returned by CalculateRequiredSize() is ALWAYS the smallest
window which fully encloses the text and image, with these rules
obeyed, and will not always use the image as the centrepiece –
therefore, care must be taken when designing the image and text
for this window – the demo program should be able to give you a
good idea of how this works.

void SetTextWrapping(BOOL bWrap = TRUE)
Indicates whether text is allowed to wrap or not. Carriage
returns and line feeds can be embedded in the string to force new
lines, but only if wrapping is enabled – they will show as
undefined characters if wrapping is disabled. It is not advisable
to prevent wrapping, since it could well result in the text being
clipped outside the window. Default is TRUE.

void SetFontToUse(CFont *pFont, BOOL bAllowMods = FALSE)
Allows a custom font to be used for the text. Parameter can be
NULL to revert back to the default window font. The second
parameter says whether the font (either the one passed in or the
default being used) can be modified by calls to the font
manipulation routines. Default font is NULL (uses default window
font). Default for modifying the font is FALSE.

void AllowModsToFont(BOOL bAllowMods = TRUE)
Indicates whether or not the default window font or user-supplied
font can be modified using the discrete font methods. You do NOT
have to call this before you call the other methods, but you will
have to call it before the hyperlink is displayed for the other
font settings to have any effect. You can, of course, call it
while the hyperlink is showing, in which case the font changes
(if any) will be reflected immediately. Note that if the font
being used is not TrueType and can’t handle changes in
attributes, this method will have no effect. Default is FALSE.

void SetFontName(CString strName)
Specifies the typeface name of the current font, and should be
something like "Arial", "Comic Sans MS",
"Times New Roman", etc. It can be an empty string to
leave the font typeface as the default window font or
user-supplied font specifies. Only has an effect if the AllowModsToFont
flag is set. If that is set, it can modify the font whether it is
the default window font or your user-supplied font. Default is no
name (no mods).

void SetFontSize(UINT uHeight, UINT uWidth = 0)
Changes the size of the current font. Width can be 0 to let the
system choose the best width in proportion to the height. Height
can be 0 to leave the font size as the default window font or
user-supplied font specifies. Only has an effect if the AllowModsToFont
flag is set. If that is set, it can modify the font whether it is
the default window font or your user-supplied font. Default is 0
for both parameters (no mods).

void SetFontAttributes(BOOL bBold, BOOL bItalic)
Changes the style of the current font. The constants HL_FONTBOLD,
HL_FONTNOTBOLD, HL_FONTITALIC and HL_FONTNOTITALIC can be used,
or just plain TRUE or FALSE. Only has an effect if the AllowModsToFont
flag is set. If that is set, it can modify the font whether it is
the default window font or your user-supplied font. Default is
FALSE for both parameters. Notice that there is no way to leave
the parameters alone with this call – if you have made a previous
call to this method which changes these attributes, you will have
to call this method again to undo that change. It is not much of
a problem. Note also that you cannot control the underline – it
is built in.

 

Miscellaneous Functions

void SetHighlightStyle(UINT uStyle)
Changes the feedback given when the mouse moves over the
hyperlink. It can be HL_HIGHLIGHT_TEXTONLY,
HL_HIGHLIGHT_IMAGEONLY or HL_HIGHLIGHT_TEXTANDIMAGE. The colour
of the text will change regardless of these settings, but you can
set the active text colour to the same as the inactive text
colour to stop the highlight of the text – the image will still
get a border, though, unless you specify highlighting the text
only. Default is to highlight both.

void SetLinkTarget(CString strTarget)
Sets the target to use when the link is clicked. This can be a
folder name, such as "C:\TEMP", to display the
folder’s contents; it can be any file whose file type has an
associated program within Windows Explorer, such as
"C:\IMAGES\STORM.GIF", to display or act upon that
file; it can be an executable or batch file, such as
"C:\TEMP\TESTPROG.EXE", to run that file; it can be
an URL, such as "http://www.codeguru.com", to launch
the default browser and go to that URL; or it can be an e-mail
address, such as "[email protected]", to launch a
mail client to start a message to that address. Note that the
e-mail address does not need to include ‘mailto:’ to work – the
hyperlink code will add that if necessary. The link does not need
to be explicitly set; it will use the hyperlink’s text (whether
text is being displayed or not) as the link, and therefore you
can just set the caption to a valid value. Default is an empty
string. Long pathnames and filenames are fully supported.

HCURSOR SetActiveCursor(HCURSOR hCursor)
If you don’t like the small hand cursor which currently appears
when the mouse is moved over the hyperlink, you can use this to
set your own cursor. The cursor must be appropriate for the
user’s display type, otherwise it won’t show – be careful.
Although the internal hand cursor is automatically destroyed when
the hyperlink object is destroyed, you are responsible for
destroying your own cursors, even if you set them into the
hyperlink object using this method – it will not delete user
cursors. The value returned is the previous user cursor, or NULL
if this is the first time you have set a user cursor since this
hyperlink object was created.

 

Using CHyperlink

Use it just like any other child control. An example of how to
call Create() from within a CDialog or CFormView
(use OnInitialUpdate() in place of OnInitDialog() )
is:


BOOL CMyDlg::OnInitDialog(void)
{
    CRect   rctWindow(0, 0, 100, 100);

    m_wndHyperlink.Create(NULL,"Click here to readrnthe ReadMe",
            WS_CHILD, rctWindow, this, 9999);

    m_wndHyperlink.SetBitmapID(ID_BMP_DOCUMENTSYMBOL);
    m_wndHyperlink.SetLinkTarget("ReadMe.TXT");
    m_wndHyperlink.SetTextColour(0x000000FF); // Bright red.
    m_wndHyperlink.SetActiveTextColour(0x00FF00FF); // Bright magenta.
    m_wndHyperlink.AllowModsToFont();
    m_wndHyperlink.SetFontName("Times New Roman");
    m_wndHyperlink.SetFontSize(18); // Width is best-fit.
    m_wndHyperlink.SetFontAttributes(HL_FONTNOTBOLD, HL_FONTITALIC);
    m_wndHyperlink.SetTextPosition(HL_TEXTPOS_ABOVE, HL_TEXTALIGN_CENTRE);

    m_wndHyperlink.ShowWindow(SW_SHOWNORMAL);
}

Downloads

Demo project – 33Kb
Source code – 7Kb

The demo demonstrates most of the features of the class, but
not quite all. It should be enough to get you going. It relies on
Comic Sans MS font being installed on your machine, although it
will choose a suitable substitute from your machine as necessary.

More by Author

Must Read