Marking hyperlinks in a Text widget

André Dahlqvist andre at beta.telenordia.se
Sun Jun 4 11:36:11 EDT 2000


Hi again Cliff, and thanks for helping me with this.

> Running netscape this way will fail if the user is already running it;
> to get around this you can check if it is running (using the output of
> os.popen("ps ax")) and use the openURL command if it is.

I will have to do something like this, yes. Debian GNU/Linux has a nice
wrapper which smartly handles these cases automatically. If you 
try to start netscape when it's already started it will use the already
started browser to open the link. Unfortunately not everyone has such 
a wrapper, and I will therefore have to check for running processes.

> Right, you'll have to read the text directly from the widget itself. You
> won't even need to use tag_names in this case.

Okay, it would be great if you could give a small example of how to do
this. Here is the code I am currently using, which is ugly and doesn't
handle all cases:

First I create a 'url' tag, and bind appropriate callbacks to this tag:

textwidget.tag_config('url', foreground='blue', underline=1)
textwidget.tag_bind('url', '<Enter>', hand_cursor)
textwidget.tag_bind('url', '<Leave>', normal_cursor)
textwidget.tag_bind('url', '<Button-1>', browser)

Below is the code that finds hyperlinks in the string called text. This 
string has also been inserted into the Text widget earlier in the code. 
http:// and ftp:// are the only protocols that needs to be found, and it 
doesn't have to find URLs like "www.address.com" (although that
wouldn't hurt.) What it would need to find, besides the url type
described above, are links that have a character right in front of it, like 
an opening pharentesis: (http://www.link.com). While almost all of the 
links in the text that I am searching for are separated by a space from 
the rest of the case, a few links are enclosed in pharentesis like this. 
I could add a "(http" and "(ftp" to the list below, but then I would have 
to remove the parenhetis in front of http:// and ftp:// in the links that I 
have found. So instead of doing this, which would be pretty ugly, I 
would prefer to use regular expressions for this. How would I use
regular expressions to only find the links themselves, and not the
stuff just in front of it?

Anyway, here's the code that I am not proud of which finds the URLs:

for word in string.split(text):
    if string.split(word, "://")[0] in ("http", "ftp"):
        pos = helpwin.textwidget.search(word, 1.0, END)
        # Add a tag from the start to the end of the URL
        textwidget.tag_add('url', pos, + pos + " + " + `len(word)`+ " chars")
        
Then I have the functions that handle the events that occur when you 
put your cursor over the link:

def hand_cursor(event):
    event.widget.configure(cursor="hand1")

def normal_cursor(event):
    event.widget.configure(cursor="xterm")

And finally the code that has to find what URL we clicked on, and start
the browser. I have not yet changed this to check for already running 
browsers, but I will do that later. If there is an easier way of finding 
these URLs I would love to hear it.

def browser(event):
    import bisect
    common_browsers = ['mozilla', 'netscape', 'lynx', 'w3m']

    # Find the ranges that have been tagged with the 'url' tag
    ranges = event.widget.tag_ranges('url')
    cursor_position = event.widget.index("@%d %d", event.x, event.y)
    # Find out in range the cursor was clicked
    slot = binsect.binsect(ranges, cursor_position)
    # Get the url
    hyperlink = event.widget.get(ranges[n-1], ranges[n])
    
    for browser in common_browsers:
        if not os.system(browser + hyperlink):
            # Found browser, leave
            break

> You could even post it so that everyone could look at it :)

I found the courage and did that now:-)

// André



More information about the Python-list mailing list