Tkinter从按钮动态创建小部件

时间:2017-10-24 06:25:38

标签: python tkinter tkinter-entry

我正在尝试创建一个动态GUI,单击按钮会导致创建一个新框架,该框架位于按钮上方,其中有3个条目小部件(用户选项),我需要能够阅读来自3个条目小部件的用户输入&可能改变他们。每次按下按钮时,都会出现三个新的可调用条目小部件。

我知道这是错误的,因为它一直给我错误,但是可以使用与列表类似的东西动态创建小部件吗?

from Tkinter import *

app = Tk()

frameNames = []
widgetNames = []

def createwidgets():
    global widgetNames
    global frameNames
    frameNames += (str("g"+str(len(frameNames))))  #why does the letter & number get added as seperate elements?
    widgetNames += [(str("w"+str(len(widgetNames)-1))), 
                    (str("w"+str(len(widgetNames)))),    
                    (str("w"+str(len(widgetNames)+1)))]

    frameNames[len(frameNames) - 1] = Frame(app)
    frameNames[len(frameNames) - 1].pack()

    widgetNames[len(widgetNames) - 3] = Entry(frameNames[len(frameNames) - 1])
    widgetNames[len(widgetNames) - 3].pack()
    widgetNames[len(widgetNames) - 2] = Entry(frameNames[len(frameNames - )- 1])
    widgetNames[len(widgetNames) - 2].pack()
    widgetNames[len(widgetNames) - 1] = Entry(frameNames[len(frameNames) - 1])
    widgetNames[len(widgetNames) - 1].pack()

createWidgetButton = Button(app, text="createWidgets", command=createwidgets())
createWidgetButton.grid(sticky=S)

app.mainloop()

2 个答案:

答案 0 :(得分:0)

这相对简单。

我们可以通过创建一个Frame窗口小部件但不打包它,用我们需要的任何内容填充它,然后Button调用Frame窗口小部件。

与以下内容非常相似:

from tkinter import *

class App:
    def __init__(self, root):
        self.root = root
        self.create = Button(self.root, text="Create", command=self.draw)
        self.create.pack(side="bottom")
        self.frame = Frame(self.root)
        self.entry1 = Entry(self.frame)
        self.entry2 = Entry(self.frame)
        self.entry3 = Entry(self.frame)
        self.entry1.pack()
        self.entry2.pack()
        self.entry3.pack()
        self.submit = Button(self.frame, text="Submit", command=self.command)
        self.submit.pack()
    def draw(self):
        self.frame.pack(side="top")
    def command(self):
        print(self.entry1.get())
        print(self.entry2.get())
        print(self.entry3.get())

root = Tk()
App(root)
root.mainloop()

如果您需要添加多个这些表单,您可以执行类似下面的操作,使用匿名函数(lambda),以便自我识别"哪些按钮"知道"他们在哪个框架中:

from tkinter import *

class App:
    def __init__(self, root):
        self.frames = []
        self.entries = []
        self.count = 0
        self.root = root
        self.create = Button(self.root, text="Create", command=self.draw)
        self.create.pack(side="bottom")
    def draw(self):
        self.frames.append(Frame(self.root, borderwidth=1, relief="solid"))
        self.frames[self.count].pack(side="top")
        self.entries.append([Entry(self.frames[self.count]), Entry(self.frames[self.count]), Entry(self.frames[self.count])])
        for i in self.entries[self.count]:
            i.pack()
        Button(self.frames[self.count], text="Submit", command=lambda c=self.count: self.submit(c)).pack()
        self.count += 1
    def submit(self, c):
        for i in self.entries[c]:
            print(i.get())

root = Tk()
App(root)
root.mainloop()

答案 1 :(得分:0)

主要问题是这四行代码:

frameNames[len(frameNames) - 1] = Frame(app)
frameNames[len(frameNames) - 1].pack()
...
createWidgetButton = Button(app, text="createWidgets", command=createwidgets())
createWidgetButton.grid(sticky=S)

您正在创建框架和按钮作为app的子项,但您使用grid表示另一个,pack表示另一个。app。您必须与pack的所有直接后代保持一致 - 他们必须全部使用grid,否则他们必须全部使用frameNames += (str("g"+str(len(frameNames)))) #why does the letter & number get added as seperate elements?

第二个问题是这一行:

frameNames

此处,frameNames.append(str(...)) 是一个列表,您尝试使用字符串添加它。添加与追加不同。您需要附加新名称,或在添加新名称之前将其放入临时列表中。

createWidgetButton = Button(app, text="createWidgets", command=createwidgets())

第三个问题是这一行:

result = createWidgets()
createWidgetButton = Button(app, text="createWidgets", command=result)

以上内容完全相同:

createWidgets

您必须将引用传递给函数,而不是调用函数。将行更改为此(注意createWidgetButton = Button(app, text="createWidgets", command=createwidgets) 之后缺少括号):

(str("w"+str(len(widgetNames)-1)

与问题无关,但如果使用临时变量而不是重复模式import Tkinter as tk app = tk.Tk() frames = [] widgets = [] def createwidgets(): global widgetNames global frameNames frame = tk.Frame(app, borderwidth=2, relief="groove") frames.append(frame) frame.pack(side="top", fill="x") for i in range(3): widget = tk.Entry(frame) widgets.append(widget) widget.pack(side="left") createWidgetButton = tk.Button(app, text="createWidgets", command=createwidgets) createWidgetButton.pack(side="bottom", fill="x") app.mainloop() ,则代码将 更容易阅读。如上所述,您的代码几乎无法阅读。此外,您不希望存储小部件名称,您需要自己存储实际的小部件。

最后,不要进行通配符导入。没有充分的理由去做。

以下是我重写代码的方法:

<div [ngStyle]="{'display':'flex', 'flex-direction':'column', 'width': '100vw', 'height': '100vh'}">
  <top-header>
    <a class="topHeaderItem" (click)="goToHome()">Home</a>
    <a class="topHeaderItem" (click)="gotoTOC()">Contents</a>
  </top-header>