【问题标题】:Restricting the value in Tkinter Entry widget限制 Tkinter Entry 小部件中的值
【发布时间】:2012-02-16 02:31:04
【问题描述】:

我需要将 Entry 小部件中的值限制为仅数字。我实现的方式是:

import numpy as np
from Tkinter import *;
import tkMessageBox;

class window2:

    def __init__(self,master1):

        self.panel2=Frame(master1)
        self.panel2.grid()

        self.button2=Button(self.panel2,text="Quit",command=self.panel2.quit)
        self.button2.grid()

        self.text1=Entry(self.panel2)
        self.text1.grid()
        self.text1.bind('<KeyPress>', self.keybind1)
        self.text1.focus()

    def keybind1 (self,event):
        if event.int in np.linspace(0,9,10):
            print event.int


root1=Tk()
window2(root1)
root1.mainloop()

我不断收到事件实例没有属性“int”的错误消息。我该怎么办?

【问题讨论】:

标签: python tkinter validation


【解决方案1】:

""" 下面的代码将 ttk.Entry 小部件限制为接收类型“str”。 """

    import tkinter as tk
    from tkinter import ttk


    def is_type_int(*args):
      item = var.get()
      try:
        item_type = type(int(item))
        if item_type == type(int(1)):
          print(item)
          print(item_type)
      except:
        ent.delete(0, tk.END)


    root = tk.Tk()
    root.geometry("300x300")

    var = tk.StringVar()

    ent = ttk.Entry(root, textvariable=var)
    ent.pack(pady=20)

    var.trace("w", is_type_int)

    root.mainloop()

