NameError:从类中调用方法时,Python未定义名称“self”

2024-09-23 22:27:42 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试使用Tkinter库在python中制作一个类似砖块破碎机的游戏。我有一个运行良好的早期版本的代码,但是由于缩进错误,所有函数都在__init__中。当我纠正了这个错误,然后添加了一些功能使它成为一个可玩的游戏时,我的主动画循环停止工作。我读了其他文章,证明这是一个间距错误,并验证了这不是使用python -tt。更新:self.moveBall()被移到__init__中,但是moveBall()仍然没有运行。

from tkinter import *


class Application(Frame):

    def __init__(self):

# Constructing the Screen

    root = Tk()
    Frame.__init__(self)
    self.canvas = Canvas(root, width=800, height=400)

# Label

    self.v = StringVar()
    self.l = 5
    self.label = Label(root, textvariable=self.v, font=('Courier',
                       20), bg='white', width=50)
    self.v.set('Lives: ' + str(self.l))
    self.label.grid()
    self.canvas.grid()

# Ball

    self.canvas.create_oval(
        2,
        2,
        22,
        22,
        fill='red',
        tags='ball',
        )

# Paddle

    self.canvas.create_rectangle(
        360,
        380,
        440,
        400,
        fill='black',
        tag='paddle',
        )

# Keybindings

    self.canvas.focus_set()
    self.canvas.bind('<Left>', self.paddleLeft)
    self.canvas.bind('a', self.paddleLeft)
    self.canvas.bind('<Button-1>', self.paddleLeft)
    self.canvas.bind('<Right>', self.paddleRight)
    self.canvas.bind('d', self.paddleRight)
    self.canvas.bind('<Button-3>', self.paddleRight)

# Logic

    self.horizontal_direction = 'east'
    self.vertical_direcction = 'south'
    self.moveBall()

    def collide(self):
        (x1, y1, x2, y2) = self.canvas.coords('ball')
        (px1, py1, px2, py2) = self.canvas.coords('paddle')
        if x2 >= 800:
            self.horizontal_direction = 'west'
        if x1 <= 0:
            self.horizontal_direction = 'east'
        if y1 <= 0:
            self.vertical_direcction = 'south'
        if y2 >= 400:
            self.l -= 1
            self.v.set('Lives: ' + str(self.l))
            self.vertical_direcction = 'north'
        if y2 >= py1:
            if x1 in range(int(px1), int(px2)) or x2 in range(int(px1),
                    int(px2)):
                self.vertical_direcction = 'north'

    def moveBall(self):
        while True:
            if self.horizontal_direction == 'east':
                self.canvas.move('ball', 2, 0)
            else:
                self.canvas.move('ball', -2, 0)
            if self.vertical_direcction == 'south':
                self.canvas.move('ball', 0, 2)
            else:
                self.canvas.move('ball', 0, -2)
                self.canvas.after(15)
                self.collide()
                self.canvas.update()

    def paddleLeft(self, event):
        (px1, py1, px2, py2) = self.canvas.coords('paddle')
        if px1 >= 0:
            self.canvas.move('paddle', -5, 0)
            self.canvas.after(15)
            self.canvas.update()

    def paddleRight(self, event):
        (px1, py1, px2, py2) = self.canvas.coords('paddle')
        if px2 <= 800:
            self.canvas.move('paddle', 5, 0)
            self.canvas.after(15)
            self.canvas.update()




def main():
   app = Application()
   app.mainloop()


main()

下面是控制台输出:

^{pr2}$

Tags: selfmoveifinitbinddefcanvasvertical
2条回答

据我所知,这种类型的错误通常发生在您试图用self从类外部调用方法时。在

我相信你的错误在于

self.moveball()

在这里,您尝试从类范围之外使用self调用moveball()。在

我希望它能帮助你克服这个问题。在

我做了这样的东西:

它使用self.root,所以我可以在moveBall中使用它,它与self.root.after(15, moveBall)一起使用,15毫秒后再次运行{},我不需要while True。我不需要canvas.after(15)和{}。在

我从class Application(Frame):中删除了Frame,因为您将所有小部件直接添加到root中,而这个{}从未使用过。在小部件中,您必须使用self而不是root来将小部件添加到此Frame,而{}则必须使用master=root将它们添加到主窗口。在

from tkinter import *


class Application():

    def __init__(self):

        # Constructing the Screen

        self.root = Tk()
        self.canvas = Canvas(self.root, width=800, height=400)

        # Label

        self.v = StringVar()
        self.l = 5
        self.label = Label(self.root, textvariable=self.v, font=('Courier',
                           20), bg='white', width=50)
        self.v.set('Lives: ' + str(self.l))
        self.label.grid()
        self.canvas.grid()

        # Ball

        self.canvas.create_oval(
            2,
            2,
            22,
            22,
            fill='red',
            tags='ball',
            )

        # Paddle

        self.canvas.create_rectangle(
            360,
            380,
            440,
            400,
            fill='black',
            tag='paddle',
            )

        # Keybindings

        self.canvas.focus_set()
        self.canvas.bind('<Left>', self.paddleLeft)
        self.canvas.bind('a', self.paddleLeft)
        self.canvas.bind('<Button-1>', self.paddleLeft)
        self.canvas.bind('<Right>', self.paddleRight)
        self.canvas.bind('d', self.paddleRight)
        self.canvas.bind('<Button-3>', self.paddleRight)

        # Logic

        self.horizontal_direction = 'east'
        self.vertical_direcction = 'south'

        # run after 250ms so mainloop has time to start
        self.root.after(250, self.moveBall)

        self.root.mainloop()

    def collide(self):
        (x1, y1, x2, y2) = self.canvas.coords('ball')
        (px1, py1, px2, py2) = self.canvas.coords('paddle')
        if x2 >= 800:
            self.horizontal_direction = 'west'
        if x1 <= 0:
            self.horizontal_direction = 'east'
        if y1 <= 0:
            self.vertical_direcction = 'south'
        if y2 >= 400:
            self.l -= 1
            self.v.set('Lives: ' + str(self.l))
            self.vertical_direcction = 'north'
        if y2 >= py1:
            if x1 in range(int(px1), int(px2)) or x2 in range(int(px1),
                    int(px2)):
                self.vertical_direcction = 'north'

    def moveBall(self):

        if self.horizontal_direction == 'east':
            self.canvas.move('ball', 2, 0)
        else:
            self.canvas.move('ball', -2, 0)
        if self.vertical_direcction == 'south':
            self.canvas.move('ball', 0, 2)
        else:
            self.canvas.move('ball', 0, -2)
            self.collide()

        # run again after 15ms - so I don't need `while True`
        self.root.after(15, self.moveBall)

    def paddleLeft(self, event):
        (px1, py1, px2, py2) = self.canvas.coords('paddle')
        if px1 >= 0:
            self.canvas.move('paddle', -5, 0)

    def paddleRight(self, event):
        (px1, py1, px2, py2) = self.canvas.coords('paddle')
        if px2 <= 800:
            self.canvas.move('paddle', 5, 0)

#  - start  -

Application()

相关问题 更多 >