Tkinter中的“ w”和“ s”键绑定工作是否不同?

时间:2019-06-20 19:40:58

标签: python python-2.7 tkinter

我一直在努力将使用CodeSkulptor为在线Python类构建的游戏“ Pong”的版本转换为使用Tkinter的“桌面” Python脚本,以此来教自己如何使用Tkinter 。我已经设法使整个游戏正常运行,除了左(玩家1)球拍。我认为我的按键绑定正确无误,因为正确的(玩家2)拨片可以按预期工作,因为当您按住“向上”或“向下”箭头键时,拨片将移动,直到其达到上下限为止画布,或者在释放任一键时停止。我将按键传递给keydown和keyup处理程序,在这里检查是否按下/释放了哪个键,并采取相应的措施。让我感到困惑的是,如果我将左拨片的移动映射到不同的键(例如,说“ a”或“ d”,或“ Up”或“ Down”箭头),它会按预期工作,但拒绝当我映射了“ w”和“ s”键时可以工作。有谁知道为什么会这样,或者我做错了什么?

我在下面提供的代码是我放在一起的一个基本示例,它演示了此问题以及我试图实现的桨运动(这几乎反映了我的Pong项目)。右侧拨片正确移动,而左侧拨片则不正确。预先感谢您的帮助!

from Tkinter import *
import random


WIDTH = 500
HEIGHT = 500
PAD_WIDTH = 10
PAD_HEIGHT = 80
HALF_PAD_WIDTH = PAD_WIDTH / 2
HALF_PAD_HEIGHT = PAD_HEIGHT / 2


class Example(Frame, object):
    def __init__(self, master):
        super(Example, self).__init__(master)

        self._paddle1_pos = 200
        self._paddle2_pos = 200
        self._paddle1_vel = 0
        self._paddle2_vel = 0

        self.initUI()

    def initUI(self):
        scn_cent_height = self.master.winfo_screenheight() // 2 - HEIGHT // 2
        scn_cent_width = self.master.winfo_screenwidth() // 2 - WIDTH // 2
        self.master.geometry("%sx%s+%s+%s" % (WIDTH, HEIGHT, scn_cent_width, scn_cent_height))
        self.master.minsize(WIDTH, HEIGHT)

        self.master.title("Example Pong Paddles")

        self._canvasFrame = Frame(self.master)
        self._canvasFrame.pack(expand=True, fill=BOTH)

        self._canvas = Canvas(self._canvasFrame, bg="black", highlightthickness=0, bd=0)
        self._canvas.pack(fill=BOTH, expand=True)
        self.update_idletasks()

        # Key handlers
        self.master.bind("<KeyPress>", self.keydown)
        self.master.bind("<KeyRelease>", self.keyup)

        while True:
            self._canvas.after(1)
            self._canvas.delete("all")
            self.draw()
            self._canvas.update()


    def draw(self):
        self._cheight = self._canvasFrame.winfo_height()
        self._cwidth = self._canvasFrame.winfo_width()

        # Draw mid line and gutters
        self._rline = self._canvas.create_line(self._cwidth / 2, 0, self._cwidth / 2, self._cheight, width=1, fill="White")
        self._mline = self._canvas.create_line(PAD_WIDTH, 0, PAD_WIDTH, self._cheight, width=1, fill="White")
        self._lline = self._canvas.create_line(self._cwidth - PAD_WIDTH, 0, self._cwidth - PAD_WIDTH, self._cheight, width=1, fill="White")

        # Update paddle's vertical position, keep paddle on the screen
        # Paddle 1 - Check height and update position
        if self._paddle1_pos + self._paddle1_vel >= HALF_PAD_HEIGHT and self._paddle1_pos + self._paddle1_vel <= HEIGHT - HALF_PAD_HEIGHT:
            self._paddle1_pos += self._paddle1_vel

        # Paddle 2 - Check height and update position
        if self._paddle2_pos + self._paddle2_vel >= HALF_PAD_HEIGHT and self._paddle2_pos + self._paddle2_vel <= HEIGHT - HALF_PAD_HEIGHT:
            self._paddle2_pos += self._paddle2_vel

        # Draw paddles
        self._p1paddle = self._canvas.create_line([HALF_PAD_WIDTH, self._paddle1_pos - HALF_PAD_HEIGHT],
                                                  [HALF_PAD_WIDTH, self._paddle1_pos + HALF_PAD_HEIGHT], width=PAD_WIDTH, fill="White")
        self._p2paddle = self._canvas.create_line([self._cwidth - HALF_PAD_WIDTH, self._paddle2_pos - HALF_PAD_HEIGHT],
                                                  [self._cwidth - HALF_PAD_WIDTH, self._paddle2_pos + HALF_PAD_HEIGHT], width=PAD_WIDTH, fill="White")


        # Draw paddles
        self._p1paddle = self._canvas.create_line([HALF_PAD_WIDTH, self._paddle1_pos - HALF_PAD_HEIGHT],
                                                  [HALF_PAD_WIDTH, self._paddle1_pos + HALF_PAD_HEIGHT], width=PAD_WIDTH, fill="White")
        self._p2paddle = self._canvas.create_line([self._cwidth - HALF_PAD_WIDTH, self._paddle2_pos - HALF_PAD_HEIGHT],
                                                  [self._cwidth - HALF_PAD_WIDTH, self._paddle2_pos + HALF_PAD_HEIGHT], width=PAD_WIDTH, fill="White")


    def keydown(self, key):
        key = key.keysym

        if key == "w":
            self._paddle1_vel = -10
        elif key == "s":
            self._paddle1_vel = 10
        elif key == "Up":
            self._paddle2_vel = -10
        elif key == "Down":
            self._paddle2_vel = 10


    def keyup(self, key):
        key = key.keysym

        if key == "w":
            self._paddle1_vel = 0
        elif key == "s":
            self._paddle1_vel = 0
        elif key == "Up":
            self._paddle2_vel = 0
        elif key == "Down":
            self._paddle2_vel = 0




