linux - tkinter 复制粘贴到 Entry 不会删除选定的文本

标签 linux python-3.x tkinter

当我复制一些文本并将其粘贴 (crtl + v) 到 tkinter Entry 中时,如果有选定的文本,它不会将其从条目中删除。我在 Linux (Mint) 64 位上。

这里我用 (ctrl + c) 复制“d”: enter image description here

然后我选择“b”: enter image description here

现在我将“d”(ctrl + v)粘贴到它上面,但结果是这样的: enter image description here

首先:我想知道这是 Linux 特有的错误还是应该如此?

第二:我正在考虑使用 validatecommand 解决此问题,但我遇到了另一个问题:

如果我要在命令中删除选定的文本,我必须知道条目中选择的索引。否则,如果在光标前后直接有多个选定文本实例,我将不知道要删除哪一个并用新文本替换。因为光标可能位于所选内容的任一侧(取决于用户是在文本上从右向左还是从左向右拖动鼠标)。

现在有办法获取条目中selectionindex吗?或其他解决此问题的方法?

下面是一些带有问题示例的代码:

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()

最佳答案

这不是错误。如果它是一个错误,十年前就会有人注意到它并修复它。 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
    }
}

使用验证功能肯定是解决这个问题的错误方法。 Validation 顾名思义就是:validation。正确的解决方案是创建您自己的绑定(bind)到 <<Paste>>事件。

Now is there a way to get the index of selection in the entry? or another way to workaround this problem?

是的,条目小部件具有特殊索引 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"

要将其应用于特定小部件,请绑定(bind)到 <<Paste>>该小部件的事件:

entry = tk.Entry(...)
entry.bind("<<Paste>>", custom_paste)

如果你想做一个适用于每个 Entry 的单一绑定(bind)小部件,使用 bind_class :

root = tk.Tk()
...
root.bind_class("Entry", "<<Paste>>", custom_paste)

关于linux - tkinter 复制粘贴到 Entry 不会删除选定的文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46634858/

相关文章:

linux - 第二天使用 'at'命令录制视频流,只做一次

android - 将 Visual C/C++ 移植到 Android,在 Linux 中途停留?

python - 在 linux 中导入错误,但在 windows 中导入成功

python-3.x - Python(Windows)中父子进程之间的连续通信?

Python 3.4 多处理队列比 Pipe 快,出乎意料

Python GUI 移动时崩溃

c - FUSE - 详细文档

django - 如何在 Django 2.1 中将多个 slugs 添加到一个 url 路径中?

python - 通过 tkinter 使用 for 循环创建按钮时遇到问题。 (Python)

python - Tkinter 文本插入 : "' Nonetype' object has no attribute 'insert'