Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 用“validatecommand”选项替换ttk.Entry小部件中的选定条目_Python_Tkinter - Fatal编程技术网

Python 用“validatecommand”选项替换ttk.Entry小部件中的选定条目

Python 用“validatecommand”选项替换ttk.Entry小部件中的选定条目,python,tkinter,Python,Tkinter,下面的脚本创建了一个ttk.Entry小部件,它只接受可以转换为浮点类型的条目。当我使用鼠标指针选择键入的条目,然后按new numeric entries(新的数字条目)时,我希望新的数字条目替换选定的条目。目前,这种行为并未发生。相反,新的数字条目将显示在所选数字的左侧。如何获得所需的替换行为 import tkinter as tk # python 3.x import tkinter.ttk as ttk # python 3.x class Example(ttk.Frame)

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

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
方法,我发现
ttk.Entry
小部件中所选的键入条目可以通过
.selection\u get()
方法获得。然而,我还没有弄清楚如何将这些方法联系起来以获得所需的行为

将这些句子附加到
\uuuu init\uuu()
方法的末尾

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

    def selecttext(self, event):
        try:
            print( 'selection = ', self.entry.selection_get() )
        except tk.TclError:
            pass
self.entry.bind(“”,self.selecttext)
def selecttext(自我、事件):
尝试:
打印('selection=',self.entry.selection_get())
除了tk.TclError:
通过

我想分享我在下面得出的解决方案。我发现,当选择
ttk.Entry
text字段中的字符串/子字符串时,tkinter将默认分两步执行验证。(1) 将所选字符串/子字符串视为要进行的第一次编辑。(2) 将按键输入视为要进行的第二次编辑。因此,
validatecommand
将被调用两次。我还在脚本中添加了一些注释

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
        # %s = value of entry prior to editing
        vcmd = (self.register(self.onValidate),'%P', '%S', '%s')
        self.text = tk.StringVar()
        self.entry = ttk.Entry(self, validate="key", validatecommand=vcmd)
        self.entry.pack(side="top", fill="x")

    def onValidate(self, P, S, s):
        # Disallow anything but '0123456789.+-'
        selected = None
        print('\nP={}, S={}, s={}'.format(P, S, s) )

        try:

            if S in '0123456789.+-' or float(S):
                if self.entry.selection_present():
                    print('With Selection')
                    selected = self.entry.selection_get()
                    print('selected = ', selected )
                    # Notes:
                    # - When .selection_present()=True, I discovered that 
                    #   tkinter will return by default:
                    #    P = s w/o 'selected'
                    #    S = 'selected' and not the keypressed
                    #    s = value of entry prior to editing.
                    # - I should "return True" so that tkinter will trigger method
                    #   self.onValidate() again. This time,
                    #    P = value of the entry if the keypress edit is allowed.
                    #    S = the key pressed
                    #    s = P from previous attempt.
                    #   As such satisfy .selection_present()=False.
                    return True
                else:
                    print('No Selection')
                    try:
                        float(P); print('True')
                        return True
                    except ValueError:
                        print(ValueError, 'float({}) False'.format(P))
                        return False
            else:
                print('S in 0123456789.+- False')
                return False

        except ValueError:
            print('Try with Exception')
            print(ValueError, 'float({}) False'.format(P))
            return False


if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(fill="both", expand=True)
    root.mainloop()
更新: 下面的脚本显示了一个改进的算法,它只允许在tkinter
条目
小部件中使用浮点型条目(包括带有指数的条目)。请用这个

