Pular navegação

Exemplo utilizando máscara de texto.

Exemplo utilizando máscara de texto.

Hoje é um dia propício pra postagem, não me pergunte o porque.
Vou começar mostrando como se aplica máscara de entrada em um campo de texto usando uma classe pronta. Encontrei essa classe em um fórum. Provavelmente surgiu deste projeto brasileiro
(já que um dos autores é o mesmo da classe).
Siga as regras da licença.

Copie o código e salve com o nome de MaskEntry.py

#
# Copyright (C) 2006 Async Open Source
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
# USA
#
# Author(s): Johan Dahlin <[EMAIL PROTECTED]>
#

import string
import sys

import gobject
import pango
import gtk

class MaskError(Exception):
    pass

(INPUT_CHARACTER,
 INPUT_ALPHA,
 INPUT_DIGIT) = range(3)

INPUT_FORMATS = {
    'a': INPUT_ALPHA,
    'd': INPUT_DIGIT,
    'c': INPUT_CHARACTER,
    }

class MaskEntry(gtk.Entry):
    def __init__(self):
        gtk.Entry.__init__(self)
        # It only makes se
        self.modify_font(pango.FontDescription("monospace"))
        self.set_property('editable', True)
        self.set_size_request(90, -1)

        self.connect('insert-text', self._on_insert_text)
        self.connect('delete-text', self._on_delete_text)

        # List of validators
        #  str -> static characters
        #  int -> dynamic, according to constants above
        self._validators = []
        self._interactive_input = True
        self._mask = None

    # Callbacks

    def _on_insert_text(self, editable, new, length, position):
        if not self._interactive_input:
            return

        if length != 1:
            print 'TODO: paste'
            self.stop_emission('insert-text')
            return

        position = self.get_position()
        next = position + 1
        validators = self._validators
        if len(validators) <= position:
            self.stop_emission('insert-text')
            return

        validator = validators[position]
        if validator == INPUT_CHARACTER:
            # Accept anything
            pass
        elif validator == INPUT_ALPHA:
            if not new in string.lowercase:
                self.stop_emission('insert-text')
                return
        elif validator == INPUT_DIGIT:
            if not new in string.digits:
                self.stop_emission('insert-text')
                return
        elif isinstance(validator, str):
            self.set_position(next)
            self.stop_emission('insert-text')
            return

        self.delete_text(position, next)

        # If the next position is a static character and
        # the one after the next is input, skip over
        # the static character
        if len(validators) > next + 1:
            if (isinstance(validators[next], str) and
                isinstance(validators[next+1], int)):
                # Ugly: but it must be done after the parent
                #       inserts the text
                gobject.idle_add(self.set_position, next+1)

    def _on_delete_text(self, editable, start, end):
        if not self._interactive_input:
            return
        if end - start != 1:
            print 'TODO: cut/delete several'
            self.stop_emission('delete-text')
            return

        validator = self._validators[start]
        if isinstance(validator, str):
            self.set_position(start)
            self.stop_emission('delete-text')
            return

        self.insert_text(' ', end)
        return False

    # Public API

    def set_mask(self, mask):
        """
        Sets the mask of the Entry.
        The format of the mask is similar to printf, but the
        only supported format characters are:
        - 'd' digit
        - 'a' alphabet, honors the locale
        - 'c' any character
        A digit is supported after the control.
        Example mask for a ISO-8601 date
        >>> entry.set_mask('%4d-%2d-%2d')
        HACK for erase data > set_mask('%0d') 
        

        @param mask: the mask to set
        """

        self._mask = mask
        if not mask:
            return

        input_length = len(mask)
        keys = INPUT_FORMATS.keys()
        lenght = 0
        pos = 0
        while True:
            if pos >= input_length:
                break
            if mask[pos] == '%':
                s = ''
                format_char = None
                # Validate/extract format mask
                pos += 1
                while True:
                    if mask[pos] not in string.digits:
                        raise MaskError(
                            "invalid format padding character: %s" % mask[pos])
                    s += mask[pos]
                    if mask[pos+1] in INPUT_FORMATS:
                        format_char = mask[pos+1]
                        break
                    pos += 1
                pos += 1
                self._validators += [INPUT_FORMATS[format_char]] * int(s)
            else:
                self._validators.append(mask[pos])
            pos += 1

        s = ''
        for validator in self._validators:
            if isinstance(validator, int):
                s += ' '
            elif isinstance(validator, str):
                s += validator
            else:
                raise AssertionError
        self.set_text(s)

    def get_field_text(self):
        """
        Get the fields assosiated with the entry
        if a field is empty it'll return an empty string
        otherwise it'll include the content

        @returns: fields
        @rtype: list of strings
        """
        if not self._mask:
            raise MaskError("a mask must be set before calling get_field_text")

        def append_field(fields, field_type, s):
            if s.count(' ') == len(s):
                s = ''
            if field_type == INPUT_DIGIT:
                s = int(s)
            fields.append(s)

        fields = []
        pos = 0
        s = ''
        field_type = -1
        text = self.get_text()
        validators = self._validators
        while True:
            if pos >= len(validators):
                append_field(fields, field_type, s)
                break

            validator = validators[pos]
            if isinstance(validator, int):
                s += text[pos]
                field_type = validator
            else:
                append_field(fields, field_type, s)
                s = ''
                field_type = -1
            pos += 1

        return fields

    def set_text(self, text):
        """
        Sets the text of the entry

        @param text:
        """
        self._interactive_input = False
        try:
            gtk.Entry.set_text(self, text)
        finally:
            self._interactive_input = True

    def delete_text(self, start, end):
        """
        Deletes text at a certain range

        @param start:
        @param end:
        """
        self._interactive_input = False
        try:
            gtk.Entry.delete_text(self, start, end)
        finally:
            self._interactive_input = True

    def insert_text(self, text, position=0):
        """
        Insert text at a specific position

        @param text:
        @param position:
        """
        self._interactive_input = False
        try:
            gtk.Entry.insert_text(self, text, position)
        finally:
            self._interactive_input = True

