【问题标题】:Text not displaying in Tkinter文本未在 Tkinter 中显示
【发布时间】:2018-03-05 03:38:55
【问题描述】:

我有以下代码,错误是缺少 1 个位置参数(文本)。据我所知,我已经包含了所有论点。任何人都可以对此有所了解吗?

错误

TypeError: draw_text() missing 1 required positional argument: 'text'

有问题的代码

while 1:
        if ball1.hit_bottom ==False: #this creates a condition - inside the loop it continues to check to see if the ball has hit (or not) the bottom of the screen
            tk.update()
            ball1.draw()
            bat1.draw()
        else:
            draw1=Game()
            draw1.draw_text(300,200,'Goodbye')

        time.sleep(0.02) 
main()

在其中定义 draw_text 的类。

class Game:
    def game_loop(self,canvas):
        if hit_bottom==True:
            self.draw_text(300,200,'You Lose')
    def draw_text(self,canvas,x,y,text,size='40'):
        font=('Helvetica',size)
        return self.canvas.create_text(x,y,text=text,font=font)

Tkinter 新手,经过大量研究后,我仍然无法找到有关使其正常工作的细节。

我也试过这个:

  while 1:
        if ball1.hit_bottom ==False: #this creates a condition - inside the loop it continues to check to see if the ball has hit (or not) the bottom of the screen
            tk.update()
            ball1.draw()
            bat1.draw()
        else:
            game_over()

        time.sleep(0.02) 
main()

...在 Ball 类中包含以下内容

  def draw(self): 
        self.canvas.move(self.id,self.x,self.y) 
        pos=self.canvas.coords(self.id) 
        if pos[1] <=0: 
            self.y=6
            #we make a change here as well -alter the if statement to see if the ball has hit the bottom (equal or greater than canvas height), if so hit_bottom =True (as there is no more need to bounce the ball if the game is over!)
        if pos[3] >=self.canvas_height: 
            self.hit_bottom = True
            game_over()

这也不起作用:

错误: 画布未定义

可运行示例(完整代码)

from tkinter import *

import random
import time

class Game:
    def game_loop(self,canvas):
        if hit_bottom==True:
            self.draw_text(300,200,'You Lose')
    def draw_text(self,canvas,x,y,text,size='40'):
        font=('Helvetica',size)
        return self.canvas.create_text(x,y,text=text,font=font)

class Ball: 
    def __init__(self,canvas,bat,color):  
        self.canvas=canvas
        self.bat=bat 
        self.id=canvas.create_oval(30,30,50,50,fill=color) 
        self.canvas.move(self.id,100,200)
        starting_position=[-3,-2,-1,1,2,3] 
        random.shuffle(starting_position) 
        self.x = starting_position[0] 
        self.y = -3 
        self.canvas_height=self.canvas.winfo_height()
        self.canvas_width=self.canvas.winfo_width()
        #Add a hit_bottom object variable here..
        self.hit_bottom=False #...note we change the main loop at the bottom to include an if function that utilises this hit_bottom object variable


    def hit_bat(self,pos):
        bat_pos=self.canvas.coords(self.bat.id) 
        if pos[2] >=bat_pos[0] and pos[0] <=bat_pos[2]: 
            if pos[3]>=bat_pos[1] and pos[3] <= bat_pos[3]: 
                return True
        return False

    def draw(self): 
        self.canvas.move(self.id,self.x,self.y) 
        pos=self.canvas.coords(self.id) 
        if pos[1] <=0: 
            self.y=6
            #we make a change here as well -alter the if statement to see if the ball has hit the bottom (equal or greater than canvas height), if so hit_bottom =True (as there is no more need to bounce the ball if the game is over!)
        if pos[3] >=self.canvas_height: 
            self.hit_bottom = True


        if self.hit_bat(pos) ==True: 
            self.y=-6 
        if pos[0] <=0:
            self.x=6
        if pos[2]>=self.canvas_width:
            self.x=-6



