'Creating a custom widget in tkinter

I want to create a custom widget in tkinter such that when instantiated, displays a label and an entry box. Example I created a class named entry and call as.. entry ('name', master ) and this would display a label with text as main along side an entry box. I have succeeded in doing that but my problem is with the geometry managers. they all seem to mess up everything



Solution 1:[1]

I agree with Mr. Oakley. You should subclass frame to do your job. The simplest way to do what you want is to create a module with the following code:

# AnnotatedEntry.py
def AnnotatedEntry(master, name="An annoted entry box"):
    '''
    As a little extra, name is a keyword-argument, which defaults to "An annotated
    entry box."
    '''
    import tkinter as tk
    overlord = tk.Frame(master, height=5, width=40)
    labeller = tk.Label(overlord, text=name, font="Times 14 bold")
    labeller.grid(sticky='new')

    inputter = tk.Entry(overlord, font="Times 14 bold")
    inputter.grid(sticky='sew', pady=(10,0))

    return overlord

This would be used as follows:

# Main program
import tkinter
import AnnotatedEntry

root = tkinter.Tk()
hold = AnnotatedEntry.AnnotatedEntry(root, name="Hello, world!")
hold.grid()

I hereby affirm, on my Scout Honor, that this code has been fully tested, and is guaranteed to work in Python 3.7.4. That being said, there is currently no method for returning the data contained in the Entry; you will have to work that out for yourself.

Solution 2:[2]

Based on @Bryan Oakley answer, I do have some modification. I know it's out of topic somehow. This is how to return a value from the widget and it only allows integer up to some number of digits that the user must entered.

#create a global value
global tbVal
tbVal = 0


class CustomWidget(tk.Frame):
    def __init__(self, parent, nDigits):
        tk.Frame.__init__(self, parent)

        self.entry = tk.Entry(self)
        self.entry.pack(side="bottom", fill="x", padx=4)
        self.entry.configure(validate='all',validatecommand=windows.register(self.sbValidate),'%P','%W',nDigits))

    def get(self):
        return self.entry.get()

    def sbValidate(self, userInput, widget, nDigits): 
        global tbVal
        tbVal = userInput

        if userInput == '':
            return True

        if '.'  in userInput or ' ' in userInput:
            return False

        n = len(userInput)
        if n > int(nDigits):
            return False

        try:
            val = int(float(userInput))
        except ValueError:
            return False

        return val

class Example(tk.Frame):
    def __init__(self, parent, nDigitsLimit):
        tk.Frame.__init__(self, parent)

        self.e1 = CustomWidget(self, nDigitsLimit)
        self.e1.grid(row=0, column=0, sticky="ew")

        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(2, weight=1)

def btnStartClick():
    print(tbVal)


nDigitsLimit = 8
tbTest = ttk.Entry(Example(windows, nDigitsLimit).place(x=20, y=20, relwidth=0.25, relheight=0.05))

btnStart = tk.Button(frame, text='Start', command=btnStartClick)
btnStart.place(relx=0.50, rely=0.50)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 The Daleks
Solution 2