如何检测Tkinter中是否按下某个键?

时间:2018-01-07 22:09:03

标签: python python-3.x tkinter keypress

作为Python的新手,我已经尝试使用指南的建议编写自己的游戏。然而,对于这个游戏,我试图检测何时一直按下按键而不是按下按键。我使用的当前代码并没有使角色移动,并且没有实施halt(self, evt)代码,导致按钮被按下足够长时间后,船只会无法控制地加速。

from tkinter import *
import random
import time

class Game:
    def __init__(self):
        self.tk = Tk()
        self.tk.title("Shooter")
        self.tk.resizable(0, 0)
        self.tk.wm_attributes("-topmost", 1)
        self.canvas = Canvas(self.tk, width=500, height=1000, highlightthickness=0)
        self.canvas.pack()
        self.tk.update()
        self.canvas_height = 1000
        self.canvas_width = 500
        self.bg = PhotoImage(file="background.gif")
        w = self.bg.width()
        h = self.bg.height()
        for x in range(0, 5):
            for y in range(0, 10):
                self.canvas.create_image(x * w, y * h, \
                        image=self.bg, anchor='nw')
        self.sprites = []
        self.running = True

    def mainloop(self):
        while 1:
            if self.running == True:
                for sprite in self.sprites:
                    sprite.move()
            self.tk.update_idletasks()
            self.tk.update()
            time.sleep(0.01)

class Coords:
    def __init__(self, x1=0, y1=0, x2=0, y2=0):
        self.x1 = x1
        self.y1 = y1
        self.x2 = x2
        self.y2 = y2

class Sprite:
    def __init__(self, game):
        self.game = game
        self.endgame = False
        self.coordinates = None
    def move(self):
        pass
    def coords(self):
        return self.coordinates

class PlayerSprite(Sprite):
    def __init__(self, game):
        Sprite.__init__(self, game)
        self.renderimage = [
            PhotoImage(file="player_1.gif"),
            PhotoImage(file="player_2.gif"),
            PhotoImage(file="player_3.gif"),
            PhotoImage(file="player_4.gif"),
        ]
        self.image = game.canvas.create_image(225, 900, \
                image=self.renderimage[0], anchor='nw')
        self.x = 0
        self.y = 0
        self.velx = 0
        self.current_image = 0
        self.current_image_add = 1
        self.shoot_timer = 0
        self.last_time = time.time()
        self.coordinates = Coords()
        x_move = None
        y_move = None
        game.canvas.bind_all('<KeyPress-Left>', self.move_left)
        game.canvas.bind_all('<KeyPress-Right>', self.move_right)
        game.canvas.bind_all('<KeyPress-Up>', self.move_up)
        game.canvas.bind_all('<KeyPress-Down>', self.move_down)
        game.canvas.bind_all('<KeyPress-Left>', self.halt)
        game.canvas.bind_all('<KeyPress-Right>', self.halt)
        game.canvas.bind_all('<KeyPress-Up>', self.halt)
        game.canvas.bind_all('<KeyPress-Down>', self.halt)
        game.canvas.bind_all('<space>', self.shoot)

    def move_left(self, evt):
        x_move = self.x - 1.5
        self.x = x_move

    def move_right(self, evt):
        x_move = self.x + 1.5
        self.x = x_move

    def move_up(self, evt):
        y_move = self.y - 1.5
        self.y = y_move

    def move_down(self, evt):
        y_move = self.y + 1.5
        self.y = y_move

    def halt(self, evt):
        time.sleep(0.01)
        if x_move < 0:
            x_move = -1.5
        elif x_move > 0:
            x_move = 1.5
        elif y_move < 0:
            y_move = -1.5
        elif y_move > 0:
            y_move = 1.5

    def shoot(self, evt):
        print("Placeholder")

    def move(self):
        self.game.canvas.move(self.image, self.x, self.y)

    def coords(self):
        xy = self.game.canvas.coords(self.image)
        self.coordinates.x1 = xy[0]
        self.coordinates.y1 = xy[1]
        self.coordinates.x2 = xy[0] + 24
        self.coordinates.y2 = xy[1] + 32
        return self.coordinates

g = Game()
sp = PlayerSprite(g)
g.sprites.append(sp)
g.mainloop()

我的目标是在按下相应的按键时让我的角色以恒定的速度移动(而不是在一段时间后不受控制地快速移动)。

2 个答案:

答案 0 :(得分:0)

对您的问题最直接的解决方案是避免在每个按键时添加值,而是设置一个常量值。

def move_left(self, evt):
    x_move = -5
    self.x = x_move

然而,运动会失去动力,但它会不变。否则,您可以创建最大值。像这样:

def move_left(self, evt):
    int max_val_left = -10
    if( self.x < max_val_left):
        x_move = self.x - 1.5
        self.x = x_move

从而迫使self.x保持上限并且如果已达到max_val则保持不变。

答案 1 :(得分:0)

按住一个键与重复按下该键基本相同。你通过在move_ *函数中添加/减去self.x / self.y属性来做的是你增加画布在每个函数调用中移动玩家精灵的数量(例如从1.5到3)按住一个方向键,按4.5到6等等。

由于每次在“PlayerSprite”类下调用“move”时画布将按(self.x,self.y)单位移动播放器,我们希望self.x和self.y为0或者你想要什么速度(以下代码中的1.5)。因此,我们应该将它分配给一个常量值,而不是添加到self.x和self.y:

def move_left(self, evt):
    self.x = -1.5

def move_right(self, evt):
    self.x = 1.5

def move_up(self, evt):
    self.y = -1.5

def move_down(self, evt):
    self.y = -1.5

此外,你可以做的是包括'KeyRelease- *'绑定,以便在你停止按住方向键后停止你的播放器,而不是使用“停止”:

game.canvas.bind_all('KeyRelease-Left'>, self.stop_horz_move)
game.canvas.bind_all('KeyRelease-Right'>, self.stop_horz_move)
game.canvas.bind_all('KeyRelease-Up'>, self.stop_vert_move)
game.canvas.bind_all('KeyRelease-Down'>, self.stop_vert_move)

(我已将左右方向概括为horz以及向上和向下方向转换为顶点,以节省函数定义的数量。)

然后你可以创建将self.x值或self.y值赋值为0的函数,这样一旦调用“move”,你的播放器就不会移动。

def stop_move_horz(self, evt):
    self.x = 0

def stop_move_vert(self, evt):
    self.y = 0