在While循环中单次鼠标点击(PsychoPy)
我正在使用PsychoPy,想要在鼠标点击时打印出它的位置。
实际上,我需要把打印位置的代码放在一个循环里。但是用下面的代码,当我点击时,会输出多行相同的位置。我希望每次点击只输出一行。
这是我正在使用的代码:
#!/usr/bin/env python2
from psychopy import visual, core, event
from pyglet.gl import *
width = 600
height = 600
myWin = visual.Window([width,height], color='white',units='pix',monitor='testMonitor')
#This will set the windows units (pixels) to GL units
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0, width, 0, height, -1, 1)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glEnable(GL_BLEND)
glBlendFunc(GL_ZERO, GL_SRC_COLOR)
myMouse = event.Mouse() # will use myWin by default
while True:
#Triangle left
glColor3f(1.0, 0.0, 0.0)
glBegin(GL_TRIANGLES)
glVertex3f(150, 550, 1)
glVertex3f(50, 350, 1)
glVertex3f(250, 350, -1)
glEnd()
if myMouse.getPressed()[0]:
myMouse.clickReset()
print myMouse.getPos()
myWin.flip()
core.quit()
我是不是做错了什么?这个循环的“帧率”需要调整吗?
3 个回答
2
我遇到过一个很相似的问题,解决的方法跟大家接受的答案稍微有点不同。这种方法的好处是,你可以设置在点击后要“去敏感”鼠标多长时间(也就是说,可以防止长按鼠标导致你的判断语句被多次触发)。根据你的鼠标或者用户释放点击的速度,你可以调整一下 minFramesAfterClick
的值:
minFramesAfterClick = 10 # to prevent re-entering the if loop too early
myMouse.clickReset()
timeAfterClick = 0
while True:
timeAfterClick += 1
if myMouse.getPressed()[0] and timeAfterClick >= minFramesAfterClick:
print myMouse.getPos()
myMouse.clickReset()
timeAfterClick = 0
myWin.flip()
顺便说一下,原问题的提问者之所以无法让Veedrac的答案生效,是因为 oldMouseIsDown = mouseIsDown
这一行应该放在判断语句里面,而不是放在后面(我没有足够的声望在那儿评论)。
3
Veedrac的回答是对的。你的代码使用了PsychoPy的常见模式,每次窗口重绘时检查事件。这种重绘通常每秒至少会发生60次。所以,除非你能在16.7毫秒内(如果屏幕更快,时间会更短)按下鼠标按钮,否则你会多次检测到按钮被按下。因为每次检查时,鼠标按钮都是按着的。虽然你只按了一次,但按下的时间并不是瞬间的。
正如Veedrac所建议的,你需要在一个变量中保存鼠标按钮的上一个状态,这样你就可以选择只打印一次位置。这里的鼠标抬起事件并不重要:你只是测试按钮当前是否被按下。
3
我没有使用过这个模块,但看起来鼠标事件也会因为鼠标的抬起而触发。
你需要:
保存鼠标的状态,以便下次使用
在每次循环中,检查鼠标按钮0的状态是否从按下变为抬起
鼠标的状态可以通过 myMouse.getPressed
来获取。
所以可以写成这样:
oldMouseIsDown = False
while True:
...
mouseIsDown = myMouse.getPressed()[0]
myMouse.clickReset()
if mouseIsDown and not oldMouseIsDown:
print myMouse.getPos()
oldMouseIsDown = mouseIsDown