Adding placeholders to tkinter Entry widget in a procedural way

后端 未结 4 1262
独厮守ぢ
独厮守ぢ 2021-01-25 13:20

I know this Q has been answered in this site, but im looking for a more simpler answer, and ive seen one before but then the question has been deleted or something, I cant find

4条回答
  •  有刺的猬
    2021-01-25 14:12

    Here is a very simple example. In this example we include a couple of features/caveats:

    • ghost text for the placeholder
    • entry.input will return None if it's text is the placeholder or empty
    • entry.input should be used in place of .get() and .insert(). The .input logic is designed to give you the proper results for this type of widget. .get() is not smart enough to return the proper data, and .insert() has been reconfigured as a proxy to .input
    • placeholder is juggled while you type
    • placeholder can be overwritten with .insert() ~ no need to use .delete(). You should still use entry.input instead

    #widgets.py
    
    import tkinter as tk
    
    class PlaceholderEntry(tk.Entry):
        '''
            All Of These Properties Are For Convenience
        '''
        @property
        def input(self):
            return self.get() if self.get() not in [self.__ph, ''] else None
            
        @input.setter
        def input(self, value):
            self.delete(0, 'end')
            self.insert(0, value)
            self.configure(fg = self.ghost if value == self.__ph else self.normal)
        
        @property
        def isempty(self) -> bool:
            return self.get() == ''
        
        @property     
        def isholder(self) -> bool:
            return self.get() == self.__ph
            
        def __init__(self, master, placeholder, **kwargs):
            tk.Entry.__init__(self, master, **{'disabledforeground':'#BBBBBB', **kwargs})
            
            self.normal = self['foreground']
            self.ghost  = self['disabledforeground']
            
            self.__ph = placeholder
            self.input = placeholder
            
            vcmd = self.register(self.validate)
            self.configure(validate='all', validatecommand=(vcmd, '%S', '%s', '%d'))
            
            self.bind('' , self.focusin)
            self.bind('', self.focusout)
            self.bind(''     , self.check)
        
        #rewire .insert() to be a proxy of .input
        def validate(self, action_text, orig_text, action):
            if action == '1':
                if orig_text == self.__ph:
                    self.input = action_text
                
            return True
        
        #removes placeholder if necessary    
        def focusin(self, event=None):
            if self.isholder:
                self.input = ''
        
        #adds placeholder if necessary    
        def focusout(self, event=None):
            if self.isempty:
                self.input = self.__ph
        
        #juggles the placeholder while you type    
        def check(self, event):
            if event.keysym == 'BackSpace':
                if self.input and len(self.input) == 1:
                    self.input = self.__ph
                    self.icursor(0)
                    return 'break'
            elif self.isholder:
                if event.char:
                    self.input = ''
                else:
                    return 'break'
    

    usage example:

    #__main__.py
    
    import tkinter as tk
    import widgets as ctk #custom tk                
                    
    
    if __name__ == "__main__":
        root = tk.Tk()
        root.title("Placeholder Entry")
        root.grid_columnconfigure(2, weight=1)
    
        #init some data
        entries    = [] #for storing entry references
        label_text = ['email', 'name']
        entry_text = ['you@mail.com', 'John Smith']
    
        #create form
        for n, (label, placeholder) in enumerate(zip(label_text, entry_text)):
            #make label
            tk.Label(root, text=f'{label}: ', width=8, font='consolas 12 bold', anchor='w').grid(row=n, column=0, sticky='w')
            #make entry
            entries.append(ctk.PlaceholderEntry(root, placeholder, width=14, font='consolas 12 bold'))
            entries[-1].grid(row=n, column=1, sticky='w')
    
        #form submit function
        def submit():
            for l, e in zip(label_text, entries):
                if e.input:
                    print(f'{l}: {e.input}')
    
        #form submit button        
        tk.Button(root, text='submit', command=submit).grid(column=1, sticky='e')
    
        root.mainloop()
            
        
        
    

提交回复
热议问题