def main():
    root = Tk()
    example = Example(root)
    root.mainloop()


if __name__ == '__main__':
    main()

2 个答案:

答案 0 :(得分:0)

为了给遇到此问题的任何其他人带来好处,我只是想补充一下,我能够将其源追溯到我的Anaconda虚拟环境(对于Python 2和Python 3,每个人都有一个)。在测试中,我能够在专门使用这些环境时重现此问题,但是在Anaconda之外使用Python 2(mac框架构建)或Python 3(通过Brew安装)时无法重现此问题。我清除了两个Anaconda虚拟环境以防万一,那里的东西弄乱了,然后重新构建了它们(即Python 2和3的全新安装),并且仍然能够重现此问题(无需安装任何其他模块)。我只能推测,Anaconda安装的python与系统框架的一部分或单独安装的python之间存在某些差异。

还要注意,事实证明,当我在@Novel的上述注释中在Python 3上成功测试时,我无意中在系统Python 3上进行了测试,而不是在Anaconda Python 3虚拟环境中进行了测试。

编辑: 事实证明,这个问题实际上是由于我的python安装所使用的Tkinter版本(Tcl / Tk)。我的笔记本电脑上的python框架使用Tk 8.5.9,而Anaconda安装使用的是8.6.8。在测试中,当我在Tk 8.6.8的python 2.7.16和3.7.3中运行Pong脚本时遇到了这个问题,但在与Tk 8.5.9相同的python版本上运行得很好。我不确定这是Tk的问题,还是Tk 8.6.8与MacOS框架之间的某些不兼容(因为该框架本身使用8.5.9)。

答案 1 :(得分:-1)

您的代码非常混乱,需要进行重构,因此我做到了。一些注意事项:

  • 最大的注意是,如果您只绘制一次对象然后简单地移动它们,那么它就更整洁了,并且效果更好,而不是清除屏幕并重新绘制所有内容。
  • 使用tkinter的主循环;不要自己制作并手动更新。 update()update_idletasks()方法是不得已的方法;普通代码没有它们。通过after()使用tkinter的主循环。这将使您的窗口更具反应性。
  • Python2 Tkinter类是旧样式的,请不要通过添加对象继承来强制它们为新样式。
  • 画布框架没用,所以我将其删除。
  • 将关键字保留在词典中可以释放大量重复代码。
  • 在所有变量名前面加上_无济于事,并且使其难以阅读和输入;别说了。

