繁体   English   中英

使用tkinter条目验证防止用户两次输入相同的值

[英]Preventing the user from entering the same value twice using tkinter entry validation

我目前正在研究计算器程序。 我设法使验证代码起作用,因此条目小部件仅接收来自valid_input列表的值。 虽然,我目前正在尝试阻止输入“ 5 ** 2”和“ 2 // 2”,但是有一种方法可以使用验证码或test_input函数使用户无法输入两个相同的运算符。 这主要是关于除法和乘法运算符。

from tkinter import *
from tkinter import messagebox

def replace_text(text):
    display.delete(0, END)
    display.insert(0, text)

#Calculates the input in the display        
def calculate(event = None):
    equation = display.get()
    try:
        result = eval(equation)
        replace_text(result)
        print(result) #Just for reference 
        return True 
    except: 
        messagebox.showerror("Error", "Math Error", parent = root)

#This function dosen't allow the user to input invalid values    
def test_input(value, action):
    #list of inputs that is valid for the calculator to function
    valid_input = ["7", "8", "9", "+", "4", "5", "6", "-", "1", "2", "3", "*", "0", ".", "/"]
    if action == "1": #If an insertion is occuring in the entry
        return all(char in valid_input for char in value)
    # if action != 1, allow it
    return True

root = Tk() 
root.title("Calculator testing")

display = Entry(root, font=("Helvetica", 16), justify = "right", validate = "key")
display.configure(validatecommand = (display.register(test_input), "%S", "%d"))
display.insert(0, "")
display.grid(column = 0, row = 0, columnspan = 4, sticky = "NSWE", padx = 10, pady = 10)
display.bind("=", calculate)

#Equals button
button_equal = Button(root, font = ("Helvetica", 14), text = "=", command = 
calculate, bg = "#c0ded9")
button_equal.grid(column = 2, row = 1, columnspan = 2, sticky = "WE")

#All clear button 
button_clear = Button(root, font = ("Helvetica", 14), text = "AC", command = 
lambda: replace_text(""), bg = "#c0ded9")
button_clear.grid(column = 0, row = 1, columnspan = 2, sticky = "WE")

#Main Program       
root.mainloop()

在验证功能中,您可以拆分用于插入数字和插入运算符/点的逻辑。

由于您关心条目中已经存在的内容以及要插入字符的位置,因此应将更多信息传递给validatecommand 您需要的信息是( 来自此答案 ):

# %i = index of char string to be inserted/deleted, or -1
# %s = value of entry prior to editing
# %S = the text string being inserted or deleted, if any

然后,您可以进行几项检查,以禁止会插入两个运算符或一个接一个的运算符:

def test_input(insert, content, index, action):
    #list of inputs that is valid for the calculator to function
    valid_numbers = ["7", "8", "9", "4", "5", "6", "1", "2", "3", "0"]
    valid_chars = ["+", "-", "*", ".", "/"]
    index = int(index)
    if action != "1": # Always allow if it's not an insert
        return True
    if insert in valid_numbers: # Always allow a number
        return True
    if insert in valid_chars: # If it's an operator or point do further checks
        if index==0: # Disallow if it's the first character
            return False
        if content[index-1] in valid_chars: # Disallow if the character before is an operator or point
            return False
        if index != len(content): # If you're not at the end
            if content[index] in valid_chars: # Disallow if the next character is an operator or point
                return False
        return True # Allow if it's none of the above
    else:
        return False # Disallow if the character is not a number, operator or point

display.configure(validatecommand = (display.register(test_input), "%S", "%s", "%i", "%d"))

我忘记了这会弄乱答案的插入,因为我假设一次只能插入一个字符。 您可以(至少)通过两种方式解决此问题:

您可以关闭用于插入答案的验证,并在插入后将其重新打开:

display.configure(validate='none')
display.insert(0, text)
display.configure(validate='key')

或者,因为答案总是所有的数字,你可以改变第二if在验证命令允许多个号码,而不是只有一个:

if all(char in valid_numbers for char in insert):

您可以使用正则表达式来验证以下类型的字符串:

import re

_str = "3*42"

print(re.match(r'[0-9]+\.?[0-9]*[\+\-\*\/][0-9]+\.?[0-9]*', _str))

输出:

<_sre.SRE_Match对象; span =(0,4),match ='3 * 42'>

如您所见,如果RegEx匹配,则re.match返回一个对象,否则返回None

有了这些信息,我们可以检查匹配是否返回一些信息来确定字符串是否有效:

import re


examples = ["3*42",       # VALID
            "3.14-42.0",  # VALID
            "12.0.0+21",  # INVALID - 2 dots
            "3--42",      # INVALID - 2 operators
            "3,14/42",    # INVALID - comma instead of dot
            "123 456",    # INVALID - no operator
            ]


for operation in examples:
    print("Operation {0} is: ".format(operation), end='')
    if re.match(r'[0-9]+\.?[0-9]*[\+\-\*\/][0-9]+\.?[0-9]*', operation):
        print("VALID")
    else:
        print("INVALID")

输出:

操作3 * 42为:有效
操作3.14-42.0为:有效
操作12.0.0 + 21为:无效
操作3--42为:无效
操作3,14 / 42是:INVALID
操作123456是:无效

RegEx的工作方式如下:
[0-9]+ :匹配一个或多个数字
\\.? :匹配零个或一个点
[0-9]* :匹配零个或多个数字
[\\+\\-\\*\\/] :正好进入这四个符号之一( +-*/
[0-9]+ :匹配一个或多个数字
\\.? :匹配零个或一个点
[0-9]* :匹配零个或多个数字

如果我们把所有东西都放在一起,我们会要求:

一个或多个数字,后跟零个或一个点,然后是零个或多个数字,然后是运算符,然后是一个或多个数字,然后是零或一个点,然后是零个或多个数字

提示:您可以使用RegEx更改您的valid_input

r`[0-9\.\+\-\*\/]*`

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM