[Tkinter-discuss] (no subject)

Michael Lange klappnase at web.de
Mon Dec 20 18:12:09 CET 2010


Hi

Thus spoketh Vasilis Vlachoudis <Vasilis.Vlachoudis at cern.ch> 
unto us on Mon, 20 Dec 2010 14:05:33 +0000:

> Dear all,
> 
> the default behavior of the Entry/Text on how they react to Cut&Paste
> is a bit problematic (at least on linux) Imaging that the entry
> contains the text "foobar" with the first 3 letters "foo" highlighted
> and we have the word "test" copied previously on the clipboard. When we
> press Ctrl-V to paste the clipboard text "test", tk will not delete the
> "foo" before inserting the "test" and we will get the text "footestbar"
> with the "foo" still highlighted. (The "test" will be inserted at the
> location of the cursor)
> 
> Normally what the user will expect will be to delete first the "foo"
> and then insert the "test" getting the string "testbar" with the "test"
> highlighted.
> 
> Do you know how I can change the behavior without the need to override
> the default Entry class and substitute it in the whole project?

This behavior is intentional by Tk developers, maybe it matched some old
Motif standard, I don't know for sure. The binding is defined in
entry.tcl as binding to the virtual <<Paste>> event:

##################################
bind Entry <<Paste>> {
    global tcl_platform
    catch {
	if {[tk windowingsystem] ne "x11"} {
	    catch {
		%W delete sel.first sel.last
	    }
	}
	%W insert insert [::tk::GetSelection %W CLIPBOARD]
	tk::EntrySeeInsert %W
    }
}
#################################

You see, in the fourth line they omit the deleting of the selection
on X11 systems.
If you want to change this, you must define a new callback for <<Paste>>
events for the Entry class and use bind_class() to override the default
binding. We can use most of the code from the default binding and "translate"
it into python, where %W corresponds with the event's widget attribute,
and the catch command works much like a try..except in python; the
"special" tk commands need to be wrapped in the widget's tk.call()
function:

######################################
from Tkinter import *
root = Tk()

def entry_paste(event):
    try:
        event.widget.delete('sel.first', 'sel.last')
    except TclError:
        pass# nothing is selected
    # in tk.call() use the widget's string representation event.widget._w
    # instead of event.widget, which is the widget instance itself
    text = event.widget.tk.call('::tk::GetSelection', event.widget._w, 'CLIPBOARD')
    event.widget.insert('insert', text)
    event.widget.tk.call('tk::EntrySeeInsert', event.widget._w)

root.bind_class('Entry', '<<Paste>>', entry_paste)

# create an Entry to see if it works:
Entry(root).pack()
root.mainloop()
######################################

I hope this helps

Michael


.-.. .. ...- .   .-.. --- -. --.   .- -. -..   .--. .-. --- ... .--. . .-.

Vulcans do not approve of violence.
		-- Spock, "Journey to Babel", stardate 3842.4


More information about the Tkinter-discuss mailing list