当我复制一些文本并粘贴(crtl + v)它在tkinter条目中时,如果有选定的文本,它将不会从条目中删除它。我在Linux(Mint)64位上。
我在这里复制" d"用(ctrl + c):
现在我粘贴" d" (ctrl + v)到它上面但结果如下:
首先:我想知道这是否是特定于Linux的错误或者它应该是怎么回事?
第二:我正在考虑使用validatecommand
解决此问题,但我遇到了另一个问题:
如果我要删除命令中的选定文本,我必须知道条目中的选择索引。否则,如果在光标之前和之前有所选文本的多个实例,我将不知道要删除哪一个并用新文本替换。因为光标可能位于选区的任一侧(取决于用户是否在文本上从右向左或从左向右拖动鼠标)。
现在有没有办法在条目中获取 选择 的 索引 ?或解决此问题的其他方法?
以下是一些代码示例:
import tkinter as tk
root = tk.Tk()
def validation(after_text, before_text, validation_text, cursor_index):
cursor_index = int(cursor_index)
print('cursor index:', cursor_index)
print('text after change:', after_text)
print('text before change:', before_text)
print('text in need of validation:', validation_text)
try:
selection = root.selection_get()
except:
selection = ''
print('selection:', selection)
# EXAMPLE:
# validation_text = 'd'
# before text = "bb"
# now if someone dragged from right to left on the 2nd b:
# cursor position will be 1 (imagine | as the cursor): 'b|b'
# cursor_index = 1
# after_text = 'bdb' --> but should be 'bd'
# now if someone dragged from left to right on the 2nd b:
# cursor position will be 2 (imagine | as the cursor): 'bb|'
# cursor_index = 2
# after_text = 'bbd' --> but should be 'bd'
# so there is no way for me to know which of these b's I have
# to replace with d based on cursor position alone. I have to
# know the index of selection itself in before_text to be
# able to replace the text properly.
# I don't know how to get that.
return True
txtvar = tk.StringVar(value = 'a-b-c-d-e')
entry = tk.Entry(root, textvariable = txtvar)
font = tk.font.Font(family = entry.cget('font'), size = -50)
entry.config(validate = 'all',
vcmd = (root.register(validation),'%P', '%s', '%S', '%i'),
font = font)
entry.pack()
root.mainloop()
答案 0 :(得分:5)
这不是一个错误。如果它是一个bug,有人会注意到它并在十年前修复它。 Tkinter已经存在很长时间了,像这样的基本事情不会被忽视。
在粘贴X11的系统上执行粘贴不会在粘贴之前删除所选文本。以下是我写这篇文章时的实际底层Tcl代码:
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
}
}
使用验证功能绝对是解决此问题的错误方法。验证特别针对名称所暗示的内容:验证。正确的解决方案是创建自己的<<Paste>>
事件绑定。
现在有办法在条目中获取选择索引吗?或解决此问题的其他方法?
是的,条目小部件具有特殊索引sel.first
,它表示选择中的第一个字符,sel.last
表示选择后的字符。
将上述代码转换为python(减去x11的检查)的相当字面翻译将如下所示:
def custom_paste(event):
try:
event.widget.delete("sel.first", "sel.last")
except:
pass
event.widget.insert("insert", event.widget.clipboard_get())
return "break"
要将此应用于特定窗口小部件,请绑定到该窗口小部件的<<Paste>>
事件:
entry = tk.Entry(...)
entry.bind("<<Paste>>", custom_paste)
如果您想要执行适用于每个Entry
窗口小部件的单个绑定,请使用bind_class
:
root = tk.Tk()
...
root.bind_class("Entry", "<<Paste>>", custom_paste)