Reputation: 3894
I am implementing a tkinter text widget based console application and as a part of auto complete feature, I am observing one problem that on pressing return key results in the deletion of the selected text. Below example shows the similar problem :
from Tkinter import *
def getCommand(*args):
global text
text.insert(END, "\n")
text.insert(END, "command>")
x = text.get("1.0",END)
print "command is %s" %(x)
return 'break'
def handle_keyrelease(event):
global text
if event.keysym == "Return":
text.tag_remove(SEL,"1.9",END)
text.mark_set("insert",END)
getCommand()
return 'break'
root = Tk()
text = Text(root)
text.pack()
text.insert(END,"command>")
text.focus()
text.bind("<KeyRelease>", handle_keyrelease)
text.insert(END,"sometext")
text.tag_add(SEL,"1.9",END)
text.mark_set("insert","1.9")
root.mainloop()
In this code, when I hit the return key, I want to get the complete command sometext
, however with the current code only s
is retrieved. I have tried setting the cursor position to end and deletion of selection tag when the return key event is recieved.
EDIT
Problem with KeyPress
event handler :
from Tkinter import *
def getCommand(*args):
global text
text.insert(END, "\n")
text.insert(END, "command>")
x = text.get("1.0",END)
print x
return 'break'
validkeysymchars = []
validkeysymchars = validkeysymchars + map(chr, range(65,91))
validkeysymchars = validkeysymchars + map(chr, range(97,123))
def handle_keyrelease(event):
global text
if event.keysym == "Return":
text.tag_remove(SEL,"1.9",END)
text.mark_set("insert",END)
getCommand()
return 'break'
if event.keysym in validkeysymchars:
for x in ['testcommand']:
strtocmp = text.get("MARK","end")
strtocmp = strtocmp.encode('ascii','ignore')
strtocmp = strtocmp.strip()
print strtocmp
if x.startswith(strtocmp):
currpos = text.index(INSERT)
text.insert(END,x[len(strtocmp):])
text.tag_add(SEL,currpos,"%s+%dc"%(currpos,len(x)-len(strtocmp)))
text.mark_set("insert",currpos)
root = Tk()
text = Text(root)
text.pack()
text.insert(END,"command>")
text.mark_set("MARK",INSERT)
text.mark_gravity("MARK",LEFT)
text.focus()
text.bind("<KeyPress>", handle_keyrelease)
root.mainloop()
Upvotes: 2
Views: 542
Reputation: 101052
The problem is that you handle <KeyRelease>
instead of <KeyPress>
(or <Return>
).
At the time the <KeyRelease>
event is raised, the text widget has already been updated with the newline. And because text was selected, that selected text got simply replaced with the newline (as it would have been replaced by pressing any other key).
So better bind to <KeyPress>
or <Return>
instead of <KeyRelease>
.
I think the easiest way to solve your issue is indeed to handle both <KeyRelease>
and <Return>
seperatly.
(You could get it to work using <KeyPress>
, but this would involve checking which key is pressed, manually inserting this key to the text, checking which text is selected, and replacing the selected text; so, it will be rather clunky).
def handle_keyrelease(event):
global text
if event.keysym in validkeysymchars:
for x in ['testcommand']:
strtocmp = text.get("MARK","end")
strtocmp = strtocmp.encode('ascii','ignore')
strtocmp = strtocmp.strip()
print strtocmp
if x.startswith(strtocmp):
currpos = text.index(INSERT)
text.insert(END,x[len(strtocmp):])
text.tag_add(SEL,currpos,"%s+%dc"%(currpos,len(x)-len(strtocmp)))
text.mark_set("insert",currpos)
return
def handle_return(event):
text.tag_remove(SEL,"1.9",END)
text.mark_set("insert",END)
text.insert(END, "\n")
text.insert(END, "command>")
text.mark_set("MARK",INSERT)
text.mark_gravity("MARK",LEFT)
return "break"
...
text.bind("<KeyRelease>", handle_keyrelease)
text.bind("<Return>", handle_return)
...
Upvotes: 1