Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Adding a hyperlink to a RichEdit

Status
Not open for further replies.

cyprus106

Programmer
Apr 30, 2001
654
I can add URL autodetection functionality to a RichEdit easily, but I want to be able to add a hyperlink, (i.e. when the user clicks on something that says:
Go to tek tips
then it will go to the url
How would I go about setting this up?
I've spent the entire day trying and guessing (and failing...) I hope somebody on here has a better idea.
Thanks, Cyprus
 
Hello,

have you solved this riddle already? I want to do the same...
 
a url is a hyperlink, so expanding upon your url detection
should bejust adding to the code.

when user clicks on this ***
and the string equals this ***
do this ***

tomcruz.net
 
Here's my code... I actually grabbed the code from my very basic test project. I've elaborated on it since then, if I remember right, so if something doesn't work let me know and I'll dig into the code I added on to it, because I seem to recall a few small bugs that I worked out of this at one point. When I pulled this back out, I only fired it up, I didn't even click the link but I know it works. I think one of the problems I worked out once was that you couldn't erase the link after you'd put it in. It wouldn't let you backspace it out because it was "protected". I may be remembering wrong, it was a while ago, but this should help. Like i said, if you've got any problems, let me know.


The form has a richedit and a button. That's it.

Code:
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
        ::SendMessage (rich->Handle, EM_SETEVENTMASK, 0 , ENM_LINK|ENM_PROTECTED);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::OnNotify(TMessage &Message)
{
       NMHDR *pNMHDR;
       pNMHDR = (NMHDR *)Message.LParam;

       switch (pNMHDR->code)
       {
               case EN_LINK :
                       OnLink (pNMHDR, (LRESULT *)&Message.Result);
                       break;

               case EN_PROTECTED :
                       OnProtected (pNMHDR, (LRESULT *)&Message.Result);
                       break;

               default :
                       TForm::Dispatch(&Message);
       }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
        DWORD dwStart;

        //get insert position
        if (::SendMessage (rich->Handle, EM_GETSEL, (WPARAM)&dwStart, NULL) == -1)
                return;

	InsertLink (rich->Handle, dwStart, "Go to Tek-Tips", "[URL unfurl="true"]www.tek-tips.com");[/URL]
}
//---------------------------------------------------------------------------
bool __fastcall TForm1::InsertLink(HWND hRich, int nPos, const char *pszTitle, const char *pszURL)
{
	Richedit::CHARFORMAT2 cf2;;
	int nTitleLen, nURLen;
	char *pszLinkBuf = NULL;

        //check if ptrs are valid and pszTitle has 2 chars at least
	if (!pszURL || !pszTitle || !pszTitle[0] || !pszTitle[1])
		return FALSE; //title too short

        //get lengths of title & URL
	nTitleLen = strlen (pszTitle);
	nURLen = strlen (pszURL) + URL_HDR_LEN;

        //alloc suff. buf for sprintf, you can manage it some other way;
        //to have constant buf, or use EM_SETSEL&EM_REPLACESEL inserting
        //text piece by piece to avoid new/delete for each link
        pszLinkBuf = new char [nTitleLen + nURLen];
        if (!pszLinkBuf)
                return FALSE; //alloc failed

        //reset cf2
        memset (&cf2, 0, sizeof(cf2));
	cf2.cbSize = sizeof(cf2);

	//1st letter+url len+url text+rest of the title
	// "G[0018www.experts-exchange.com]o to Experts-Exchange"
	sprintf (pszLinkBuf, "%c%04X%s%s", *pszTitle, nURLen, pszURL, pszTitle + 1);

	//set title text
	::SendMessage (hRich, EM_SETSEL, nPos, nPos);
	::SendMessage (hRich, EM_REPLACESEL, 0, (LPARAM)pszLinkBuf);

        //now we don't need the buf anymore, so delete it
        delete[] pszLinkBuf;
	
	//apply link style on'G' 
	::SendMessage (hRich, EM_SETSEL, nPos, nPos+1);
	cf2.dwMask = CFE_LINK|CFE_PROTECTED;
	cf2.dwEffects = CFM_LINK|CFM_PROTECTED;
	::SendMessage (hRich, EM_SETCHARFORMAT, SCF_SELECTION , (LPARAM)&cf2);

	//hide URL text
	nPos++;
	
	::SendMessage (hRich, EM_SETSEL, nPos, nPos+nURLen);
	cf2.dwMask = CFE_LINK|CFE_PROTECTED|CFE_HIDDEN;
	cf2.dwEffects = CFM_LINK|CFM_PROTECTED|CFM_HIDDEN;
	::SendMessage (hRich, EM_SETCHARFORMAT, SCF_SELECTION , (LPARAM)&cf2);

	//apply link&protected style on the rest of the title
	nPos += nURLen;

	::SendMessage (hRich, EM_SETSEL, nPos, nPos+nTitleLen-1);
	cf2.dwMask = CFE_LINK|CFE_PROTECTED;
	cf2.dwEffects = CFM_LINK|CFM_PROTECTED;
	::SendMessage (hRich, EM_SETCHARFORMAT, SCF_SELECTION , (LPARAM)&cf2);

	return TRUE;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::OnLink(NMHDR* pNMHDR, LRESULT* pResult)
{
	ENLINK *pEnLink = (ENLINK *)pNMHDR;

	if (pEnLink->msg == WM_LBUTTONDOWN)
	{
		Richedit::TEXTRANGE tr;
		int nURLen, nRange;

                //prepare TEXTRANGE and aloc suff. buf for clicked link text
		tr.chrg = pEnLink->chrg;
		tr.lpstrText = new TCHAR[tr.chrg.cpMax-tr.chrg.cpMin + 1];

		if (!tr.lpstrText)
			return; //alloc failed

		//get the link text
		nRange = ::SendMessage (rich->Handle, EM_GETTEXTRANGE, 0 , (LPARAM)&tr);

		//get URL length
		if (!sscanf (tr.lpstrText + 1, "%04X", &nURLen) ||
			nRange < nURLen + 1)
			return;

		//place zero at the URL's end
		tr.lpstrText[nURLen + 1] = 0;

		//here is your URL
		ShellExecute (NULL, "open", (tr.lpstrText + 1 + URL_HDR_LEN), NULL, NULL, SW_SHOW);

		delete[] tr.lpstrText;
	}
	
	*pResult = 0;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::OnProtected(NMHDR* pNMHDR, LRESULT* pResult)
{
	ENPROTECTED *pEnProtected = (ENPROTECTED *)pNMHDR;

        //return 0 to allow modification, 1 otherwise
	//allow copy, but deny link modification
	*pResult = pEnProtected->msg != WM_COPY;
}



And the header...

Code:
#include <stdio.h>

#define URL_BUF_LEN 512
#define URL_HDR_LEN 4
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE-managed Components
        TRichEdit *rich;
        TButton *Button1;
        void __fastcall Button1Click(TObject *Sender);
private:	// User declarations
        void __fastcall OnLink(NMHDR* pNMHDR, LRESULT* pResult);
        void __fastcall OnProtected(NMHDR* pNMHDR, LRESULT* pResult);
public:		// User declarations
        __fastcall TForm1(TComponent* Owner);
        bool __fastcall InsertLink(HWND hRich, int nPos, const char *pszTitle, const char *pszURL);

protected:
        void __fastcall OnNotify(TMessage &Message);

        BEGIN_MESSAGE_MAP
        MESSAGE_HANDLER(WM_NOTIFY, TMessage, OnNotify)
        END_MESSAGE_MAP(TForm)

};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

Cyprus
 
ok, for my life I have no idea what the problem is. And maybe somebody can check the code and tell me. I copied and pasted my slightly modified code into one of my new projects, and the URL code didn't work! So I copied and pasted the code letter-for-letter from my example program that I've posted before, and ran both programs. The example URL worked like a charm and my URL didn't work at all. Then I tried just creating a brand new project and doing the exac tsame thing as the example and it STILL doesn't work! Anyone know the problem? The ONLY thing I could think of was that there was some discrepency between BCB5 and BCB6?

I'll probably post this in it's own thread pretty soon here...

Cyprus
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top