tkinter复制粘贴到Entry不会删除所选文本 [英] tkinter copy-pasting to Entry doesn't remove selected text

查看:98
本文介绍了tkinter复制粘贴到Entry不会删除所选文本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

When I copy some text and paste (crtl + v) it in a tkinter Entry , if there is selected text, it won't remove it from the entry. I'm on Linux (Mint) 64-bit.

在这里,我用(ctrl + c)复制"d":

Here I copy "d" with (ctrl + c):

然后我选择"b":

现在我将"d"(ctrl + v)粘贴到它上,但是结果是这样的:

Now I paste "d" (ctrl + v) onto it but the result is this:

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

First: I want to know if this is a bug specific to Linux or this is how it was supposed to be?

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

Second: I was thinking of a workaround for this with validatecommand but I got another problem:

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

If I am to remove the selected text in a command, I have to know the index of selection in the entry. Otherwise if there are multiple instances of the selected text directly after and before the cursor, I wouldn't know which one to delete and replace with the new text. Because the cursor could be on either side of the selection (depending on if the person dragged the mouse form right to left or left to right on the text).

现在是否可以获取条目中 选择 索引 ?或解决此问题的另一种方法?

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

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

Here's some code with an example of the problem:

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已经存在了很长时间,并且诸如此类的基本事情也不会被忽视.

It's not a bug. If it were a bug, somebody would have noticed it and fixed it a decade ago. Tkinter has been around a long time, and fundamental things like this don't go unnoticed.

在基于X11的系统上执行粘贴操作不会在粘贴之前删除所选文本.以下是撰写本文时实际的底层Tcl代码:

The implementation of paste on X11-based systems will not delete the selected text before pasting. The following is the actual underlying Tcl code as of the time I write this:

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>> 事件的绑定.

Using the validation feature is definitely the wrong way to solve this. Validation is specifically for what the name implies: validation. The right solution is to create your own binding to the <<Paste>> event.

现在有一种方法可以获取条目中的选择索引吗?或解决此问题的另一种方法?

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 表示所选内容之后的字符.

Yes, the entry widget has the special index sel.first which represents the first character in the selection, and sel.last represents the character just after the selection.

将上面的代码相当精确地翻译成python(减去x11的检查)看起来像这样:

A fairly literal translation of the above code into python (minus the check for x11) would look something like this:

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>> 事件:

To have this apply to a specific widget, bind to the <<Paste>> event for that widget:

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

如果您想对每个 Entry 小部件进行一次绑定,请使用 bind_class :

If you want to do a single binding that applies for every Entry widget, use bind_class:

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

这篇关于tkinter复制粘贴到Entry不会删除所选文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