TkinterWeb icon indicating copy to clipboard operation
TkinterWeb copied to clipboard

[Feature request] Rigth click on link

Open ShuffleWire opened this issue 3 years ago • 2 comments

The feature To be able to right click on hypertext link, and trigger a different action.

Use case Be able to emulate the behavior "open in a new tab" or display a drop down menu, or whatever else.

Possible implementation Add a method HtmlFrame.on_link_right_click(callback), triggered on right click. AFAIK, binding stuff on ButtonRelease-3 should do it.

Also Same idea with wheel click, and by extension all the button that Tkinter is aware of ?

Also again To display a drop down menu "Browers-like style", I found this article that seems to be a good way to go. I don't what you want to do with it, but I'm leaving it here :) https://www.geeksforgeeks.org/right-click-menu-using-tkinter/

ShuffleWire avatar Aug 10 '22 15:08 ShuffleWire

Hi!

Thanks for your suggestion. I think that hard-coding every binding would be redundant. It would be better to leave that to whoever is using TkinterWeb. This would also give you much more control over what happens on right-clicks. TkinterWeb is supposed to be very easy to build on and extend, but it isn't supposed to be a full web browser on its own. This means that extra features such as popups or tabs are not within the scope of this project, but should be easy to add yourself.

That being said, I just added the function resolve_url to help make it easier to get the hyperlink. You will need to upgrade TkinterWeb in order to use this function.

You can use url = frame.get_currently_hovered_node_attribute("href") to get the href of the hyperlink. Then run url = frame.resolve_url(url) to get the full url of the hyperlink (since many links only have partial or relative urls). Here's an example from the HtmlFrame docs that can get you started:

import tkinter as tk
from tkinterweb import HtmlFrame

root = tk.Tk()

myhtmlframe = HtmlFrame(root)
myhtmlframe.pack(fill="both", expand=True)
myhtmlframe.load_html("""<a class="center-red" href="http://tkhtml.tcl.tk">TEST</a>""")

def copy_url(url):
    root.clipboard_clear()
    root.clipboard_append(url)

def on_right_click(event):
    if myhtmlframe.get_currently_hovered_node_tag() == "a": #if the mouse is over a link
        link = myhtmlframe.get_currently_hovered_node_attribute("href") #get the link's url
        url = myhtmlframe.resolve_url(link) #get a full url from the link
        menu = tk.Menu(root, tearoff=0) #create the menu
        menu.add_command(label="Open %s" % url, command=lambda url=url: myhtmlframe.load_url(url))
        menu.add_command(label="Copy %s" % url, command=lambda url=url: copy_url(url))
        menu.tk_popup(event.x_root, event.y_root, 0) #show the menu


myhtmlframe.bind("<Button-3>", on_right_click)

root.mainloop()

Here, right-clicking a link will open a popup with two buttons. Clicking one loads the website, and clicking the other copies the link.

Hope this helps!

Andereoo avatar Aug 30 '22 16:08 Andereoo

Ok, I was not asking for so much xD But thank anyway for the work.

The thing is that I'm not using tkinterweb to load web page, but html code that is generated on the fly by my own app. So, the html code code be somewhat "tuned" to match tkinterweb capabilities. So I don't need advanced behavior, as I don't have to "be able to" load "random" page :) I just want to avoid manually building an HMI (with Qt or else) and simply render HTML is very convenient !

That being said, myhtmlframe.bind("<Button-3>", on_right_click) is what I need xD After that I will be able to trigger whatever action I like, but I'm in charge at this point :)

So Thank for the tip !

Side note, I thing it would be very nice to emphasis the usage of the bind method to extend tkinterweb, in my case I wasn't asking for much more. (granted the menu.tk_popup(event.x_root, event.y_root, 0) is so nice to display something precisely located, I will keep in mind !) (the only thing bothering me is that the user should use (and know how to use (that was one of the thing I was missing, also, and I think it's hard to guess)) the

if myhtmlframe.get_currently_hovered_node_tag() == "a": #if the mouse is over a link
        link = myhtmlframe.get_currently_hovered_node_attribute("href") #get the link's url

I do thing it's kind of a "tkinterweb" internal stuff dependent, and it would be sick to get that embedded in the source of tkinterweb, as for the left click (hence the OP) But I do understand that you don't when to hard code all the event !

Maybe you could add those tow line in a API function, that could be called from the user code getClickedLink(event) -> link of None That would make creating the on_right_click()-like callback easier, and promote is usage to allows more extensibility of tkinterweb :)

The whole popup menu thing is fine, imo, but don't belong in tkinterweb, as it's a pure tkinterweb code. But promoting it as you did is great nevertheless !

Cheers, and thank for the feedback !

I'm keeping open if you want to discussed it, but my issue is fixed, for my use case !

ShuffleWire avatar Sep 03 '22 15:09 ShuffleWire

Hi @ShuffleWire, I've added a convenience method as you suggested. Simply calling myhtmlframe.get_current_link() will return the url under the mouse when applicable. I might make an on_right_click function in the future. I've also added some tips in the FAQ and API reference to make it more obvious, as you suggested. Thanks!

Andereoo avatar Feb 02 '23 16:02 Andereoo