【讨论】:

    【解决方案2】:
    def validate(entry_text):
        chars = '1234567890'
        if any((c not in chars) for c in pin.get()):
            lpin = int(len(pin.get()))-1 
            pin.set(pin.get()[:lpin])
    
    pin.trace("w", lambda *args: validate(pin))
    

    【讨论】:

      【解决方案3】:

      我是 python 和 Tkinker 的新手,但这最适合我:

          def keybind1 (self,event):
              v = event.char
              try:
                  v = int(v)
              except ValueError:
                  if v!="\x08" and v!="":
                      return "break"
      

      v = int(v) 在除数字键之外的任何键上触发 ValueError,但是 if v!="\x08v!="":" 语句仍然允许退格键、("\x08") 和 delete、箭头、home、end 等键(具有 event.char"")正常工作 - 否则break 命令停止将其他字符输入到 Entry 小部件中。

      【讨论】:

      • 这是最好的解决方案。谢谢!
      【解决方案4】:

      这使用validatecommandtk.Entry 中的有效用户输入限制为可以解释为浮点数的字符串:

      import tkinter as tk
      
      class window2:
          def __init__(self, master1):
              self.panel2 = tk.Frame(master1)
              self.panel2.grid()
              self.button2 = tk.Button(self.panel2, text = "Quit", command = self.panel2.quit)
              self.button2.grid()
              vcmd = (master1.register(self.validate),
                      '%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W')
              self.text1 = tk.Entry(self.panel2, validate = 'key', validatecommand = vcmd)
              self.text1.grid()
              self.text1.focus()
      
          def validate(self, action, index, value_if_allowed,
                             prior_value, text, validation_type, trigger_type, widget_name):
              if value_if_allowed:
                  try:
                      float(value_if_allowed)
                      return True
                  except ValueError:
                      return False
              else:
                  return False
      
      root1 = tk.Tk()
      window2(root1)
      root1.mainloop()
      

      参考资料:

      • Tk man page 解释了validatevalidatecommand 选项。 (感谢schlenk 提供链接)。
      • 我学会了如何在 Python here 中做到这一点。

      【讨论】:

      • 关于验证的 Tk 文档可能会有所帮助:tcl.tk/man/tcl8.5/TkCmd/entry.htm#M-validate
      • 谢谢你的链接,schlenk。
      • 如何处理删除输入字段中的所有字符?我试过if action == 0: return True,但没用。但是,如果我在except ValueError: 之后检查if value_if_allowed == '': return True,它确实允许我删除该字段的内容。很奇怪。
      • 为什么退格键删除所有输入的数据在这里不起作用。即使在键入一个值后按退格键,一个值也始终存在。 !
      • @sunny_old_days:感谢您的错误报告。当value_if_allowed 等于一个空字符串时,float(value_if_allowed) 正在提高ValueError。我已更改代码以避免此ValueError,从而允许空字符串。
      【解决方案5】:

      如果您正在处理以逗号作为小数点的语言环境:

      locale.setlocale(locale.LC_ALL,'de_DE.UTF-8') # German
      

      vcmd = (self.root.register(self.entry_numericonly), '%d', '%P')
      

      self.my_float_entry = tk.Entry(self.root, ... , validate='key', validatecommand=vcmd)
      

      def entry_numericonly(self, action, value_if_allowed):
          if(action == "1"):
              try:
                  loc_float  = locale.atof(value_if_allowed)
                  loc_float_format = locale.format("%f", loc_float)
                  try:
                      loc_same_length = loc_float_format[:len(value_if_allowed)]
                      return value_if_allowed == loc_same_length
                  except:
                      return False                    
              except:
                  return False
          else:
              return True
      

      【讨论】:

        【解决方案6】:

        我意识到这个答案已经很晚了,但我觉得我可以给出一个更简单的答案......一旦你了解它是如何工作的,它真的很简单。

        使用Entry 小部件附带的验证功能。

        假设self 是一个小部件:

        vcmd = (self.register(self.callback))
        
        w = Entry(self, validate='all', validatecommand=(vcmd, '%P')) 
        w.pack()
        
        def callback(self, P):
            if str.isdigit(P) or P == "":
                return True
            else:
                return False
        

        您不需要包含所有的替换代码:('%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W'),只有您将使用的那些是必需的。

        Entry 小部件返回一个字符串,因此您必须以某种方式提取任何数字才能将它们与其他字符分开。最简单的方法是使用str.isdigit()。这是一个内置于 python 库中的方便的小工具,不需要额外的导入,它会识别它从 Entry 小部件返回的 string 中找到的任何数字(数字)。

        if 语句的or P == "" 部分允许您删除整个条目,如果没有它,您将无法删除最后一个(输入框中的第一个)数字,因为'%P' 返回一个空值并导致你的回调返回False。我不会在这里详细说明原因。

        validate='all' 允许回调评估P 的值,就像您在focusinfocusout 或任何key 中风一样更改小部件中的内容,因此您不会留下任何漏洞输入错误的字符。

        总而言之,让事情变得简单。如果您的回调返回True,它将允许输入数据。如果回调返回“False”,它将基本上“忽略”键盘输入。

        查看这两个参考。他们解释了每个替换代码的含义以及如何实现它们。

        http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/entry-validation.html http://stupidpythonideas.blogspot.ca/2013/12/tkinter-validation.html

        编辑: 这只会处理盒子中允许的内容。但是,您可以在回调中将 P 的任何值添加到您希望的任何变量中。

        【讨论】:

        • 我更喜欢这个,代码行数更少,所以更易读,谢谢。
        • 请注意,P == '' 检查实际上至少需要在 python 3.8 中为 str(P) == ''
        【解决方案7】:

        我还必须处理一个初始插入案例。这就是我最终得到的结果:

            def _checkNumberOnly(self, action, value_if_allowed):
                if action != '1':
                   return True
                try:
                    return value_if_allowed.isnumeric()
                except ValueError:
                   return False
        
            vcmd = (self.register(self._checkNumberOnly), '%d', '%P')
                self.port = ttk.Entry(self, width=35, validate='key', validatecommand=vcmd)
        

        因此它验证以下内容:

            self.port.insert(0, '6379')
        

        我不确定是否需要 catch,因为 isnumeric() 没有说明它会引发异常。

        【讨论】:

          【解决方案8】:

          答案几乎是完美的,只需添加一点即可删除整个字符串。 只应在插入文本时检查浮点数

          def validate_float(self, action, index, value_if_allowed,
              prior_value, text, validation_type, trigger_type, widget_name):
              # action=1 -> insert
              if(action=='1'):
                  if text in '0123456789.-+':
                      try:
                          float(value_if_allowed)
                          return True
                      except ValueError:
                          return False
                  else:
                      return False
              else:
                  return True
          

          【讨论】:

          • 感谢您对 unutbu 答案的修复!他离开了你提到的那个散乱的角色。
          猜你喜欢
          • 2018-05-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-06-27
          • 1970-01-01
          • 1970-01-01
          • 2012-04-06
          • 2019-02-26
          相关资源
          最近更新 更多