首页 > 解决方案 > 用 `validatecommand` 选项替换 ttk.Entry 小部件中的选定条目

问题描述

以下脚本创建了一个ttk.Entry小部件,它只接受可以转换为浮点类型的条目。当我使用鼠标指针选择键入的条目,然后按新的数字条目时,我希望新的数字条目替换选定的条目。目前这种行为不会发生。相反,新的数字条目将出现在所选数字的左侧。如何获得我需要的替换行为?

import tkinter as tk  # python 3.x
import tkinter.ttk as ttk  # python 3.x

class Example(ttk.Frame):

    def __init__(self, parent):
        super().__init__(parent)

        # %P = value of the entry if the edit is allowed
        # %S = the text string being inserted or deleted, if any    
        vcmd = (self.register(self.onValidate),'%P', '%S')
        self.entry = ttk.Entry(self, validate="key", validatecommand=vcmd)
        self.entry.pack(side="top", fill="x")

    def onValidate(self, P, S):
        # Disallow anything but '0123456789.+-'
        if S in '0123456789.+-':
            try:
                float(P)
                print('float(P) True')
                return True
            except ValueError:
                print('float(P) False')
                return False
        else:
            print('S in 0123456789.+- False')
            return False

if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(fill="both", expand=True)
    root.mainloop()

更新:使用事件.bind上的方法'<ButtonRelease>',我发现ttk.Entry小部件中选择的类型条目可以通过该.selection_get()方法获得。但是,我还没有弄清楚如何将这些方法联系起来以获得所需的行为。

将这些句子附加到__init__()方法的末尾。

        self.entry.bind( '<ButtonRelease>', self.selecttext )

    def selecttext(self, event):
        try:
            print( 'selection = ', self.entry.selection_get() )
        except tk.TclError:
            pass

标签: pythontkinter

解决方案


发生的事情是这样的:当你选择一个文本范围然后按下一个键时,tkinter 必须做两件事:它必须删除选定的文本,然后它必须插入新的文本。

首先调用处理程序进行删除。因为删除导致条目小部件完全为空,并且您无法将空字符串转换为浮点数,所以您的处理程序返回False. 这可以防止删除发生。

接下来,调用您的处理程序进行插入。旧文字还在。您允许插入,因此您最终得到的结果是所选文本不会被删除,新文本会插入到它之前。

最简单的解决方案是允许一个空字符串。然后,您可以简单地验证非空字符串是否可以转换为浮点数。

例子:

import tkinter as tk  # python 3.x
import tkinter.ttk as ttk  # python 3.x

class Example(ttk.Frame):

    def __init__(self, parent):
        super().__init__(parent)

        # %P = value of the entry if the edit is allowed
        vcmd = (self.register(self.onValidate),'%P')
        self.entry = ttk.Entry(self, validate="key", validatecommand=vcmd)
        self.entry.pack(side="top", fill="x")

    def onValidate(self, P):
        if P.strip() == "":
            # allow blank string
            return True
        try:
            float(P)
            return True
        except:
            return False

if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(fill="both", expand=True)
    root.mainloop()

推荐阅读