优点:

  • 此算法允许将浮点型数字及其指数输入tkinter输入小部件
  • 该算法避免了
    .selection\u present()
    方法,因为 它使用
    %d
    ,这是的固有回调替换代码
    validatecommand
    <代码>%d的值指示与删除(或选择)、插入和其他相关的场景(即“聚焦输入”、“聚焦输出”或“文本变量值的更改”)
  • 此算法中考虑的场景比我的第一个算法更全面。(如果您注意到任何相关场景被遗漏,请提醒我。谢谢。)
  • 改进算法:

    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)
    
            # %d = Type of action (1=insert, 0=delete, -1 for others)
            # %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_Float), '%d','%P','%S')
            self.entry = ttk.Entry(self, validate="key", validatecommand=vcmd)
            self.entry.pack(side="top", fill="x")
    
        def onValidate_Float(self, d, P, S):
            '''Allow only float type insertions (including exponents).
    
            Notes: 1. The culminated insertions can fail to convert to a float.
                      This scenario occurs ONLY when the exponent entry is not 
                      completed, i.e. when 'e-' and 'e+' are supplied only.
                   2. User of this method should remember that when they bind a
                      handle and '<KeyPress-Return>' to the tkinter Entry widget,
                      the handle can encounter error associated with processing
                      "float(numeric)" when numeric=1.4e- or 1.4e+ (as example).
                   3. I discovered that validatecommand uses %d to determine
                      the type of actions it take. As such, it is useful to
                      structure validatecommand instructions according to scenarios
                      d='0', d='1' and d='-1'. 
            '''
    
            def _checkDecimal(P):
                '''Return True when decimal does not occur in exponent.'''
                decimal_index = P.find('.')
                exponent_index = P.find('e')
                if exponent_index > decimal_index:
                    return True
                else:
                    return False
    
            print('\nd={}, P={}, S={}'.format(d, P, S) )
    
            if d == '0': #Delete Selection or keypress "Delete"/"Backspace"
                print('Allow delete action regardless of keypress.')
                return True
    
            elif d == '1': #Insert keypress
                print('d==1, Insert keypress.')
                try:
                    if S in '0123456789e.+-':
                        float(P); print('True')
                        return True
                    else:
                        print('False')
                        return False
                except ValueError:
                    print('float({}) ValueError.'.format(P))
                    if P.count('e')>1: return False
                    if P.count('e.')>0: return False
                    if P.count('-e')>0: return False
                    if P.count('+e')>0: return False
                    if P.find('e') == 0: return False
                    if P.count('.')>1: return False
    
                    if P[0]=="-":
                        print('P[0]=="-"')
                        if P.count("e-")>=1:
                            print('P.count("e-")>=1')
                            if P.count("-")>2: return False
                            if P.count("+")>0: return False
                            if not _checkDecimal(P): return False
                        elif P.count("e+")>=1:
                            print('P.count("e+")>=1')
                            if P.count("+")>1: return False
                            if P.count("-")>1: return False
                            if not _checkDecimal(P): return False
                        else:
                            print('no e- or e+')
                            if P.find('.') == 1: return False #disallow '-.'
                            if P.find('+') >= 1: return False #disallow '-+'
                            if P.find('-') >= 1: return False #disallow '--'
                            if P.count("-")>1: return False
                            if P.count("+")>1: return False
    
                    elif P[0]=="+":
                        print('P[0]=="+"')
                        if P.count("e-")>=1:
                            print('P.count("e-")>=1')
                            if P.count("-")>1: return False
                            if P.count("+")>1: return False
                            if not _checkDecimal(P): return False
                        elif P.count("e+")>=1:
                            print('P.count("e+")>=1')
                            if P.count("+")>2: return False
                            if P.count("-")>0: return False
                            if not _checkDecimal(P): return False
                        else:
                            print('no e- or e+')
                            if P.find('.') == 1: return False #disallow '+.'
                            if P.find('+') >= 1: return False #disallow '++'
                            if P.find('-') >= 1: return False #disallow '+-'
                            if P.count("-")>1: return False
                            if P.count("+")>1: return False
    
                    else:
                        print('P[0] is a number') 
                        if P.count("e-")>=1:
                            print('P.count("e-")>=1')
                            if P.count("-")>1: return False
                            if P.count("+")>0 : return False
                            if not _checkDecimal(P): return False
                        elif P.count("e+")>=1:
                            print('P.count("e+")>=1')
                            if P.count("+")>1: return False
                            if P.count("-")>0: return False
                            if not _checkDecimal(P): return False
                        else:
                            print('no e- or e+')
                            if P.count("-")>0: return False
                            if P.count("+")>0: return False
    
                    return True #True for all other insertion exceptions.
    
            elif d == '-1': #During focus in, focus out, or textvariable changes
                print('d==-1, During focus in, focus out, or textvariable changes')
                return True
    
    
    if __name__ == "__main__":
        root = tk.Tk()
        Example(root).pack(fill="both", expand=True)
        root.mainloop()
    
    将tkinter作为tk#python 3.x导入
    将tkinter.ttk作为ttk#python 3.x导入
    类示例(ttk.Frame):
    定义初始化(自身,父级):
    super()。\uuuu init\uuuu(父级)
    #%d=操作类型(1=插入,0=删除,-1表示其他)
    #%P=如果允许编辑,则该条目的值
    #%S=正在插入或删除的文本字符串(如果有)
    vcmd=(self.register(self.onValidate_Float)、“%d”、“P”、“S”)
    self.entry=ttk.entry(self,validate=“key”,validatecommand=vcmd)
    自进式包装(side=“top”,fill=“x”)
    def onValidate_浮动(自身、d、P、S):
    ''只允许浮点类型插入(包括指数)。
    注意:1.最终插入可能无法转换为浮点。
    只有当指数项不可用时,才会出现这种情况
    已完成,即仅提供“e-”和“e+”时。
    2.此方法的用户应记住,当他们绑定
    tkinter条目小部件的句柄和“”,
    句柄可能会遇到与处理相关的错误
    当数值=1.4e-或1.4e+(例如)时,“浮点(数值)”。
    3.我发现validatecommand使用%d来确定
    它所采取的操作类型。因此
    根据场景对命令和指令进行结构验证
    d='0',d='1'和d='1'-1'。
    '''
    def_checkDecimal(P):
    ''当指数中未出现小数时返回True''
    十进制索引=P.find('.'))
    指数=P.find('e')
    如果指数指数>十进制指数:
    返回真值
    其他:
    返回错误
    打印('\nd={},P={},S={}'。格式(d,P,S))
    如果d='0':#删除所选内容或按键“删除”/“退格”
    打印('允许删除操作而不考虑按键')
    返回真值
    elif d=='1':#插入按键
    打印('d==1,插入按键')
    尝试:
    如果在'0123456789e.+-'中:
    浮点数(P);打印('True')
    返回真值
    其他:
    打印('False')
    返回错误
    除值错误外:
    打印('float({})ValueError.'.format(P))
    如果P.count('e')>1:返回False
    如果P.count('e')>0:返回False
    如果P.count('-e')>0:返回False
    如果P.count('+e')>0:返回False
    如果P.find('e')==0:返回False
    如果P.count('.')>1:返回False
    如果P[0]=“-”:
    打印('P[0]==“-”)
    如果P.count(“e-”>=1:
    打印('P.count(“e-”>=1'))
    如果P.count(“-”)大于2:返回False
    如果P.count(“+”)大于0:返回False
    如果不是_checkDecimal(P):返回False
    elif P.count(“e+”)>=1:
    打印('P.count(“e+”)>=1')
    如果P.count(“+”)大于1:返回False
    如果P.count(“-”)大于1:返回False
    如果不是_checkDecimal(P):返回False
    其他:
    打印('无e-或e+')
    如果P.find('.')==1:返回False#disallow'-.'
    
    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()