Question

I am using PsychoPy and I would like to print the position of my mouse when it has been clicked.

The actual printing of the position needs to be placed inside a while loop. Using the code below, when I click I get more than one output lines, which print the same positions. I would like to have only one output printing for each click.

This is the code I am using:

#!/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()

Is there something wrong I am doing? Should the 'frame rate' of the while loop be changed?

Was it helpful?

Solution

I've not used the module, but it seems like mouse events are thrown for mouse raises as well.

You'll need to

  • Store the mouse state for next time

  • Each iteration, test whether the mouse state for button 0 has gone up → down

The mouse state is returned by myMouse.getPressed.

So something like:

oldMouseIsDown = False

while True:
    ...

    mouseIsDown = myMouse.getPressed()[0]
    myMouse.clickReset()

    if mouseIsDown and not oldMouseIsDown:
        print myMouse.getPos()

    oldMouseIsDown = mouseIsDown

OTHER TIPS

Veedrac's answer is correct. Your code is using the typical PsychoPy pattern of checking for events once every time the window is redrawn. This will typically be happening at least at 60 Hz. So unless you manage to press the mouse button for less than 16.7 ms (or less for a faster screen), you will detect it multiple times as being pressed, as each time you check on successive window redraws, the mouse button remains down. Even though it was pushed only once, the duration of the push is not instantaneous.

As Veedrac suggests, you therefore need to maintain the previous state of the mouse button in a variable so that you can choose to only print the position once. Mouseup events are not relevant here: you are purely testing for whether the button is currently pressed.

I had a very similar problem and fixed it in a slightly different way from the accepted answer. The advantage of this one is that you can set how long you want to 'desensitize' the mouse after a click (i.e. to prevent longer clicks from triggering your if loop multiple times). Depending on your mouse or the user's click release speed you can change 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()

By the way, the reason why the OP couldn't get Veedrac's answer work is because line oldMouseIsDown = mouseIsDown should be placed it inside the if loop rather than after it (not enough reputation to comment there).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top