簡體   English   中英

Python Tkinter-名稱未定義

[英]Python Tkinter - Name is not defined

碼:

def createLetters(frame, startX, startY, width, height, spacing):

    alphabet = ["A", "B", "C", "D", "E", "F", "G", "H", "I", 
                "J", "K", "L", "M", "N", "O", "P", "Q", "R", 
                "S", "T", "U", "V", "W", "X", "Y", "Z"]

    def letterAction(letter):
        letter.destroy()

    for i in range(0, 26):

        if (i >= 9 and i <= 17):
            y = startY +  height + 2 * spacing
            x = startX + ((width + spacing) * (i - 9))

        elif (i >= 17):
            y = startY + 2 * height + 3 * spacing
            x = (width + spacing) / 2 + startX + ((width + spacing) * (i - 18))

        elif (i <= 8):
            y = startY + spacing
            x = startX + ((width + spacing) * i)

        exec(alphabet[i] + " = Button(" + frame + ", text = '" + alphabet[i] + "', command = letterAction(" + alphabet[i] + "))")
        exec(alphabet[i] + ".place(x = " + str(x) + ", y = " + str(y) + ", width = " + str(width) + ", height = " + str(height) + ")")

錯誤:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python33\lib\tkinter\__init__.py", line 1442, in __call__
    return self.func(*args)
  File "E:\Hangman\hangmanTk.py", line 106, in playScreen
    createLetters("playFrame", 175, 250, 50, 50, 0)
  File "E:\Hangman\hangmanTk.py", line 95, in createLetters
    exec(alphabet[i] + " = Button(" + frame + ", text = '" + alphabet[i] + "', command = letterAction(" + alphabet[i] + "))")
  File "<string>", line 1, in <module>
NameError: name 'A' is not defined

我試圖用循環創建多個tkinter按鈕。 我可以很好地創建按鈕,但似乎無法為其創建回調。 每當我嘗試時,它會告訴我未定義用於按鈕的變量。 我嘗試在定義按鈕的上方添加“ exec(“ global” + Alphabet [i])“,但這並沒有改變任何內容。

不管“ it”是什么,使用exec幾乎總是錯誤的方法。

動態創建變量幾乎總是錯誤的做法。

而讓此方法起作用的問題就是為什么的完美例證。


只需創建一個將名稱映射到按鈕的dict即可:

buttons = {}

# ...

letter = alphabet[i]
buttons[letter] = Button(frame, text = letter, command = letterAction(letter))
buttons[letter].place(x = x, y = y, width = width, height = height)

如果您真的想將dict轉儲到locals() (或者類似地,將self.__dict__globals()或…)轉儲到這,那將是微不足道的。 但是你沒有。 您唯一需要使用該變量的位置是在letterAction函數中。 所以:

def createLetters(frame, startX, startY, width, height, spacing):

    alphabet = string.ascii_uppercase
    buttons = {}

    def letterAction(letter):
        buttons[letter].destroy()

    for i, letter in enumerate(alphabet):

        if (i >= 9 and i <= 17):
            y = startY +  height + 2 * spacing
            x = startX + ((width + spacing) * (i - 9))

        elif (i >= 17):
            y = startY + 2 * height + 3 * spacing
            x = (width + spacing) / 2 + startX + ((width + spacing) * (i - 18))

        elif (i <= 8):
            y = startY + spacing
            x = startX + ((width + spacing) * i)

        buttons[letter] = Button(frame, text = letter, command = letterAction(letter))
        buttons[letter].place(x = x, y = y, width = width, height = height)

但是請注意,這做錯了事。 command = letterAction(letter) —是直接運行還是通過exec —現在將調用letterAction(letter) ,銷毀按鈕甚至創建它,然后返回None ,然后將其設置為command

您需要lambda: letterAction(letter)partial(letterAction, letter)來解決此問題。

另外,無論現在還是以后,您都無法編寫將按鈕變量本身傳遞給letter代碼,因為該變量尚不存在。 您必須像上面一樣將字母作為字符串傳遞。


但是,實際上,如果您考慮一下,則根本不需要這些按鈕變量,無論是dict還是其他形式。 您只需要一種將每個按鈕綁定為自己的回調目標的方法,對嗎? 有很多方法可以做到這一點,但是很明顯的一個類是繼承或委托給Button (或者,在這種情況下,兩者都不是,因為您不需要將其用作按鈕,甚至不必記住它) ,創建后)。

在此過程中,讓我們刪除一些無關緊要的內容,以免使情況變得更難以閱讀並解決17似乎屬於兩個不同組的問題……

class SelfDestructiveButton(object):
    def __init__(self, frame, letter, x, y, width, height):
        self.button = Button(frame, text=letter, command=self.command)
        self.button.place(x=x, y=y, width=width, height=height)
    def command(self):
        self.button.destroy()

def createLetters(frame, startX, startY, width, height, spacing):
    for i, letter in enumerate(string.ascii_uppercase):
        if 9 <= i <= 17:
            y = startY +  height + 2 * spacing
            x = startX + ((width + spacing) * (i - 9))
        elif i > 17:
            y = startY + 2 * height + 3 * spacing
            x = (width + spacing) / 2 + startX + ((width + spacing) * (i - 18))
        else:
            y = startY + spacing
            x = startX + ((width + spacing) * i)
        SelfDestructiveButton(frame, letter, x, y, width, height)

if 'J' <= letter <= 'R'甚至可能更清楚,因為它是字母,而不是調試時要看到的數字。

首次調用exec該字符串的計算結果為:

"A = Button(<frame>, text = 'A', command = letterAction(A))"

因此,在定義A (名稱)之前,您要先對其進行引用。 我猜你忘了第二個alphabet[i]的單引號:

exec(alphabet[i] + " = Button(" + frame + ", text = '" + alphabet[i] + "', command = letterAction('" + alphabet[i] + "'))")

注意,這將調用letterAction('A') ,即'A'.destroy() ,由於字符串沒有destroy()方法,該方法將引發AttributeError letterAction應該實現什么?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM