Python Tkinter从函数中获取按键事件

Python Tkinter从函数中获取按键事件,python,tkinter,Python,Tkinter,我有以下代码 如果我按“左箭头键”,它只打印将播放器向左移动 但是我需要一个功能,在这个功能中,按下给定的箭头键可以将玩家移动到给定的方向。 在我的move\u dir功能中是否有检测按键事件的方法 PS:对python来说相当陌生 import Tkinter as tk move = 1 pos = -1 def move_dir(): global move global pos while move ==1: if pos == 0:

我有以下代码

如果我按“左箭头键”,它只打印
将播放器向左移动
但是我需要一个功能,在这个功能中,按下给定的箭头键可以将玩家移动到给定的方向。

在我的
move\u dir
功能中是否有检测按键事件的方法
PS:对python来说相当陌生

import Tkinter as tk

move = 1
pos = -1


def move_dir():
    global move
    global pos
    while move ==1:
        if pos == 0:
            print 'move player to left'

        elif pos == 1:
            print 'move player to right'

        elif pos == -1:
            print 'stop moving!'

def kr(event):
    global move
    global pos
    global root
    if event.keysym == 'Right':
        move = 1
        pos = 0
        move_dir()
        print 'right ended'
    elif event.keysym == 'Left':
        move = 1
        pos = 1
        move_dir()
        print 'left ended'
    elif event.keysym == 'Space':
        move = 0
        move_dir()
    elif event.keysym == 'Escape':
        root.destroy()

root = tk.Tk()
print( "Press arrow key (Escape key to exit):" )
root.bind_all('<KeyRelease>', kr)
root.mainloop()
将Tkinter作为tk导入
移动=1
位置=-1
def move_dir():
全球行动
全球pos
当move==1时:
如果pos==0:
打印“向左移动播放器”
elif pos==1:
打印“将玩家向右移动”
elif pos==-1:
打印“停止移动!”
def kr(事件):
全球行动
全球pos
全局根
如果event.keysym=='Right':
移动=1
pos=0
move_dir()
打印“右端”
elif event.keysym==‘Left’:
移动=1
位置=1
move_dir()
打印“左端”
elif event.keysym=='Space':
移动=0
move_dir()
elif event.keysym==‘Escape’:
root.destroy()
root=tk.tk()
打印(“按箭头键(退出键):”)
root.bind_all(“”,kr)
root.mainloop()

编辑4

您有一个while循环,希望与Tkinter main循环相结合。 在这种情况下,您希望按键时移动,松开按键时停止移动。 下面的代码允许您执行此操作:

import Tkinter as tk
from guiLoop import guiLoop # https://gist.github.com/niccokunzmann/8673951#file-guiloop-py

direction = 0
pos = 0 # the position should increase and decrease depending on left and right
# I assume pos can be ... -3 -2 -1 0 1 2 3 ...

@guiLoop
def move_dir():
    global pos
    while True: # edit 1: now looping always
        print 'moving', direction 
        pos = pos + direction
        yield 0.5 # move once every 0.5 seconds

def kp(event):
    global direction # edit 2
    if event.keysym == 'Right':
        direction  = 1 # right is positive
    elif event.keysym == 'Left':
        direction = -1
    elif event.keysym == 'Space':
        direction = 0 # 0 is do not move
    elif event.keysym == 'Escape':
        root.destroy()

def kr(event):
    global direction
    direction = 0

root = tk.Tk()
print( "Press arrow key (Escape key to exit):" )
root.bind_all('<KeyPress>', kp)
root.bind_all('<KeyRelease>', kr)
move_dir(root)
root.mainloop()
将Tkinter作为tk导入
从Guilloop导入Guilloop#https://gist.github.com/niccokunzmann/8673951#file-吉卢普
方向=0
pos=0#位置应根据左右而增减
#我想pos可以是-3 -2 -1 0 1 2 3 ...
@吉卢普
def move_dir():
全球pos
虽然为True:#编辑1:现在始终循环
打印“移动”方向
位置=位置+方向
产量0.5#每0.5秒移动一次
def kp(事件):
全局方向#编辑2
如果event.keysym=='Right':
方向=1#右侧为正
elif event.keysym==‘Left’:
方向=-1
elif event.keysym=='Space':
方向=0#0表示不移动
elif event.keysym==‘Escape’:
root.destroy()
def kr(事件):
全球方向
方向=0
root=tk.tk()
打印(“按箭头键(退出键):”)
root.bind_all(“”,kp)
root.bind_all(“”,kr)
移动目录(根目录)
root.mainloop()
要了解这是如何实现的,您可以阅读源代码或阅读Bryan Oakley的第二个答案

编辑3

无法直接在
move\u dir
功能中检测按键。 您可以在
move_dir
函数中使用
root.update()
,以便在调用
root.update
时执行
kr
kp
root.update()
还会重新绘制窗口,以便用户可以看到更改


root.mainloop()
可以被视为
,而True:root.update()
如果您想要为某个对象设置动画,则应该在
之后使用
来设置动画循环。动画循环如下所示:

def animate():
    <draw one frame of your animation>
    after(<delay>, animate)
def animate():
    if direction is not None:
        print "move player to the ", direction
    after(33, animate)

def on_keypress(event):
    global direction
    if event.keysym == "Left":
        direction = "left"
    elif event.keysum == "right":
        direction = "right"

def on_keyrelease(event):
    global direction
    direction = None
看到了吗?当你按下一个键时,它定义了方向。然后,每33毫秒检查一次方向,如果确定了方向,则移动播放器。当用户松开按钮时,方向变得不确定,移动停止

把它们放在一起,并使用一个类来避免使用全局变量,它看起来如下所示。这将在画布上创建一个球,可以向左、向右、向上和向下移动:

import Tkinter as tk

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

        self.direction = None

        self.canvas = tk.Canvas(width=400, height=400)
        self.canvas.pack(fill="both", expand=True)
        self.canvas.create_oval(190, 190, 210, 210, 
                                tags=("ball",),
                                outline="red", fill="red")

        self.canvas.bind("<Any-KeyPress>", self.on_press)
        self.canvas.bind("<Any-KeyRelease>", self.on_release)
        self.canvas.bind("<1>", lambda event: self.canvas.focus_set())

        self.animate()

    def on_press(self, event):
        delta = {
            "Right": (1,0),
            "Left": (-1, 0),
            "Up": (0,-1),
            "Down": (0,1)
        }
        self.direction = delta.get(event.keysym, None)

    def on_release(self, event):
        self.direction = None

    def animate(self):
        if self.direction is not None:
            self.canvas.move("ball", *self.direction)
        self.after(50, self.animate)

if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(fill="both", expand=True)
    root.mainloop()
将Tkinter作为tk导入
类示例(tk.Frame):
定义初始化(自身,父级):
tk.Frame.\uuuu init\uuuuu(自,父)
self.direction=无
self.canvas=tk.canvas(宽度=400,高度=400)
self.canvas.pack(fill=“both”,expand=True)
self.canvas.create_椭圆形(190190210210,
标记=(“球”,),
outline=“red”,fill=“red”)
self.canvas.bind(“,self.on_press)
self.canvas.bind(“,self.on_release)
self.canvas.bind(“,lambda事件:self.canvas.focus\u set())
self.animate()
def on_按下(自身,事件):
增量={
“右”:(1,0),
“左”:(-1,0),
“向上”:(0,-1),
“向下”:(0,1)
}
self.direction=delta.get(event.keysym,None)
def on_释放(自身、事件):
self.direction=无
def动画(自):
如果self.direction不是None:
self.canvas.move(“球”、*self.direction)
self.after(50,self.animate)
如果名称=“\uuuuu main\uuuuuuuu”:
root=tk.tk()
示例(root).pack(fill=“both”,expand=True)
root.mainloop()

谢谢你的回复,但这不是我想要的。让我再次解释一下,如果我按下右键,只要没有按下其他键,我就想向右移动。在您的示例中,它移动一个位置并停止,但我需要保持该位置的增量,直到按空格、左键或Escape键编辑文章。我猜:)又编辑了一次。。更改了move_dir的调用。我创建了Guilloop,以便能够使用while循环和Tkinter。如果您不想使用它,请告诉我。如果您可以与Guilloop一起使用,请告诉我。我会很高兴的。有可能在不使用while循环的情况下通过连续函数调用来实现。感谢您的及时响应。我正在使用guiLoop,但我也想知道其他的可能性。每当我在GUI程序中看到无限循环时,我的蜘蛛就会感到刺痛。即使你有收益,我认为有更好的方法来完成同样的事情。谢谢布莱恩。我认为问题的方向不同。我必须用箭头键控制步进电机,而不是移动
播放器
。所以,
键的行程可以让我的马达在那个方向移动