-

try:
    import tkinter as tk # python3 detected
except ImportError:
    import Tkinter as tk # python2 detected

WIDTH = 500
HEIGHT = 500
PAD_WIDTH = 10
PAD_HEIGHT = 80
VELOCITY = 10
HALF_PAD_WIDTH = PAD_WIDTH // 2
HALF_PAD_HEIGHT = PAD_HEIGHT // 2

P1_UP = 111 # Up arrow key
P1_DOWN = 116 # Down arrrow key
P2_UP = 25 # 'w' key
P2_DOWN = 39 # 's' key

class Example(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)

        self.keys = {}
        self.initUI()

        # Key handlers
        self.master.bind("<KeyPress>", self.keydown)
        self.master.bind("<KeyRelease>", self.keyup)

        self.draw() # add the game loop to the mainloop

    def initUI(self):
        scn_cent_height = self.master.winfo_screenheight() // 2 - HEIGHT // 2
        scn_cent_width = self.master.winfo_screenwidth() // 2 - WIDTH // 2
        self.master.geometry("%sx%s+%s+%s" % (WIDTH, HEIGHT, scn_cent_width, scn_cent_height))
        self.master.minsize(WIDTH, HEIGHT)

        self.master.title("Example Pong Paddles")

        self.canvas = tk.Canvas(self, bg="black", highlightthickness=0, bd=0, width=WIDTH, height=HEIGHT)
        self.canvas.pack(fill=tk.BOTH, expand=True)

        # Draw mid line and gutters
        self.rline = self.canvas.create_line(WIDTH//2, 0, WIDTH//2, HEIGHT, width=1, fill="White")
        self.mline = self.canvas.create_line(PAD_WIDTH, 0, PAD_WIDTH, HEIGHT, width=1, fill="White")
        self.lline = self.canvas.create_line(WIDTH - PAD_WIDTH, 0, WIDTH - PAD_WIDTH, HEIGHT, width=1, fill="White")

        # Draw paddles
        self.p1paddle = self.canvas.create_line([HALF_PAD_WIDTH, HEIGHT//2 - HALF_PAD_HEIGHT],
                                                  [HALF_PAD_WIDTH, HEIGHT//2 + HALF_PAD_HEIGHT], width=PAD_WIDTH, fill="White")
        self.p2paddle = self.canvas.create_line([WIDTH - HALF_PAD_WIDTH, HEIGHT//2 - HALF_PAD_HEIGHT],
                                                    [WIDTH - HALF_PAD_WIDTH, HEIGHT//2 + HALF_PAD_HEIGHT], width=PAD_WIDTH, fill="White")

    def draw(self):
        if self.keys.get(P2_UP) and self.canvas.coords(self.p1paddle)[1] > 0:
            self.canvas.move(self.p1paddle, 0, -VELOCITY)
        if self.keys.get(P2_DOWN) and self.canvas.coords(self.p1paddle)[3] < HEIGHT:
            self.canvas.move(self.p1paddle, 0, VELOCITY)
        if self.keys.get(P1_UP) and self.canvas.coords(self.p2paddle)[1] > 0:
            self.canvas.move(self.p2paddle, 0, -VELOCITY)
        if self.keys.get(P1_DOWN) and self.canvas.coords(self.p2paddle)[3] < HEIGHT:
            self.canvas.move(self.p2paddle, 0, VELOCITY)

        self.after(10, self.draw)

    def keydown(self, key):
        self.keys[key.keycode] = True

    def keyup(self, key):
        self.keys[key.keycode] = False

def main():
    root = tk.Tk()
    example = Example(root)
    example.pack()
    root.mainloop()

if __name__ == '__main__':
    main()

也许,偶然地,那里的一些改进也将解决您原来的问题。