在tkinter中创建自定义小部件

时间:2015-05-27 17:27:08

标签: python tkinter

我想在tkinter中创建一个自定义窗口小部件,以便在实例化时显示标签和输入框。示例我创建了一个名为entry的类,并调用了.. entry('name',master),这将显示一个标签,其中文本为main,并且在输入框旁边。 我成功地做到了这一点,但问题在于几何管理器。他们似乎都搞乱了一切

3 个答案:

答案 0 :(得分:3)

您的小部件应该是Frame的子类。在框架内,您可以使用所需的任何几何管理器,而不会影响任何其他代码。重要的是,窗口小部件类调用gridpackplace本身 - 这是创建窗口小部件的函数的作用。创建窗口小部件的每个窗口小部件或函数都应该只担心布局其子窗口。

这是一个创建几个不同自定义小部件的示例。每个使用不同的几何管理器来说明它们不会相互干扰:

try:
    # python 3.x
    import tkinter as tk
except ImportError:
    # python 2.x
    import Tkinter as tk


class CustomWidget(tk.Frame):
    def __init__(self, parent, label, default=""):
        tk.Frame.__init__(self, parent)

        self.label = tk.Label(self, text=label, anchor="w")
        self.entry = tk.Entry(self)
        self.entry.insert(0, default)

        self.label.pack(side="top", fill="x")
        self.entry.pack(side="bottom", fill="x", padx=4)

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

class Example(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        self.label = tk.Label(self)
        self.e1 = CustomWidget(self, "First Name:", "Inigo")
        self.e2 = CustomWidget(self, "Last Name:", "Montoya")
        self.submitButton = tk.Button(self, text="Submit", command=self.submit)

        self.e1.grid(row=0, column=0, sticky="ew")
        self.e2.grid(row=1, column=0, sticky="ew")
        self.label.grid(row=2, column=0, sticky="ew")
        self.submitButton.grid(row=4, column=0)

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

    def submit(self):
        first = self.e1.get()
        last = self.e2.get()
        self.label.configure(text="Hello, %s %s" % (first, last))

if __name__ == "__main__":
    root = tk.Tk()
    Example(root).place(x=0, y=0, relwidth=1, relheight=1)
    root.mainloop()

答案 1 :(得分:1)

基于@Bryan Oakley 的回答,我确实有一些修改。我知道它以某种方式脱离了主题。这是从小部件返回一个值的方法,它只允许用户必须输入的整数到一定数量的数字。

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

答案 2 :(得分:0)

我同意奥克利先生。您应该子类化框架来完成您的工作。 执行所需操作的最简单方法是使用以下代码创建模块:

# 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

这将按如下方式使用:

# Main program
import tkinter
import AnnotatedEntry

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

我谨此以我的Scout Honor确认此代码已经过全面测试,并保证可以在Python 3.7.4中使用。话虽如此,目前尚无返回条目中包含的数据的方法。您将不得不自己解决这个问题。