【问题标题】:Python Using tkinterPython 使用 tkinter
【发布时间】:2015-05-04 04:29:39
【问题描述】:

我正在使用 Python 开发基于 GUI 的刽子手游戏。 Tkinter main_window 代码来自教科书,但“.Tk()”引起了问题。运行我的代码时,我收到错误:

Traceback (most recent call last):
  File "E:\final.py", line 62, in <module>
    class MyGUI():
  File "E:\final.py", line 93, in MyGUI
    tkinter.mainloop()
  File "C:\Python34\lib\tkinter\__init__.py", line 403, in mainloop
    _default_root.tk.mainloop(n)
AttributeError: 'NoneType' object has no attribute 'tk'

我知道我对 GUI 的编码不正确,但我不确定如何修复。这是因为我在运行 GUI 窗口之前正在运行“设置”方法吗?我的代码如下:

import tkinter
import tkinter.messagebox
import random

#fruit category
easyWords = ['apple', 'orange', 'mango', 'peach', 'guava']
#space category
mediumWords = ['atmosphere', 'jupiter', 'quasar', 'satellite', 'asteroid']
#science category
hardWords = ['biochemical', 'hemoglobin', 'emulsify', 'reactant', 'dynamo']

def setting():

    wordChoice = ''

    difficulty = input('''Welcome to hangman, select your difficulty.
Type, easy, medium, or hard to begin:''')

    if difficulty == 'easy':

        wordChoice = easyWords.random
        print('You have selected easy mode, start guessing your letters now in the game window. The category is: fruit')

    if difficulty == 'medium':

        wordChoice = mediumWords.random
        print('You have selected medium mode, start guessing your letters now in the game window. The category is: space')

    if difficulty == 'hard':

        wordChoice = hardWords.random
        print('You have selected hard mode, start guessing your letters now in the game window. The category is: science')

def game():

    missGuess = 0
    guesses = ''

    for char in wordChoice:
        label3.print(char),

        if char in guesses:
            print(char),

        else:
            label3.print("_"),
            missGuess += 1

        if missGuess == 1:
            label1.print('head')
        if missGuess == 2:
            label1.print('torso')
        if missGuess == 3:
            label1.print('left arm')
        if missGuess == 4:
            label1.print('right arm')
        if missGuess == 5:
            label1.print('left leg')
        if missGuess == 6:
            label1.print('right leg'),

class MyGUI():
    def __init__(self):
        self.main_window = tkinter.Tk()

        #create needed frames
        self.top_frame = tkinter.Frame(self.main_window)
        self.center_frame = tkinter.Frame(self.main_window)
        self.bottom_frame = tkinter.Frame(self.main_window)

        #create top frame labels
        self.label1 = tkinter.Label(self.top_frame, text='Hangman parts:')
        self.label2 = tkinter.Label(self.top_frame, text=' ')
        #center frame labels
        self.label3 = tkinter.Label(self.center_frame, text=' ')
        #bottom frame labels
        self.label4 = tkinter.Label(self.bottom_frame, text='Guess a letter:')
        self.entry1 = tkinter.Entry(self.bottom_frame, width=5)
        self.button1 = tkinter.Button(self.bottom_frame, text='Guess', command=self.game) #calls the game method
        self.button2 = tkinter.Button(self.bottom_frame, text='Exit', command=self.main_window.destroy)

        #pack top frame labels
        self.label1.pack(side='left')
        self.label2.pack(side='right')
        #pack center frame
        self.label3.pack(side='top')
        #bottom frame
        self.label4.pack(side='left')
        self.entry1.pack(side='left')
        self.button1.pack(side='left')
        self.button2.pack(side='left')

    tkinter.mainloop()



setting()
main()

【问题讨论】:

  • 不要编码太多,然后测试它。始终有一个工作代码和增量程序。首先,您可以只显示一个空窗口。
  • “apple”和“guava”实际上是比“asteroid”更难的刽子手词。

标签: python tkinter


【解决方案1】:

您已将tkinter.mainloop() 放入类体内。

这意味着它在定义类本身时被执行。这是在定义它的任何实例之前。这意味着它在您的 Tk() 被创建之前。所以,默认的Tk 实例还不存在,所以它是None

如果你只是进一步缩进一个档次,在 __init__ 调用的末尾,而不是在类级别,那么它会起作用。

但是,通常最好在您自己的Tk 实例上显式调用mainloop(意味着self.main_window.mainloop()MyGUI 的方法内部,或从外部some_instance.main_window.mainloop())。

使用self.main_window.mainloop() 的原因是它更清晰,更易于调试。特别是,如果你搞砸了并将它放在一个方法之外,你会得到一个异常,告诉你没有 self 这样的东西,这很明显你打算把代码放在一个方法中(就像一个类似的Java 中 this 的错误),而不是来自 Tkinter 内部的神秘错误,只有知道它的内部运作才能理解。

但是,如果您想了解内部工作原理:Tk 是“几乎单例”;虽然创建多个实例是合法的,但您很少这样做。在 Java 中,您可能有一个静态类成员将第一个创建的实例存储为“默认”实例,并有一个静态类方法来访问它,例如 Tk.get_default_root()。然后,您将拥有另一个静态类方法Tk.default_mainloop(),它只执行Tk.get_default_root().mainloop()。在 Python 中,您并不经常需要静态属性和方法,因为您可以将它们设为全局模块,因此默认实例存储在 _default_root 中,mainloop() 调用 _default_root.mainloop()


与此同时,您还有其他问题需要解决。例如,您有多个行在执行easyWords.random 之类的操作。首先,如果要在 Python 中调用函数或方法,则需要括号。其次,列表没有名为random 的方法。如果您想从列表中选择一个随机值,请执行random.choice(easyWords)。您还调用了一个名为main 的函数,该函数尚未在任何地方定义。而且我敢肯定还有其他问题。显然,您必须修复所有这些问题,而不仅仅是 mainloop 一个,然后它才会起作用。

【讨论】:

  • main 方法是在编码过程中创建的,但我忘了删除它。我已经用班级电话代替了它。 “在您自己的 Tk 实例上显式调用 mainloop”到底是什么意思?你有一个简单的例子吗?我对 Python 很陌生,我唯一的其他经验就是一点 Java。
  • @DustinWondrasek:示例就在答案中:self.main_window.mainloop()。我将尝试通过编辑答案来进一步解释。
【解决方案2】:

与您的问题无关的旁注。您对 random 的使用可能不起作用,例如如行中所示:

wordChoice = easyWords.random.

列表对象没有随机属性。我认为您打算做的是从 easyWords 列表中随机选择一个单词。为此,您可以使用:

wordChoice = random.choice(easyWords)

看看这是否有效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-24
    • 2015-11-27
    • 2017-12-08
    • 2016-09-02
    • 1970-01-01
    相关资源
    最近更新 更多