在Python 3.5.2中使用tkinter实现当按钮被按下时从输入框更新标签的功能。

3

我想创建一个窗口,其中包含一条标签、一个输入框、一个当前值标签和一个“更新值”按钮。

以下是示例:

enter image description here

目前我已经完成了如下内容。我可以将输入的值打印到控制台,但我似乎无法弄清楚如何通过按按钮来获取输入的值并更改“currentValue”标签以反映该值:

from tkinter import*
main=Tk()

#StringVar for currentValue in R0C2
currentValue = StringVar(main, "0")

#Called by the setValues button, looks for content in the entry box and updates the "current" label
def setValues():
        content = entry.get()
        print(content)


#This kills the program
def exitProgram():
        exit()

#Title and window size
main.title("Title")
main.geometry("350x200")

#Descriptions on the far left
Label(main, text="Duration (min): ").grid(row=0, column=0)

#Entry boxes for values amidship
entry=Entry(main, width=10)
entry.grid(row=0, column=1)

#Displays what the value is currently set to.
currentValue = Label(textvariable=currentValue)
currentValue.grid(row=0,column=2)

#Takes any inputted values and sets them in the "Current" column using def setValues
setValues=Button(text='Set Values',width=30,command=setValues)
setValues.grid(row=9, column=0, columnspan=2)

#Red button to end program
exitButton=Button(main, text='Exit Program',fg='white',bg='red',width=30, height=1,command=exitProgram)
exitButton.grid(row=20, column = 0, columnspan=2)
main.mainloop()
3个回答

4

您的代码存在一些问题。

首先,您正在使用 setValues 按钮小部件覆盖 setValues 函数,类似地,您正在使用 currentValue 标签覆盖 currentValue StringVar。

要设置 StringVar,请使用其 .set 方法。

不要在脚本中使用普通的 exit,那只适用于交互式解释器会话,正确的退出函数是 sys.exit。但是,在 Tkinter 程序中,您可以直接调用根窗口的 .destroy 方法。

以下是修复后的代码版本。

import tkinter as tk
main = tk.Tk()

#StringVar for currentValue in R0C2
currentValue = tk.StringVar(main, "0")

#Called by the setValues button, looks for content in the entry box and updates the "current" label
def setValues():
    content = entry.get()
    print(content)
    currentValue.set(content)

#This kills the program
def exitProgram():
    main.destroy()

#Title and window size
main.title("Title")
main.geometry("350x200")

#Descriptions on the far left
tk.Label(main, text="Duration (min): ").grid(row=0, column=0)

#Entry boxes for values amidship
entry = tk.Entry(main, width=10)
entry.grid(row=0, column=1)

#Displays what the value is currently set to.
currentValueLabel = tk.Label(textvariable=currentValue)
currentValueLabel.grid(row=0,column=2)

#Takes any inputted values and sets them in the "Current" column using def setValues
setValuesButton = tk.Button(text='Set Values',width=30,command=setValues)
setValuesButton.grid(row=9, column=0, columnspan=2)

#Red button to end program
exitButton = tk.Button(main, text='Exit Program',fg='white',bg='red',width=30, height=1,command=exitProgram)
exitButton.grid(row=20, column = 0, columnspan=2)
main.mainloop()

顺便提一下,避免使用“星号”导入是个好主意。像这样 from tkinter import * 将130个名称导入了你的命名空间中,这是不必要的,也会产生名称冲突的可能性,特别是如果你从几个模块中进行星号导入。它还使代码可读性变差,因为读者必须记住哪些名称是你定义的,哪些来自导入的模块。


谢谢,这正好得到了我想要的结果,现在我也明白了我犯错的各个地方。此外,它还解决了我因相关错误而苦苦挣扎的其他一些问题。 - Agent
@Agent 正如Ethan所指出的那样,有许多方法可以改善您代码的逻辑和组织;我只是想用最少的修改使您的代码正常工作。 - PM 2Ring
1
我很感激 :) 这是我第一天尝试用Python编写GUI,我只是将所有东西排列出来,以便在自己的上下文中轻松地看到和理解它为什么有效或无效,我真的只是通过小步学习如何做每件事。我知道它看起来有点尴尬,但一旦我更好地了解这些东西为什么会发生,我就可以学习如何将其优化并将其放入功能程序中。 - Agent
@Agent 考虑到这是你的 GUI 编程的第一天,你做得很不错。有很多东西要学习,而且理解事件驱动编程需要一定时间,但是随着实践,就像编程中的大多数事情一样,最终会掌握。 - PM 2Ring