class Pongbat():
    def __init__(self,canvas,color): 
        self.canvas=canvas
        self.id=canvas.create_rectangle(0,0,100,10,fill=color) 
        self.canvas.move(self.id,200,300)
        self.x=0
        self.canvas_width=self.canvas.winfo_width() 
        self.canvas.bind_all('<KeyPress-Left>',self.left_turn)
        self.canvas.bind_all('<KeyPress-Right>',self.right_turn)


    def draw(self): 
        self.canvas.move(self.id,self.x,0)
        pos=self.canvas.coords(self.id)
        if pos[0]<=0: 
            self.x=0
        if pos[2]>=self.canvas_width:
            self.x=0

    def left_turn(self,evt):
        self.x=-10 

    def right_turn(self,evt):
        self.x=10

def main():
    tk=Tk()
    tk.title("My 21st Century Pong Game")
    tk.resizable(0,0)
    tk.wm_attributes("-topmost",1)
    canvas=Canvas(tk,bg="white",width=500,height=400,bd=0,highlightthickness=0)
    canvas.pack()
    tk.update()

    bat1=Pongbat(canvas,'red') 
    ball1=Ball(canvas,bat1, 'green') 

    while 1:
        if ball1.hit_bottom ==False: #this creates a condition - inside the loop it continues to check to see if the ball has hit (or not) the bottom of the screen
            tk.update()
            ball1.draw()
            bat1.draw()
        else:
            draw1=Game()
            draw1.draw_text(300,200,'Goodbye')

        time.sleep(0.02) 
main()

最终更新:

我尝试的最新方法是添加一个 init 方法,如下所示:

class Game:
    def __init__(self,canvas):
     self.canvas=canvas

    def game_loop(self,canvas):
        if hit_bottom==True:
            self.draw_text(300,200,'You Lose')
    def draw_text(self,canvas,x,y,text,size='40'):
        font=('Helvetica',size)
        return self.canvas.create_text(x,y,text=text,font=font)

 while 1:
        if ball1.hit_bottom ==False: #this creates a condition - inside the loop it continues to check to see if the ball has hit (or not) the bottom of the screen
            tk.update()
            ball1.draw()
            bat1.draw()
        else:
            draw1=Game(canvas)
            #def draw_text(self,canvas,x,y,text,size='40'):
            draw1.draw_text(canvas,300,200,'Goodbye')

        time.sleep(0.02) 
main()

现在,第一个错误(关于没有画布或没有位置参数)消失了,但屏幕只是挂起。

