自动向 tkinter 中的输入框添加破折号 [英] Auto add dashes to entryboxes in tkinter

查看:33
本文介绍了自动向 tkinter 中的输入框添加破折号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当用户输入他们的电话号码时,有没有办法在电话号码中自动添加破折号,比如电话号码是 5551111234,但是当他们在输入框中输入时,该号码应该显示为带有连字符 b/w 的号码自动喜欢555-1111234.

Is there a way to auto add dashes in a phone number when the person types their phone number like for say phone number is 5551111234, but when they type it in the entry box the number should appear with hyphen b/w the number automatically like 555-1111234.

推荐答案

这是一个复杂的例子,但它处理的不仅仅是电话号码.被评论死了.

This is a complex example, but it handles more than just phone numbers. It is commented to death.

#widgets.py

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)


''' FormEntryFormat_dc
    this serves as a configuration for the behavior of FormEntry
'''
@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)   


''' FormEntry
    an entry with format behavior
'''
class FormEntry(tk.Entry):
    @property
    def input(self) -> str:
        return self.get()
        
    def offset(self, 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(self.input):
            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
    
    def __init__(self, master, frmt:FormEntryFormat_dc, **kwargs):
        tk.Entry.__init__(self, master, **kwargs)
        
        self.valid = frmt.valid
        if self.valid:
            #register validatecommand and assign to options
            vcmd = self.register(self.validate)
            self.configure(validate="all", validatecommand=(vcmd, '%P'))
            
        if frmt.marks and frmt.separator:
            #bind every key to formatting
            self.bind('<Key>', lambda e: self.format(e, frmt.separator, frmt.marks, frmt.strict))
        
    def validate(self, text:str):      
        return not (self.valid.match(text) is None) #validate with regex

    def format(self, event, separator:str, marks:Iterable, strict:bool):
        if event.keysym != 'BackSpace':             #allow backspace to function normally
            i = self.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+self.offset(separator, marks) in marks:
                    event.char = f'{separator}{event.char}'
                    
            self.insert(i, event.char)              #validation will check if this is allowed
            
            return 'break'


#main.py (OOP style)

import widgets as ctk #custom tk
import tkinter as tk

class Main(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        
        self.title("Formatted Entry")

        self.grid_columnconfigure(2, weight=1)

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

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


Main().mainloop() if __name__ == "__main__" else None


#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()

这篇关于自动向 tkinter 中的输入框添加破折号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