如何使用绑定“ <return>”来调用函数

时间:2019-01-24 16:11:16

标签: python tkinter tkinter-entry

我知道我的问题听起来很像以前的许多问题,但是老实说我不能在我的程序上下文中弄清楚它。我有一个Collat​​z猜想的算法,我想通过Tkinter GUI运行(一切都可以在终端上正常运行)。我试图将相关函数绑定到Return键和按钮上,但是遇到相同的错误两种输入数据方法的提示信息,我将在下面显示。如果通过终端输入,我的输出将在GUI上完美运行。

我尝试过的方法最好通过下面的代码来解释。 (####行上方的代码主要与使GUI出现在我的Spyder IDE上而不是隐藏在它的后面有关。)

代码:

from tkinter import *
root = Tk()

import os
import subprocess
import platform

def raise_app(root: Tk):
    root.attributes("-topmost", True)
    if platform.system() == 'Darwin':
        tmpl = 'tell application "System Events" to set frontmost of every process whose unix id is {} to true'
        script = tmpl.format(os.getpid())
        output = subprocess.check_call(['/usr/bin/osascript', '-e', script])
    root.after(0, lambda: root.attributes("-topmost", False))
########################################################################

lst = []

def collatz(num):
    while num != 1:
        lst.append(num)

        if num % 2 == 0:
            num = int(num / 2)

        else:
            num = int(3 * num + 1)

def main(event):

    collatz(num)

#Input Box
input = Entry(root, width = 10, bg = "light grey")
input.grid(row = 0, column = 0, sticky = W)
input.get()
input.bind("<Return>", main)

##Button
#button1 = Button(root, width = 10, text = "Run", command = main)
#button1.grid(row = 1, column = 0, sticky = W)

##Output box
output1 = Text(root, width = 100, height = 10, bg = "light grey")
output1.grid(row = 3, column = 0, sticky = W)
output2 = Text(root, width = 50, height = 1, bg = "white")
output2.grid(row = 2, column = 0, sticky = W)

output1.insert(END, lst)
output2.insert(END, "Number of iterations are: " + str(len(lst)))


########################################################################

raise_app(root)
root.mainloop()

按原样运行代码时,会出现输入框,但是当我单击return时,会出现错误消息:

Exception in Tkinter callback
Traceback (most recent call last):
  File "/anaconda3/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
    return self.func(*args)
  File "/Users/andrehuman/Desktop/Python/programs/Collatz Conjecture/Collatz_alt3.py", line 43, in main
    collatz(num)
NameError: name 'num' is not defined

如果我尝试将按钮链接到“主要”功能,则完全相同。

当我注释输入并按下按钮,然后通过终端输入数字时,一切都会按预期进行。迭代编号的列表应出现在文本框中。 (而且我什至可以得到Matplotlib图,以便在终端中直观地显示数据。)如果可以解决此问题,我想尝试在GUI中显示(或嵌入)Matplotlib图。

反正就是这样。任何帮助将不胜感激。

安德烈·人类

1 个答案:

答案 0 :(得分:2)

出现

name 'num' is not defined的原因是您正在调用collatz(num),但是当您说num时,程序无法理解您指的是什么值。您应该在使用该名称之前为其分配一个值。我假设您希望该值成为input框中的内容。

def main(event):
    num = int(input.get())
    collatz(num)

您还需要将output1.insertoutput2.insert行复制到main的内部。现在,这些行在窗口甚至没有显示给用户之前就已执行,因此它们无法输入足够快的数字以使collatz在文本被写入之前触发。并且在事实结束后更改lst不会对文本产生任何影响,因为它不够聪明,无法注意到列表已更改。

def main(event):
    num = int(input.get())
    collatz(num)
    #delete previous contents of text boxes
    output1.delete(1.0, END)
    output2.delete(1.0, END)
    output1.insert(END, lst)
    output2.insert(END, "Number of iterations are: " + str(len(lst)))

另一个问题是,对collatz的连续调用将导致lst不断增长,因为先前调用中的列表内容仍然存在。尝试在文本框中输入4,然后按Enter几次。输出将从2变为4到6 ...这是不对的。

使用可变全局状态时,这是自然危险。一种可能的解决方案是在每个collat​​z调用开始时重置lst

def collatz(num):
    lst.clear()
    #rest of function goes here

...但是我更倾向于将lst设置为该函数的局部变量,并在最后将其返回。

def collatz(num):
    lst = []
    while num != 1:
        lst.append(num)

        if num % 2 == 0:
            num = int(num / 2)

        else:
            num = int(3 * num + 1)
    return lst

def main(event):
    num = int(input.get())
    lst = collatz(num)
    #delete previous contents of text boxes
    output1.delete(1.0, END)
    output2.delete(1.0, END)
    output1.insert(END, lst)
    output2.insert(END, "Number of iterations are: " + str(len(lst)))

#later, just before mainloop is called...
#lst doesn't exist in this scope, so just set the text to a literal value
output1.insert(END, "[]")
output2.insert(END, "Number of iterations are: 0")