Validar Entrada do Usuário Tratar erros de entrada do usuário costuma ser uma tarefa desgastante e que muitas vezes, ocupa grande parte do tempo de implementação de um software. Uma forma de reduzir o código para tratamento de erros é filtrar a entrada, não permitindo assim que o usuário consiga entrar com um valor inválido. Por exemplo: Para um campo de entrada QLineEdit que só pode receber um valor numérico inteiro, temos que impedir que o usuário possa digitar qualquer caractere que não seja um número no intervalo de (0...9) ou um sinal de menos (-). Para isso, poderíamos reimplementar o evento KeyPress para impedir a entrada de caracteres inválidos. Mas somente evitar que sejam digitados caracteres inválidos, muitas vezes não é o suficiente para evitar entradas inválidas. Por exemplo: O usuário poderia digitar 92-1 o que não corresponde a um número inteiro válido, pois o sinal de menos só poderia aparecer na primeira posição da string. Para eliminar esse problema poderíamos fazer uma rotina de validação que é executada quando o texto está sendo editado. Quando estamos implementando um software que contem muitos campos que devem ser filtrados, o trabalho de filtragem se torna muito cansativo e o código muito grande. Em muitos casos podemos usar máscaras de entrada, mas às vezes elas são limitadas ou não aplicáveis. Para resolver esse problema e simplificar nosso trabalho de validação da entrada, existe no Qt a classe abstrata QValidator que serve para validar entradas de texto. Desta se derivam três subclasses, que são:
Se quisermos que em um determinado QLineEdit o usuário só possa digitar um valor numérico inteiro poderíamos usar o QIntValidator desta forma: QIntValidator *intValidator = new QIntValidator(this); QLineEdit *lineEdit = new QLineEdit(this); lineEdit->setValidator(intValidator); Vamos supor que estamos desenvolvendo um aplicativo de controle de vendas. Quando o vendedor selecionar algum produto, uma variável chamada QuantDisponivel irá indicar quantas unidades do produto estão disponíveis no estoque. Queremos que o vendedor entre com a quantidade do produto a ser vendida em um QLineEdit. Mas precisamos evitar que ele digite algum valor que não seja um número inteiro. Também queremos evitar que o vendedor digite um valor acima da quantidade disponível em estoque. Isso poderia ser implementado setando o range de QIntValidator desta forma: QIntValidator *intValidator = new QIntValidator(0, QuantDisponivel, this); Assim, estamos passando o range logo no construtor. Podemos também modificar o range utilizando as funções setRange, setButton ou setTop. Um recurso fantástico para a validação de entrada é o QRegExpValidator. Não vou entrar em detalhes sobre expressões regulares, mas um bom resumo pode ser encontrado em: http://guia-er.sourceforge.net/index.html Para demonstrar o QRegExpValidator, vamos supor que em um campo QLineEdit do nosso aplicativo, precisamos que o usuário digite um valor hexadecimal de 0 a FFFF. Para isso, podemos usar o QRegExpValidator assim: QValidator *hexValidator = new QRegExpValidator(QRegExp("[0-9A-Fa-f]{1,4}"), this); Desta forma o usuário só poderá digitar números no intervalo de (0...9), letras minúsculas (a...f) e maiúsculas (A...F). Para a expressão ser válida ela deverá ter no mínimo um dígito e só poderão ser digitados no máximo 4 dígitos. Com a expressão regular, podem ser feitos os mais diversos tipos de validadores de entrada personalizados. Como outro exemplo de expressão regular, esta serve para entrada de horas no formato (hh:mm) "([01][0-9]|2[0-3]):[0-5][0-9]". Nossa entrada vai até 23h e 59m. Dessa forma se o primeiro dígito da hora for 0 ou 1, o segundo pode ir até nove, o que poderia ser (09h) ou (19h). Mas se o primeiro dígito for 2, o segundo só pode ir até 3 que seria o nosso máximo para hora (23h). Neste caso se utiliza o OU, que é representado pelo símbolo (|). Então, a hora pode ser: Com o primeiro digito (0 ou 1) e o segundo de (0...9) OU (|) Com o primeiro dígito igual a dois e o segundo de (0...3) Para os minutos, como vão até 59, ficaria assim: O primeiro dígito pode ser de (0...5) e o segundo de (0...9) Além de usarmos as subclasses QIntValidator, QDoubleValidator e QRegExpValidator, também podemos herdar a classe virtual QValidator e implementar nossa própria classe de validação. Uma vantagem disso é que podemos não somente validar a entrada como também fazer transformações no texto de entrada. Por exemplo, podemos validar a entrada e transformá-la em maiúscula. Para demonstrar, vamos criar um validador de entrada hexadecimal que pode permitir entrada negativa (-FF) e pode também transformar a entrada para maiúscula. Aqui está nosso arquivo de cabeçalho: #ifndef FVALIDATORS_H #define FVALIDATORS_H #include <QValidator> class FHexValidator : public QValidator { Q_OBJECT public: explicit FHexValidator(QObject *parent = 0, bool _Signal = false, bool _UpperCase = true); void setSignal(bool _Signal) { Signal = _Signal; } void setUpperCase(bool _UpperCase) { UpperCase = _UpperCase; } QValidator::State validate(QString &input, int &pos) const; private: QRegExpValidator *validator; bool Signal; bool UpperCase; }; #endif // FVALIDATORS_H Criamos uma classe FHexValidator que é herdada de QValidator e reimplementamos a função virtual pura validate. Estou usando QRegExpValidator para simplificar o trabalho de filtrar a entrada hexadecimal, mas uma rotina que faça isso poderia ser implementada facilmente. A variável Signal indica se a entrada pode ser negativa e a variável UpperCase indica que a entrada deve ser convertida em maiúscula. Vamos ao código: #include "fvalidators.h" FHexValidator::FHexValidator(QObject *parent, bool _Signal, bool _UpperCase): QValidator(parent) { validator = new QRegExpValidator(QRegExp("[-0-9A-Fa-f]{1,8}"), this); Signal = _Signal; UpperCase = _UpperCase; } QValidator::State FHexValidator::validate(QString &input, int &pos) const { if(input.contains('-')) { if(!Signal || input[0] != '-' || input.count('-') > 1) return Invalid; if(input.size() < 2) return Intermediate; } if(UpperCase) input = input.toUpper(); return validator->validate(input, pos); } No construtor iniciamos validator para validar uma entrada hexadecimal com até 8 dígitos que pode conter o sinal de (-). A implementação de validate é bem simples. Ele pode retornar 3 estados, que são:
Primeiro a função checa se a string de entrada contém o caractere (-). Caso contenha a entrada pode ser inválida se o modo de entrada negativa (Signal) não estiver habilitado ou se o caractere (-) não estiver na primeira posição da string. Somente com essas condições poderia acontecer um erro se o usuário digitar (-), voltar o cursor para a primeira posição e digitar novamente (-). Para isso não acontecer a entrada também será invalidada se a string contiver mais de um caractere (-). Se a string contém o sinal (-) e não foi invalidada, precisamos saber se existem mais dígitos, pois uma string que contém somente o sinal (-) não é aceitável, mas sim indeterminada. Pois necessita de algum dígito para ser válida. Logo após, se o modo UpperCase estiver ativo, o texto é transformado em maiúsculo. Finalmente a string pode ser validada pelo objeto validator, que vai verificar se nela existem somente dígitos hexadecimais e o sinal (-). É isso aí pessoal, vou ficando por aqui e espero que tenham gostado do artigo. Até a próxima! |