Tkinter中的文本输入

1 投票
4 回答
23814 浏览
提问于 2025-04-17 19:44

目标

我想写一个简单的文件,这样我就可以在其他程序中导入它。这个文件里会有一个简单的功能,可以接收用户输入,然后返回这个输入。

代码

为此,我写了以下代码:

class takeInput(object):

    def __init__(self,requestMessage,parent):

        self.string = ''
        self.frame = Frame(parent)
        self.frame.pack()        
        self.acceptInput(requestMessage)

    def acceptInput(self,requestMessage):

        r = self.frame

        k = Label(r,text=requestMessage)
        k.pack(side='left')
        self.e = Entry(r,text='Name')
        self.e.pack(side='left')
        self.e.focus_set()
        b = Button(r,text='okay',command=self.gettext)
        b.pack(side='right')

    def gettext(self):
        self.string = self.e.get()
        self.frame.destroy()
        print self.string

    def getString(self):
        return self.string

def getText(requestMessage,parent):
    global a
    a = takeInput(requestMessage,parent)
    return a.getString()

我还添加了一些脚本级别的代码来进行测试:

root = Tk()

getText('enter your name',root)

var = a.getString()

print var

root.mainloop()

让我感到困惑的是:

  1. var 这个变量没有我输入的值,它的值是空字符串 ''
  2. a.string 这个变量有我输入的值,我在命令行中检查过了。

另外 当我尝试把 a.getString() 返回的字符串赋值给 var 时,这在命令行中是可以工作的。

注意 我是刚开始学习 Tkinter 编程,对 mainloop() 的工作原理还不太了解。所以可能问题出在这里,但我不太确定。

规格

操作系统:Linux Mint 14

Python IDLE 2.7

帮我解决这个问题。

4 个回答

1

问题在于,你的测试代码在对话框显示之前就已经打印出了var的值,更不用说输入文本了。(你可以通过在测试代码中添加一些print语句来验证这一点。)这是因为mainloop()的调用是在最后的。相反,你应该在创建窗口后,但在读取和返回输入之前调用mainloop,比如可以放在你的getText方法里:

def getText(requestMessage,parent):
    a = takeInput(requestMessage,parent)
    parent.mainloop()
    return a.getString()

不过,这样做还是不太好,因为即使点击了“确定”,你还得关闭对话框(点击[x]按钮),我不太确定该怎么解决这个问题。

不过,要注意的是,实际上已经有一个模块可以做到这一点,叫做tkSimpleDialog,它提供了像askstring(title, prompt)这样的函数,可以显示输入对话框。所以你可以使用这些函数,或者查看源代码(在/usr/lib/python2.7/lib-tk等地方找到)来了解它是怎么实现的。

12

正如其他回答所说,你在进入主循环之前打印了var,也就是说在你的窗口实际上还没有运行的时候,你的程序就在等待用户输入了。

你可以使用tkSimpleDialog这个家族来获取用户输入:

import Tkinter
import tkSimpleDialog

root = Tkinter.Tk()
var = tkSimpleDialog.askstring("Name prompt", "enter your name")
print var

如果你想继续你自己的方式,可以在“确定”按钮的回调函数中进行打印(在你的情况下是gettext)。你也可以在按下“确定”时生成一个虚拟事件,并在你的主程序中绑定这个事件(http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/virtual-events.html

7

你的代码执行流程是这样的:

  • 主程序首先调用了 getText
  • getText 创建了一个 takeInput 对象,叫做 a
  • takeInput 对象自己初始化,创建了一些标签和按钮等。
  • getText 返回 a.getString(),这个方法返回 self.string,而这个值还是默认的空字符串。
  • 主程序打印了 var,结果是空的。

到现在为止,这一切都发生在几纳秒内。用户甚至还没看到窗口。

然后,主程序调用了 root.mainloop(),这才给用户一个与窗口互动的机会。但这时候已经太晚了,var 已经被打印出来了。

如果你希望 getText 在用户提交文本之前不返回,那么 mainloop 必须放在 getText 里面,而不是在它之后。

from Tkinter import *

class takeInput(object):

    def __init__(self,requestMessage):
        self.root = Tk()
        self.string = ''
        self.frame = Frame(self.root)
        self.frame.pack()        
        self.acceptInput(requestMessage)

    def acceptInput(self,requestMessage):
        r = self.frame

        k = Label(r,text=requestMessage)
        k.pack(side='left')
        self.e = Entry(r,text='Name')
        self.e.pack(side='left')
        self.e.focus_set()
        b = Button(r,text='okay',command=self.gettext)
        b.pack(side='right')

    def gettext(self):
        self.string = self.e.get()
        self.root.destroy()

    def getString(self):
        return self.string

    def waitForInput(self):
        self.root.mainloop()

def getText(requestMessage):
    msgBox = takeInput(requestMessage)
    #loop until the user makes a decision and the window is destroyed
    msgBox.waitForInput()
    return msgBox.getString()

var = getText('enter your name')
print "Var:", var

撰写回答