Tkinter 从按钮动态创建小部件
Tkinter dynamically create widgets from button
我正在尝试创建一个动态 GUI,在该 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()
这个比较简单
我们可以通过创建一个 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
) 来获得 "self aware" 个按钮,其中 "know"他们在哪个帧:
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()
主要问题是这四行代码:
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)
您必须将 reference 传递给函数,而不是 call 函数。将此行更改为(注意 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()
我正在尝试创建一个动态 GUI,在该 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()
这个比较简单
我们可以通过创建一个 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
) 来获得 "self aware" 个按钮,其中 "know"他们在哪个帧:
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()
主要问题是这四行代码:
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)
您必须将 reference 传递给函数,而不是 call 函数。将此行更改为(注意 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()