I am trying to create a popup menu that opens only when right-clicked inside of certain widgets (Text and Entry, in this case) but nowhere else inside the root window. When a user right-clicks inside one of the widgets and selects "copy", the text selection inside that widget should be copied to the clipboard.
As is, the code below only works when explicitly referring to a certain widget but I want to generalize the copyToClipboard
function
to copy the text selection from the widget that the user right-clicked inside.
Instead, running the commented out lines from the code below gives the following error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\...\...\lib\tkinter\__init__.py", line 1702, in __call__
return self.func(*args)
TypeError: <lambda>() missing 1 required positional argument: 'e'
How do I access the appropriate (right-clicked) widget within the copyToClipboard
function?
def copyToClipboard():
#def copyToClipboard(event):
#value = event.widget.get(SEL_FIRST,SEL_LAST)
value = inputText.get(SEL_FIRST,SEL_LAST)
pyperclip.copy(value)
print(value)
def showMenu(event):
popup.post(event.x_root, event.y_root)
inputEntry = ttk.Entry(root)
inputText = Text(root)
popup = Menu(root)
popup.add_command(label="Copy", command=copyToClipboard)
#popup.add_command(label="Copy", command=lambda e: copyToClipboard(e))
inputText.bind("<Button-3>", showMenu)
inputEntry.bind("<Button-3>", showMenu)
inputText.pack()
inputEntry.pack()
mainloop()
I've added a solution below. Storing event.widget
as a global variable seemed to help as per acw's suggestion. I got rid of pyperclip because it kept giving me chinese chars and other random chars when mixing clicking-to-copy with Ctrl-V.
EDIT: It is worth noting that the Entry widget doesn't seem to handle line breaks well when they are pasted with Ctrl-V into the entry widget. Unfortunately, I haven't found an effective way to override the hotkey's default paste command to remove the line breaks prior to pasting.
from tkinter import *
from tkinter import ttk
root = Tk()
def copyToClipboard():
val = clickedWidget.selection_get()
root.clipboard_clear()
root.clipboard_append(val)
def showMenu(event):
global clickedWidget
clickedWidget = event.widget
popup.post(event.x_root, event.y_root)
inputEntry = ttk.Entry(root)
inputText = Text(root)
popup = Menu(root)
popup.add_command(label="Copy", command=copyToClipboard)
inputText.bind("<Button-3>", showMenu)
inputEntry.bind("<Button-3>", showMenu)
inputText.pack()
inputEntry.pack()
mainloop()