def main(args):
    win = gtk.Window()
    win.set_title('gtk.Entry subclass')
    def cb(window, event):
        print 'fields', widget.get_field_text()
        gtk.main_quit()
    win.connect('delete-event', cb)

    widget = MaskEntry()
    widget.set_mask('%2d/%2d/%4d')

    win.add(widget)

    win.show_all()

    widget.select_region(0, 0)
    gtk.main()

if __name__ == '__main__':
    sys.exit(main(sys.argv))

Depois disso, você poderá testa-la rodando normalmente, assim:
$ python MaskEntry.py

Para inseri-la no seu próprio programa, faça como no exemplo:

        self.dtaemi     = MaskEntry()
        self.dtaemi.set_mask('%2d/%2d/%4d')
        self.hboxDtasBusca.pack_start(self.dtaemi,False,False,0)
        texto = gtk.Label()
        texto.set_text("e")
        self.hboxDtasBusca.pack_start(texto,True,True,0)

        self.dtavenc    = MaskEntry()
        self.dtavenc.set_mask('%2d/%2d/%4d')
        self.hboxDtasBusca.pack_start(self.dtavenc,False,False,0)

Na primeira linha é criada a entrada de texto que receberá a máscara da classe.
Em seguida é configurada a máscara para esse objeto(%2d significa 2 dígitos).
No meu exemplo eu adicionei à um hbox criado anteriormente.
Pronto, tá feito.

Obs.: Se você selecionar um “MaskEntry” utilizando a tecla tab, ele selecionará todos os campos e não conseguirá apagar e voltar para o primeiro espaço.

