I searched the site and found a link to vb-world (hyperlink in richtextbox), but I think the site is down. Could anyone help?
What I actually want to do is something like the Rules Wizard in Outlook 2000. The rules is in a checked listbox, and the selected rule's description is in another listbox (used Spy++ to find out). In this second listbox, the rules are summarized, and the user could change certain variables by clicking on them (like a hyperlink). That's what I want. I want to build THAT listbox.
Thanx
Last edited by r0ach; Nov 25th, 2005 at 01:48 AM.
Reason: Resolved
Putting a "hyperlink" in a listbox is easy enough. What I don't understand is what you want to happen if someone clicks on the link. Could you provide more details on your request?
OK, I've attached an image. This is one rule from the rules wizard. The box is a listbox. You'll see that the label states:
"(click on an underlined value to edit it)"
That's what I want. I want to pop up a specific window (be it a common dialog, or one of my own forms) where the value can be edited.
You need an owner-drawn listbox with self-coded extra feature to highlight a certain word (I guess). Then when detect a click on the certain word the listbox could raise a new event and tell which word was clicked.
I have a UniListBox which is a very simple owner-drawn listbox. Owner-drawing requires subclassing and you need to capture certain messages and process them before or after the default thing happens (= subclassing). Here is the usercontrol code.
Now what you need to do this is to:
a) Make it possible to add a list of highlightable and clickable words (Dim m_ClickWords() As String for an example and then subs AddWord and RemoveWord)
b) Detect the position the word is at, you can use GetTextExtendPoint32 or DrawTextW (this one with DT_CALCRECT setting) API to do this. You could store the position in a RECT. First you can use InStr to look for the word, then get the text length before the word, then the word length itself. For this use the beforementioned API. You need to take columns into account if you use my control as a base.
c) Capture WM_MOUSEMOVE (or possibly some other window message) to see if the X and Y position are within the word RECT. Then highlight the word if this is the case.
d) You need to change the drawing part of the listbox so that it takes this new feature into account. It becomes a bit more complex than it currently is, but shouldn't be impossible.
e) Once you have the basic stuff working, you can add new properties to change the link text color and style to polish it up.
Good luck, there is pretty much no other way to do it
You are not going to be able to do this with a VB listbox. Each "line" in a listbox is considered to be a listbox entry, and all, or none of the entry will be underlined or highlighted.
With that in mind, I've been playing around with a richtextbox which does permit specific words within it to be manipulated. This I can do.
Now, my question is, what do I do when I click on it? It seems to me that you would need to code in specifics for each word. Like:
I think I'll only have one word per listbox entry. So, I could have specific listbox entry types. Each type, performing a different function. In my case, I'll have a specific date/date range, time/time range, age/age range, gender, etc. I'll have something like;
Apply this rule before allowing abc
where age is age
and gender is gender
the window that accepts the input can format the updated text before displaying it in the listbox to something like;
Apply this rule before allowing abc
where age is 25
and gender is gender
or
Apply this rule before allowing abc
where age is between 21 and 28
and gender is gender
I'm sure that - with subclassing - I could ignore the message to highlight the specific line. This is the thing about the Outlook Rule Wizard's box. I was surprised to find out it was a listbox. It never highlights the line. Only the underlined word.
I've build a full control that looks simular to the one in the Rules Dialog box of Outlook showed above. It contains a locked RichTextBox so the user can not edit the text in it directly. But you can change the text via code, either directly by changing the Text property which will erase all hyperlinks, or by using the InsertText method (however this method fails with an error if there is a hyperlink at that position).
Hyperlinks can be created in two ways, either by converting an existing text portion to a link using the ConvertTextToLink method or by inserting a link at a given position using the InsertLink method. Both of these methods returns a CHyperlink object which has a number of read-only properties + only one read/write property called ExtraInfo.
The ExtraInfo property can be used to store any string in a hyperlink, for example an URL to navigate to when the hyperlink is clicked on.
When you add or convert a text to a hyperlink you must specify a unique Key value for this link (unlike other collection classes where Key is optional).
When you click on a hyperlink a HyperlinkClick event is raised which recieves a reference to a CHyperlink object which you can use to determent what action you want to take, which could be to navigate to an URL, show a dialog box, or a popup menu, or whatever...
The attached ZIP also contains a demo project that shows a simple SQL builder tool for a simulated database (see attached screen shot).
Just like Rhino I use the EM_GETCHARFROMPOS message to check if the mouse is currently hovering a hyperlink and in that case change the cursor to a hand. However I also use EM_GETPOSFROMCHAR to validate that you actually are over the hyperlink. @Rhino, if you would set a hyperlink at the end of the text in your RTB and move the mouse below that text it will still show a hand cursor even though the mouse isn't over any text at all.
The ActiveX control project contains, except for the UserControl, two different classes, one named CHyperlink which is PublicNotCreatable (you can get a reference when you add a hyperlink or in the HyperlinkClick event). The other class is CHyperlinks, which is a collection of the current existing hyperlinks, however this class is Private and you can't get a direct reference to this, instead you use Methods and Properties of the Control itself.
To try out the demo, download the ZIP and open the HyperTxt.vbg project group file.
Last edited by Joacim Andersson; Nov 30th, 2005 at 01:11 PM.
...@Rhino, if you would set a hyperlink at the end of the text in your RTB and move the mouse below that text it will still show a hand cursor even though the mouse isn't over any text at all...
Hmmm... Works fine for me... but I'm not sure if I follow you Joacim. Anyway, will take a close look. Thanks.
It is a RichTextBox. The problem is that the VB RTBox is an implementation of version 1 of the RichTextBox control that didn't support hyperlinks.
It's not a RichTextBox. It's a Listbox. Check the Spy++ result below.
I've been screwing around in vb.net to see how I would do this. vb.net just allows a lot easier owner-drawing.
Here's what I came up with: Since each link might perform a different task, and I'm only going to have 1 link per ListboxItem, I thought that I should override the ListItem Class first. Easy in .net. Also add a pointer (AddressOf) Eventhandler, so that the onclick fires the correct event, and I can specify a different event for each item. I can olso fire the whole item's onclick, but only when the user clicks on the link. I used something like "where age is @age@", and parsed the @age@ part to become age. Then I override the listbox to take these specific ListItems, and render them correctly.
OK, I don't use Outlook so I just checked the Rules dialogbox in Outlook Express which used a RichTextBox. But regardless of the fact that Outlook uses a ListBox, why must you? My control can do exactly what you want since it raises an event whenever you click on a hyperlink and it passes the CHyperlink object of which hyperlink you clicked on. Just use a Select Case Link.Key statement to determent which link it is and perform whatever action you want.
If you have a look at the demo project I posted you will notice that it performs a slightly different task depending on which link you click at... Well, they both show the same dialogbox but the dialog have different appearance depending on which link you have clicked on.
I bet you do the same kind of thing to determent which button on a toolbar the user has clicked on and perform different tasks for each button. I'm aware that user-drawn listboxes is easy to create in .Net but in classic VB it's a bit harder, however there is a good user-drawn listbox at VBAccelerator you can use if you really need to use a ListBox instead of another control. But I'll bet that the end-user doesn't care if the control is based on a ListBox or something else. In my control I hide the caret so you don't have to have that flashing in the control while still allowing you to select text in it. Much like you can select text in IE without a caret appearing.
No, nothing except that the HyperlinkClick event is fired. You have to write code in this event to determent what should be done. Did you test the attached demo application?
No, nothing except that the HyperlinkClick event is fired. You have to write code in this event to determent what should be done. Did you test the attached demo application?
no, i tried the .vbg file.
tried the Demo.vbp file and it generated an error could not create reference : "c:\...\HT Ctrl.vbp". how can i do that?
You must save all the files in the same directory and open the *.vbg file, you can not run the Demo.vbp alone, atleast not if you haven't compiled the HTCtrl.vbp project to an OCX.
R0ach noticed a bug in my control posted above, so I've updated the code to fix that. The new demo also shows one way of implementing ToolTips when the mouse hovers one of the hyperlinks. I've updated my origional post with the new code (post #13 above).