【问题讨论】:

  • 我试过了:game_over(canvas) ..and def game_over(canvas): ..但还是不行。您可以发布作为答案吗
  • 你有canvas 作为draw_text 中的参数,然后永远不要传递它。这意味着 300 -> canvas, 200 -> x, 'Goodbye' -> y,因此您没有向text 传递任何内容,并收到此错误。
  • 感谢 SneakyTurtle 和 abccd - 只是发布整个代码
  • SneakyTurtle - 你能发布答案吗,我看不出你的意思,我看不出如何解决这个问题。 :=(
  • 当我通过画布时,像这样:draw1.draw_text(canvas,300,200,'Goodbye') 我得到错误:AttributeError: 'Game' object has no attribute 'canvas' 如果可以发布一个解决问题并显示文本的答案,我会很高兴地投票并接受答案!如您所见,我已经尝试了各种方法,并希望 SO 上的某个人能阻止我为此发疯……!

标签: python text tkinter display


【解决方案1】:

屏幕在您上次更新时挂起,因为while 循环仍在运行,您没有得到/打破它。一旦满足您的条件,您应该 break 退出 while 循环。

这是您的代码,还有一些其他修复:

您的 right_turnleft_turn 方法似乎无法正常工作,但我会留给您解决。

from tkinter import *

import random
import time

class Game:
    def __init__(self, canvas):
        self.canvas=canvas

    def game_loop(self): ##No need to pass canvas since you are using the same canvas in __init__
        if hit_bottom==True:
            self.draw_text(300,200,'You Lose')
    def draw_text(self, x, y, text, size='40'): ##No need to pass canvas
        font=('Helvetica',size)
        print "Ok"
        return self.canvas.create_text(x,y,text=text,font=font)

class Ball: 
    def __init__(self,canvas,bat,color):  
        self.canvas=canvas
        self.bat=bat 
        self.id=self.canvas.create_oval(30,30,50,50,fill=color) ## self.canvas
        self.canvas.move(self.id,100,200)
        starting_position=[-3,-2,-1,1,2,3] 
        random.shuffle(starting_position) 
        self.x = starting_position[0] 
        self.y = -3 
        self.canvas_height=self.canvas.winfo_height()
        self.canvas_width=self.canvas.winfo_width()
        #Add a hit_bottom object variable here..
        self.hit_bottom=False #...note we change the main loop at the bottom to include an if function that utilises this hit_bottom object variable


    def hit_bat(self,pos):
        bat_pos=self.canvas.coords(self.bat.id) 
        if pos[2] >=bat_pos[0] and pos[0] <=bat_pos[2]: 
            if pos[3]>=bat_pos[1] and pos[3] <= bat_pos[3]: 
                return True
        return False

    def draw(self): 
        self.canvas.move(self.id,self.x,self.y) 
        pos=self.canvas.coords(self.id) 
        if pos[1] <=0: 
            self.y=6
            #we make a change here as well -alter the if statement to see if the ball has hit the bottom (equal or greater than canvas height), if so hit_bottom =True (as there is no more need to bounce the ball if the game is over!)
        if pos[3] >=self.canvas_height: 
            self.hit_bottom = True


        if self.hit_bat(pos) ==True: 
            self.y=-6 
        if pos[0] <=0:
            self.x=6
        if pos[2]>=self.canvas_width:
            self.x=-6



class Pongbat():
    def __init__(self,canvas,color): 
        self.canvas=canvas
        self.id=self.canvas.create_rectangle(0,0,100,10,fill=color) ## self.canvas
        self.canvas.move(self.id,200,300)
        self.x=0
        self.canvas_width=self.canvas.winfo_width() 
        self.canvas.bind_all('<KeyPress-Left>',self.left_turn)
        self.canvas.bind_all('<KeyPress-Right>',self.right_turn)


    def draw(self): 
        self.canvas.move(self.id,self.x,0)
        pos=self.canvas.coords(self.id)
        if pos[0]<=0: 
            self.x=0
        if pos[2]>=self.canvas_width:
            self.x=0

    def left_turn(self,evt):
        self.x =-10 

    def right_turn(self,evt):
        self.x =+10

def main():
    tk=Tk()
    tk.title("My 21st Century Pong Game")
    tk.resizable(0,0)
    tk.wm_attributes("-topmost",1)
    canvas=Canvas(tk,bg="white",width=500,height=400,bd=0,highlightthickness=0)
    canvas.pack()
    tk.update()

    bat1=Pongbat(canvas,'red') 
    ball1=Ball(canvas,bat1, 'green') 

    while 1:
        if ball1.hit_bottom ==False: #this creates a condition - inside the loop it continues to check to see if the ball has hit (or not) the bottom of the screen
            tk.update()
            ball1.draw()
            bat1.draw()
        else:
            draw1=Game(canvas)
            #def draw_text(self,canvas,x,y,text,size='40'):
            draw1.draw_text(300,200,'Goodbye')
            break ## This stops the while loop

        time.sleep(0.02)
    tk.mainloop() # Keep the main window open
main()

【讨论】:

    【解决方案2】:

    在进行了一些更改后,其中大部分(如果不是全部)都用 cmets 表示,这里有一个脚本的可运行版本,它将在游戏结束时显示文本。

    from tkinter import *
    
    import random
    import time
    
    class Game:
        def __init__(self, canvas): # Added method.
            self.canvas=canvas
        def game_loop(self):  # Removed canvas parameter.
            if hit_bottom==True:
                self.draw_text(self.canvas,300,200,'You Lose')  # Added self.canvas arg
        def draw_text(self,canvas,x,y,text,size='40'):
            font=('Helvetica',size)
            return self.canvas.create_text(x,y,text=text,font=font)
    
    class Ball:
        def __init__(self,canvas,bat,color):
            self.canvas=canvas
            self.bat=bat
            self.id=canvas.create_oval(30,30,50,50,fill=color)
            self.canvas.move(self.id,100,200)
            starting_position=[-3,-2,-1,1,2,3]
            random.shuffle(starting_position)
            self.x = starting_position[0]
            self.y = -3
            self.canvas_height=self.canvas.winfo_height()
            self.canvas_width=self.canvas.winfo_width()
            #Add a hit_bottom object variable here..
            self.hit_bottom=False #...note we change the main loop at the bottom to include an if function that utilises this hit_bottom object variable
    
    
        def hit_bat(self,pos):
            bat_pos=self.canvas.coords(self.bat.id)
            if pos[2] >=bat_pos[0] and pos[0] <=bat_pos[2]:
                if pos[3]>=bat_pos[1] and pos[3] <= bat_pos[3]:
                    return True
            return False
    
        def draw(self):
            self.canvas.move(self.id,self.x,self.y)
            pos=self.canvas.coords(self.id)
            if pos[1] <=0:
                self.y=6
                #we make a change here as well -alter the if statement to see if the ball has hit the bottom (equal or greater than canvas height), if so hit_bottom =True (as there is no more need to bounce the ball if the game is over!)
            if pos[3] >=self.canvas_height:
                self.hit_bottom = True
    
    
            if self.hit_bat(pos) ==True:
                self.y=-6
            if pos[0] <=0:
                self.x=6
            if pos[2]>=self.canvas_width:
                self.x=-6
    
    
    
    class Pongbat():
        def __init__(self,canvas,color):
            self.canvas=canvas
            self.id=canvas.create_rectangle(0,0,100,10,fill=color)
            self.canvas.move(self.id,200,300)
            self.x=0
            self.canvas_width=self.canvas.winfo_width()
            self.canvas.bind_all('<KeyPress-Left>',self.left_turn)
            self.canvas.bind_all('<KeyPress-Right>',self.right_turn)
    
    
        def draw(self):
            self.canvas.move(self.id,self.x,0)
            pos=self.canvas.coords(self.id)
            if pos[0]<=0:
                self.x=0
            if pos[2]>=self.canvas_width:
                self.x=0
    
        def left_turn(self,evt):
            self.x=-10
    
        def right_turn(self,evt):
            self.x=10
    
    def main():
        tk=Tk()
        tk.title("My 21st Century Pong Game")
        tk.resizable(0,0)
        tk.wm_attributes("-topmost",1)
        canvas=Canvas(tk,bg="white",width=500,height=400,bd=0,highlightthickness=0)
        canvas.pack()
        tk.update()
    
        bat1=Pongbat(canvas,'red')
        ball1=Ball(canvas,bat1, 'green')
    
        while 1:
            if ball1.hit_bottom ==False: #this creates a condition - inside the loop it continues to check to see if the ball has hit (or not) the bottom of the screen
                ball1.draw()
                bat1.draw()
                tk.update()  # Allow screen to be updated (moved here after draw calls).
            else:
                draw1=Game(canvas)  # Added argument for new __init__() method.
                draw1.draw_text(canvas,300,200,'Goodbye')  # Added canvas arg.
                tk.update()  # Allow screen to be updated.
                canvas.after(3000)  # Added. Pause for a few seconds.
                return  # Terminate.
    
    #        time.sleep(0.02)  # Shouldn't call sleep() in tkinter app.
            canvas.after(2)  # Use universal 'after()` method instead. Time in millisecs.
    main()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-15
      • 1970-01-01
      • 2020-11-03
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      • 1970-01-01
      相关资源
      最近更新 更多