4 Comments

  1. Olá amigo, trabalho com LibGlade no Python, criei uma janelinha com uma caixa de texto um rótulo e um botão OK para textar sua sujestão de módulo. No caso a idéia do programinha é exibir a caixa de texto com a máscara e ao clicar em OK o rótulo exibiria os dados da caixa.
    Mas não consegui fazer funcionar…
    Como faço para inserir esse módulo no meu código? Sempre trabalho nesse formato com o “glade”.
    Aí vai o script do programa:
    import gtk
    import gtk.glade
    import MaskEntry

    class Exec(object):
    “””
    Janela principal
    “””

    def __init__(self):
    “””
    Inicializa a classe
    “””

    # Carrega a interface
    self.tree = gtk.glade.XML(‘caixadata.glade’,’main’)

    self.w_txt = self.tree.get_widget(‘txt’)
    self.w_lbl = self.tree.get_widget(‘lbl’)

    callbacks = {
    ‘on_main_destroy’: self.on_main_destroy,
    ‘on_ok_clicked’: self.on_ok_clicked
    }

    self.tree.signal_autoconnect(callbacks)

    def on_main_destroy(self, widget):
    raise SystemExit

    def on_ok_clicked(self, widget):
    txt = self.w_txt.get_text()
    self.w_lbl.set_text(txt)

    if __name__ == “__main__”:
    Exec()
    gtk.main()

    Desde já agradeço.

  2. Olá Jeremias, desculpe-me pela demora.
    Hum, você precisa criar um objeto MaskEntry e “empacotá-lo” em um box(hbox, vbox, table).

    Pode fazer isso na __init__ de seu programa, inserindo(e adaptando) o segundo trecho do código que passei.

    Tenta aí que é fácil! =D

  3. Olá amigo, desculpe a encheção de saco, mas sou totalmente principiante.
    Não entendi como inserir o trecho na minha __init__.
    Também não entendi qual seria a segunda parte…
    Seria a que começa com – def main (args): ?

    Desde já agradeço a atenção.

  4. Oi amigo, consegui fazer funcionar dessa forma. Mas em módulo sinceramente não consegui fazer…

    Dá uma idéia aí…

    Aí vai o script que funciona:

    #! /usr/bin/python2.6
    # -*- coding: iso-8859-15 -*-

    import gtk
    import gtk.glade

    import string
    import sys

    import gobject
    import pango
    import gtk

    class MaskError(Exception):
    pass

    (INPUT_CHARACTER,
    INPUT_ALPHA,
    INPUT_DIGIT) = range(3)

    INPUT_FORMATS = {
    ‘a’: INPUT_ALPHA,
    ‘d’: INPUT_DIGIT,
    ‘c’: INPUT_CHARACTER,
    }

    class MaskEntry(gtk.Entry):
    def __init__(self):
    gtk.Entry.__init__(self)
    # It only makes se
    self.modify_font(pango.FontDescription(“monospace”))
    self.set_property(‘editable’, True)
    self.set_size_request(90, -1)

    self.connect(‘insert-text’, self._on_insert_text)
    self.connect(‘delete-text’, self._on_delete_text)

    # List of validators
    # str -> static characters
    # int -> dynamic, according to constants above
    self._validators = []
    self._interactive_input = True
    self._mask = None

    # Callbacks

    def _on_insert_text(self, editable, new, length, position):
    if not self._interactive_input:
    return

    if length != 1:
    print ‘TODO: paste’
    self.stop_emission(‘insert-text’)
    return

    position = self.get_position()
    next = position + 1
    validators = self._validators
    if len(validators) next + 1:
    if (isinstance(validators[next], str) and
    isinstance(validators[next+1], int)):
    # Ugly: but it must be done after the parent
    # inserts the text
    gobject.idle_add(self.set_position, next+1)

    def _on_delete_text(self, editable, start, end):
    if not self._interactive_input:
    return
    if end – start != 1:
    print ‘TODO: cut/delete several’
    self.stop_emission(‘delete-text’)
    return

    validator = self._validators[start]
    if isinstance(validator, str):
    self.set_position(start)
    self.stop_emission(‘delete-text’)
    return

    self.insert_text(‘ ‘, end)
    return False

    # Public API

    def set_mask(self, mask):
    “””
    Sets the mask of the Entry.
    The format of the mask is similar to printf, but the
    only supported format characters are:
    – ‘d’ digit
    – ‘a’ alphabet, honors the locale
    – ‘c’ any character
    A digit is supported after the control.
    Example mask for a ISO-8601 date
    >>> entry.set_mask(‘%4d-%2d-%2d’)
    HACK for erase data > set_mask(‘%0d’)

    @param mask: the mask to set
    “””

    self._mask = mask
    if not mask:
    return

    input_length = len(mask)
    keys = INPUT_FORMATS.keys()
    lenght = 0
    pos = 0
    while True:
    if pos >= input_length:
    break
    if mask[pos] == ‘%’:
    s = ”
    format_char = None
    # Validate/extract format mask
    pos += 1
    while True:
    if mask[pos] not in string.digits:
    raise MaskError(
    “invalid format padding character: %s” % mask[pos])
    s += mask[pos]
    if mask[pos+1] in INPUT_FORMATS:
    format_char = mask[pos+1]
    break
    pos += 1
    pos += 1
    self._validators += [INPUT_FORMATS[format_char]] * int(s)
    else:
    self._validators.append(mask[pos])
    pos += 1

    s = ”
    for validator in self._validators:
    if isinstance(validator, int):
    s += ‘ ‘
    elif isinstance(validator, str):
    s += validator
    else:
    raise AssertionError
    self.set_text(s)

    def get_field_text(self):
    “””
    Get the fields assosiated with the entry
    if a field is empty it’ll return an empty string
    otherwise it’ll include the content

    @returns: fields
    @rtype: list of strings
    “””
    if not self._mask:
    raise MaskError(“a mask must be set before calling get_field_text”)

    def append_field(fields, field_type, s):
    if s.count(‘ ‘) == len(s):
    s = ”
    if field_type == INPUT_DIGIT:
    s = int(s)
    fields.append(s)

    fields = []
    pos = 0
    s = ”
    field_type = -1
    text = self.get_text()
    validators = self._validators
    while True:
    if pos >= len(validators):
    append_field(fields, field_type, s)
    break

    validator = validators[pos]
    if isinstance(validator, int):
    s += text[pos]
    field_type = validator
    else:
    append_field(fields, field_type, s)
    s = ”
    field_type = -1
    pos += 1

    return fields

    def set_text(self, text):
    “””
    Sets the text of the entry

    @param text:
    “””
    self._interactive_input = False
    try:
    gtk.Entry.set_text(self, text)
    finally:
    self._interactive_input = True

    def delete_text(self, start, end):
    “””
    Deletes text at a certain range

    @param start:
    @param end:
    “””
    self._interactive_input = False
    try:
    gtk.Entry.delete_text(self, start, end)
    finally:
    self._interactive_input = True

    def insert_text(self, text, position=0):
    “””
    Insert text at a specific position

    @param text:
    @param position:
    “””
    self._interactive_input = False
    try:
    gtk.Entry.insert_text(self, text, position)
    finally:
    self._interactive_input = True

    class Exec(object):
    “””
    Janela principal
    “””

    def __init__(self):
    “””
    Inicializa a classe
    “””

    # Carrega a interface
    self.tree = gtk.glade.XML(‘caixadata.glade’)

    self.w_main = self.tree.get_widget(‘main’)
    self.w_hbox = self.tree.get_widget(‘hbox1’)
    self.w_lbl = self.tree.get_widget(‘lbl’)
    self.w_txt = MaskEntry()
    self.w_txt.set_mask(‘%4d-%2d-%2d’)
    self.w_hbox.pack_start(self.w_txt,True,True)
    self.w_main.show_all()

    callbacks = {
    ‘on_main_destroy’: self.on_main_destroy,
    ‘on_ok_clicked’: self.on_ok_clicked
    }

    self.tree.signal_autoconnect(callbacks)

    def on_main_destroy(self, widget):
    raise SystemExit

    def on_ok_clicked(self, widget):
    txt = self.w_txt.get_text()
    self.w_lbl.set_label(txt)

    Exec()
    gtk.main()


Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google

Você está comentando utilizando sua conta Google. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s

%d blogueiros gostam disto: