0
votes

Auto Ajouter des tirets à des entrées dans Tkinter

Y a-t-il un moyen d'ajouter automatiquement des tirets dans un numéro de téléphone lorsque la personne tape son numéro de téléphone que leur numéro de téléphone est 5551111234, mais lorsqu'il le saisit dans la case d'entrée, le nombre doit apparaître avec un trait d'entraînement B / W. Automatiquement comme 555-1111234 .


0 commentaires

3 Réponses :


1
votes

J'ai utilisé une combinaison de Cet exemple de traçage variables tkinter et y combiné avec Cette réponse , je ne suis pas sûr à 100% s'il s'agit du formatage correct américain parce que je vis dans le Royaume-Uni et nous formatons les choses différemment ici, mais c'est l'exemple approximatif de la manière dont cela fonctionnerait: xxx

alternative xxx

ceci était Ma solution, en utilisant phonumbers de PYPI, qui semblait le faire fonctionner.


5 commentaires

Appréciez cela, mais la mise en forme est assez gâchée, avez-vous essayé ce surn?


Désolé, je suis confus, juste copié et collé cela et cela a fonctionné sur mon système? Quels EEMS ÊTRE LE PROBLÈME?


L'étiquette n'est pas aussi identique que WT que nous tapons dans l'entréebox


@Coolcloud Cela devrait être corrigé maintenant! Pardon


La même erreur vient, essayez d'entrer 055 au début et vous pourriez le remarquer



1
votes

Ceci est un exemple complexe, mais il gère plus que des numéros de téléphone. Il est commenté à mort.

#main.py (procedural style)

import widgets as ctk #custom tk
import tkinter as tk

if __name__ == "__main__":
    root = tk.Tk()
    root.title("Formatted Entry")
    root.grid_columnconfigure(2, weight=1)

    #create labels
    labels = ['time', 'date', 'phone', 'phone2']
    for n, label in enumerate(labels):
        tk.Label(root, text=f'{label}: ', width=14, font='consolas 12 bold', anchor='w').grid(row=n, column=0, sticky='w')

    #create entries
    entries = []
    for n, format in enumerate([ctk.TimeFormat, ctk.DateFormat, ctk.PhoneFormat, ctk.PhoneFormat2]):
        entries.append(ctk.FormEntry(root, format, width=14, font='consolas 12 bold'))
        entries[-1].grid(row=n, column=1, sticky='w')
     
    def submit():
        for l, e in zip(labels, entries):
            print(f'{l}: {e.input}')
            
    #form submit button        
    tk.Button(root, text='submit', command=submit).grid(column=1, sticky='e')
    
    root.mainloop()


15 commentaires

Merci pour cette réponse incroyable et votre temps à ce sujet, mais y a-t-il un moyen sans cours? Alors que mon interface graphique ne dispose d'aucune classe et de mettre en œuvre des cours uniquement dans le but de cela est un peu trop excédentaire?


@CoolCloud ~ Chaque widget que vous utilisez dans tkinter est une classe, y compris tk et toplevel . Si la mise en œuvre d'une classe a été surchargée pour votre projet, vous ne pouvez pas utiliser tkinter , du tout. En outre, j'ai édité ma réponse depuis votre commentaire. J'ai trouvé 2 minuscules bugs et les corrigé.


@CoolCloud ~ j'ai mis à jour mon exemple avec 2 Exemple main.py . L'un est le style OOP et l'autre est procédural.


Merci pour votre temps, je vais vérifier bientôt et l'accepterai


Wow, cela fonctionne comme un charme, mais comment puis-je obtenir les données de la boîte d'entrée? get () la méthode semble ne pas fonctionner


@CoolCloud ~ Je n'ai pas fait de références dans mon exemple. Vous devez commencer par faire une référence (ex :) time = ctk.formatentry (root, tformat) , puis vous pouvez utiliser temps.input . .Input est un en lecture seule de sorte que vous l'appelez comme un var, pas une méthode / une fonction.


Okay, ce qui vous a obtenu, de toute façon pour changer le format un peu, comme actuellement il est 123-102-1712 et le faire 101-1203215


Laissez-nous Continuez cette discussion en chat .


@Coolcloud ~ Tout est corrigé


Stackoverflow.com/Questtions/63651586/... Vous y allez;)


Hey, bonjour, pouvez-vous me dire quel formentryformat_dc (re.cètez ('^ (\ d {1,3} (- (\ d {1,7})?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?) - ', [3], true) serait pour un numéro censé insérer - dans le format 12345-12345-12345


@CoolCloud ~ FORMENRYFORMAT_DC (RECOMPILE ('^ (\ D {1,5} (- (\ D {1,5} (- (\ D {1,5})?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)? )?)? $ '),' - ', [5, 11], True) . C'est assez simple. Vous voulez 5 caractères, Dash, 5 caractères, Dash, 5 caractères. Ainsi, tournez simplement le numéro maximum sur 5 dans les gammes de regex et personnalisez la liste de positions pour les positions de tiret appropriées ([5, 11]). N'oubliez pas que cette regex ne vaut que la validation de votre type. Cela ne se soucie pas de ce que le résultat final est. C'est pourquoi il y a des gammes de 1 à max. Cela doit le faire pour vous permettre de taper.


Merci mec!!! Pouvez-vous m'aider une fois de plus? Trop petit pour demander comme q, une idée de la manière de permettre seulement 5 numéros sur un champ d'entrée? Sans utiliser Regex ou quelque chose?


@CoolCloud ~ Capturez simplement la saisie dans le champ et ne permettez-la que d'ajouter de nouveaux caractères si la chaîne actuelle a une longueur inférieure à 5. Utilisez VCMD . De cette façon, vous pouvez simplement retour len (entrée.get (get (Get ()) <5) , lequel si faux, ne tapera pas le caractère.


@CoolCloud ~ Cependant, vous voudrez vous assurer que la phrase était un personnage réel avant de faire ce retour. Par exemple, si entrée.get.get () a une longueur de 5 et vous appuyez sur Backspace Il reviendra toujours sur la fausse et interdire la backpace de se produire.



1
votes

Voici un exemple de procédure. L'exemple est très fortement commenté.

import tkinter as tk, re
from dataclasses import dataclass, field
from typing import List, Pattern, Iterable
from copy import deepcopy

Char: Pattern = re.compile('[a-z0-9]', re.I)


''' FormField_dc
    this serves as a configuration for the behavior of form_field
'''
@dataclass
class FormEntryFormat_dc:
    valid      :Pattern        = None                        #pattern to validate text by
    separator  :str            = None                        #the separator to use
    marks      :List           = field(default_factory=list) #list of positions to apply separator
    strict     :bool           = False                       #True|False strict typing
        
    def config(self, ascopy:bool=True, **data):
        c = deepcopy(self) if ascopy else self
        for key in c.__dict__:
            if key in data:
                c.__dict__[key] = data[key]                  #assign new value
        return c
    
    
#prepare a few formats        
TimeFormat   = FormEntryFormat_dc(re.compile('^(\d{1,2}(:(\d{1,2}(:(\d{1,2})?)?)?)?)?$'      ), ':' , [2, 5])
DateFormat   = FormEntryFormat_dc(re.compile('^(\d{1,2}(\\\\(\d{1,2}(\\\\(\d{1,4})?)?)?)?)?$'), '\\', [2, 5])
PhoneFormat  = FormEntryFormat_dc(re.compile('^(\d{1,3}(-(\d{1,3}(-(\d{1,4})?)?)?)?)?$'      ), '-' , [3, 7], True)   
PhoneFormat2 = FormEntryFormat_dc(re.compile('^(\d{1,3}(-(\d{1,7})?)?)?$'                    ), '-' , [3]   , True)   


''' FormField
    An entry field intended to force a specific format while the user types
'''
def form_field(master, f:FormEntryFormat_dc, **kwargs) -> tk.Entry:
    entry = tk.Entry(master, **kwargs)
    
    def offset(separator:str, marks:Iterable):
        sep_marks = [] #cache for positions of already inserted separators
        offset    = 0  #the overall offset between inserted and expected separator marks
        
        #get a mark for every current separator
        for i, c in enumerate(entry.get()):
            if c == separator:
                sep_marks.append(i)
        
        #if any sep_marks ~ subtract the value of sep_marks last index 
        #~from the value of the corresponding index in marks
        n = len(sep_marks)
        if n:       
            offset = max(0, marks[n-1]-sep_marks[-1])
            
        return offset
        
    #test text against validity conditions
    def validate(text):
        #if numeric check is True and len(text) > 0 
        return not (f.valid.match(text) is None) #validate with regex
        
    if f.valid:
        #register validatecommand and assign to options
        vcmd = entry.register(validate)
        entry.configure(validate="all", validatecommand=(vcmd, '%P'))
            
    #add separators when entry "insert" index equals a mark  
    #~and separator isn't already present
    def format(event, separator:str, marks:Iterable, strict:bool):
        #allow backspace to function normally
        if event.keysym != 'BackSpace':
            i = entry.index('insert')                #get current index
            if Char.match(event.char) is None and (i in marks or not strict):
                event.char = separator              #overwrite with proper separator
            else:
                #automatically add separator
                if i+offset(separator, marks) in marks:
                    event.char = f'{separator}{event.char}'
                    
            entry.insert(i, event.char)              #validation will check if this is allowed
            
            return 'break'
                
    
    if f.marks and f.separator:           
        #bind every keypress to formatting
        entry.bind('<Key>', lambda e: format(e, f.separator, f.marks, f.strict))
    
    
    return entry
    

##USAGE EXAMPLE
if __name__ == "__main__":
    root = tk.Tk()
    root.title("Formatted Entry")
    root.grid_columnconfigure(2, weight=1)

    #create labels
    labels = ['time', 'date', 'phone', 'phone2']
    for n, label in enumerate(labels):
        tk.Label(root, text=f'{label}: ', width=14, font='consolas 12 bold', anchor='w').grid(row=n, column=0, sticky='w')

    #create entries
    entries = []
    for n, format in enumerate([TimeFormat, DateFormat, PhoneFormat, PhoneFormat2]):
        entries.append(form_field(root, format, width=14, font='consolas 12 bold'))
        entries[-1].grid(row=n, column=1, sticky='w')
     
    def submit():
        for l, e in zip(labels, entries):
            print(f'{l}: {e.get()}')
            
    #form submit button        
    tk.Button(root, text='submit', command=submit).grid(column=1, sticky='e')
    
    root.mainloop()


0 commentaires