HyperLinks in RTF

by Radek Červinka 4. May 2012 23:57

For my program I need hyperlinks in TRichEdit with hidden address part - emulate simple web address. For example something like Delphi, you see text but link is different (someone call this user friendly hyperlinks). When user click on link, I catch this action and do something other.

TRichEdit starting with version 2 (maybe Windows 2000) can display automatic links (for example: when type http://delphi.cz, RichEdit show this as link, starting with version 3 protocol is not required - www.delphi.cz). For your information: description of richedit version features.

Delphi including wrapper for version 2 (but version 3 working without problems). Howto for version 4.1 is (using-richedit-4-1-with-d2010). But I think that code in this article is better (you don't copy VCL).

But there is a problem for me. Version 4.1 (XP+) is first version with direct support for "user friendly" links. Support = can show, but you must hardcode RTF. There is nice article about this topic: richedit friendly name hyperlinks.

For simple hyperlinks is the best solution to use TJvRichEdit with property AutoURLDetect - see TJvRichEdit from JVCL.

For RichEdit version 4 you can use this code, based on TJvCustomRichEdit. Unicode Delphi is required because version 4 is unicode based (with ansi Delphi there will be much more work). Minimal windows version is Windows XP.

Inserting link

Link can be inserted with injecting RTF (you can see how nice JvRichEdit support this). Example code insert RTF codes, but rest of text is preserved:

procedure TForm1.Button2Click(Sender: TObject);
var
  Stream : TMemoryStream;
const
 cHyperlink = '{\rtf1{\field {\*\fldinst {HYPERLINK "%s" }}{\fldrslt {\ul %s }}}}';
var
  s: AnsiString;
begin
 Stream := TMemoryStream.Create;
 try
   s := Format(cHyperLink, ['http://jvcl.sourceforge.net', 'JVCL']);

   Stream.Write(PChar(s)^, Length(s));
   Stream.Position := 0;
   rtf.StreamFormat := sfRichText;

   rtf.StreamMode := [smSelection, smPlainRtf];
   rtf.Lines.LoadFromStream(Stream);
   rtf.StreamMode := [];
 finally
   Stream.Free;
 end;
end;

Important: See AnsiString in example. If you want unicode, you must insert BOM bytes at the beginning (this is very important and I spent about 2 hours with this).

unit RichEdit4;

interface
uses
  jvRichEdit, ComCtrls, Controls;
var
FMoudlEdit:THandle;
const
  RichEdit41ModuleName = 'Msftedit.dll';
  RichEdit41ClassName = 'RichEdit50W';

type
TRichEdit41=class(TJvCustomRichEdit)
private
protected
    procedure CreateParams(var Params: TCreateParams);override;
public
  published
    property AdvancedTypography;
    property Align;
    property Alignment;
    property AutoAdvancedTypography;
    property AutoSize default False;
    property AutoURLDetect;
    property AutoVerbMenu;
    property AllowObjects;
    property AllowInPlace;
    property Anchors;
    property BevelEdges;
    property BevelInner;
    property BevelKind default bkNone;
    property BevelOuter;
    property BiDiMode;
    property BorderWidth;
    property DragKind;
    property BorderStyle;
    property ClipboardCommands;
    property Color;
    property DragCursor;
    property DragMode;
    property Enabled;
    property Flat;
    property Font;
    property ForceUndo;
    property HideSelection;
    property HideScrollBars;
    property HintColor;
    property Title;
    property ImeMode;
    property ImeName;
    property Constraints;
    property ParentBiDiMode;
    property LangOptions;
    property Lines;
    property MaxLength;
    property OLEDragDrop;
    property ParentColor;
    property ParentFlat;
    property ParentFont;
    property ParentShowHint;
    property PlainText;
    property PopupMenu;
    property ReadOnly;
    property ScrollBars;
    property SelectionBar;
    property SelText;
    property ShowHint;
    property StreamFormat;
    property StreamMode;
    property TabOrder;
    property TabStop;
    property UndoLimit;
    property UseFixedPopup;
    property Visible;
    property WantTabs;
    property WantReturns;
    property WordSelection;
    property WordWrap;
    property Zoom; // added by J.G. Boerema
    property OnChange;
	property OnClick;
    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;
    property OnContextPopup;
    property OnConversionProgress;
    property OnEndDock;
    property OnStartDock;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property OnMouseDown;
    property OnMouseMove;
    property OnMouseUp;
    property OnMouseWheel;
    property OnMouseWheelDown;
    property OnMouseWheelUp;
    property OnProtectChange; { obsolete }
    property OnProtectChangeEx;
    property OnResizeRequest;
    property OnSaveClipboard;
    property OnSelectionChange;
    property OnStartDrag;
    property OnTextNotFound;
    property OnCloseFindDialog;
    property OnDragAllowed;
    property OnGetDragDropEffect;
    property OnQueryAcceptData;
    property OnURLClick;
    property OnMouseEnter;
    property OnMouseLeave;
    property OnParentColorChange;
    property OnVerticalScroll;
    property OnHorizontalScroll;
    // From CCR
    property OnInPlaceActivate;
    property OnInPlaceDeactivate;
end;

implementation
uses
  Windows, SysUtils;

procedure TRichEdit41.CreateParams(var Params: TCreateParams);
begin
if FMoudlEdit = 0 then
begin
    FMoudlEdit := LoadLibrary(RichEdit41ModuleName);
    if FMoudlEdit <= HINSTANCE_ERROR then FMoudlEdit := 0;
end;

inherited CreateParams(Params);

CreateSubClass(Params, RichEdit41ClassName);
with Params do
begin
//
end;
end;

initialization
finalization
  if FMoudlEdit <> 0 then FreeLibrary(FMoudlEdit);
end.

Tags:

Components

Comments are closed