Предотвращение ввода пользователем одного и того же значения дважды с помощью проверки записи tkinter - PullRequest
0 голосов
/ 13 сентября 2018

Я сейчас работаю над программой калькулятора. Мне удалось сделать функцию кода проверки, чтобы виджет ввода получал значения только из списка 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()

Ответы [ 2 ]

0 голосов
/ 13 сентября 2018

В функции проверки вы можете разделить логику для вставки числа и ввода оператора / точки.

Так как вы заботитесь о том, что уже есть в записи и месте, где вы вставляете символ, вы должны передать некоторую дополнительную информацию 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):
0 голосов
/ 13 сентября 2018

Вы можете использовать регулярные выражения для проверки таких строк:

import re

_str = "3*42"

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

выход:

<_ sre.SRE_Match object; span = (0, 4), match = '3 * 42'>

Как видите, re.match возвращает объект, если RegEx совпадает, иначе он возвращает 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: VALID
Операция 3.14-42.0: VALID
Операция 12.0.0 + 21: НЕВЕРНЫЙ
Операция 3--42: НЕВЕРНЫЙ
Операция 3,14 / 42: НЕВЕРНЫЙ
Операция 123 456: НЕВЕРНЫЙ

Вот как работает RegEx:
[0-9]+: соответствует одной или нескольким цифрам
\.?: соответствует нулю или одной точке
[0-9]*: соответствует нулю или более цифрам
[\+\-\*\/]: Маркирует ровно один из этих четырех символов (+-*/)
[0-9]+: соответствует одной или нескольким цифрам
\.?: соответствует нулю или одной точке
[0-9]*: соответствует нулю или более цифрам

Если мы добавим все вместе, мы просим:

Одна или несколько цифр, за которыми следуют ноль или одна точка, за которыми следуют ноль или несколько цифр, после чего следует оператор, за которыми следуют одна или несколько цифр, за которыми следуют ноль или одна точка, за которыми следуют ноль или несколько цифр

и, как подсказка, вы можете изменить свой valid_input с помощью RegEx:

r`[0-9\.\+\-\*\/]*`
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...