3
在我看来,最简单的方法是使用面向对象的方法。这样,您可以声明一个带有调用defcommandbutton,该def运行self.label.configure(text=self.entry.get())
以下是示例:
import tkinter as tk

class App:
    def __init__(self, master):
        self.master = master
        self.label = tk.Label(self.master)
        self.entry = tk.Entry(self.master)
        self.button = tk.Button(self.master, text="Ok", command=self.command)
        self.label.pack()
        self.entry.pack()
        self.button.pack()
    def command(self):
        self.label.configure(text=self.entry.get())

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

上述代码创建了一个`label`(标签)、一个`entry`(输入框)和一个`button`(按钮)。`button`(按钮)有一个`command`(命令),它调用了`class`(类)`App`中的一个`def`(函数),并将`label`(标签)的值更新为`entry`(输入框)中包含的文本。
这一切都非常顺畅、干净,更重要的是,在我看来,未来阅读和更新都会大大简化。

@PM2Ring 已更新以达成安抚目的 ;) - Ethan Field
@PM2Ring 请创建一个新账户并再次点赞,谢谢。 - Ethan Field
我会考虑这个建议。 - Ethan Field
感谢您的输入,对于我来说,使用类是“未知领域”,但当时机成熟时,我会接受所有建议。就像我在另一篇帖子中所说的那样,现在我还只是在“蹒跚学步”。 - Agent
1
@Agent,这很容易理解,当与tkinter一起使用时,类可以非常有用。当我开始使用Python时,我并没有考虑过使用它,但是一旦你理解了它,你会希望早点看到它。此外,我不确定您正在使用哪个tkinter文档,但是http://effbot.org/tkinterbook/是与任何与tkinter相关的内容有关的最好的朋友。 - Ethan Field

1
从您的代码中可以看出,您正在设置“currentValue”,这是一个 StringVar
#StringVar for currentValue in R0C2
currentValue = StringVar(main, "0")

你不能在代码中进一步将标签对象转换为下一个对象。请注意!

 #Displays what the value is currently set to.
    currentValue = Label(textvariable=currentValue) ** this line is wrong
    currentValue.grid(row=0,column=2)

您应该将标签命名为不同的名称,例如:

#Displays what the value is currently set to.
        lblCurrentValue = Label(textvariable=currentValue)
         lblCurrentValue.grid(row=0,column=2)

在你的“setValues”方法中,你应该使用'StringVar.set(value)'来更新标签,如下所示:
def setValues():
    content = entry.get()
    currentValue.set(entry.get())------------------Here I set the value to the entry box value
    print(content)

我倾向于避免使用stringVar,而直接使用:

Label.config(text='*label's text*')

如果你需要更多帮助,我可以发布我的解决方案,但是请先尝试自己解决问题,因为这是最好的学习方式。我的提示是确保你使用正确的命名约定。在tkinter中,我倾向于在小部件之前使用lbl...,entryBox...等来命名,这样我就知道它们是什么,不会将它们与变量混淆。

感谢您的反馈,我之前没有意识到我一直在用标签对象覆盖我的变量,但现在这很有道理。此外,有什么特别的原因要避免使用stringVar吗?它是否有被认可的“正确”和“不正确”的用法,还是只是个人偏好?我还是Python的新手,正在努力学习最佳实践。 - Agent
嗨,只是个人偏好。我这个月才开始使用tkinter。如果stringvar对象在许多地方使用,那么更新该变量比单独更新每个Label对象要好。缺点是当您遇到错误时,您可能会想“为什么这个标签没有更新!”那是因为您分配了'label(self,text ='some text')' 而不是 'Label(self,textvariable ='some text')'对于新手来说,可能更难阅读您的代码并查看为什么某些内容没有更新,但两者都可以。 :) - Daniel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接