psychopy.org | Reference | Downloads | Github

Creating Clickable Buttons on Windows Surface (Touchscreen)

Hi all,

I’d like participants to be able to touch a button on either side of the screen of a Windows Surface for an on-site IAT test. Thus far, I’ve run into a few issues.

The first is that, in order for the program to move forward, the screen has to be tapped twice. I’m not sure exactly why this is. I used Builder to create a click event so that when the mouse is clicked (or in this case, the equivalent event of ‘screen is touched’) the routine ends. However, this doesn’t seem to be translating over well to the touchscreen as the screen always has to be tapped twice before the programs moves forward. Does anyone have any experience with this or any ideas?

The more pressing, second problem is that I’m not sure how to code the ‘touch’ for a specific button As of right now, double tapping any area of the screen moves the program forward. I’d like to restrict the clickable area to the size of the button (which is composed of a polygon and text). I looked at the API and saw isPressedIn(), which seems like the function most relevant to what I’m trying to accomplish. Since the polygon has a .contains() method, I figured that would be the next step. Unfortunately, upon testing, isPressedIn() never returns true. At this point, even dividing the screen in half and storing a different result for right and left would be fine. I think that would require a getPos() call, but I’m not quite sure where to go from there. I don’t have much experience with Python or PsychoPy, so any help here would be really appreciated!

If anyone can point me in the direction of helpful manuals or resources, or has similar code they’d be willing to share, I’d be very grateful.

Thank you so much for any assistance or ideas!

Best,

Paige

1 Like

Hi Paige,

I do not have a Surface Pro so cannot test this - but it appears that a press on a touch screen is not a solid signal but has a lot of noise around it. I’ve had a similar issue with mouse clicks in experiments in the past.

Try something along the lines of (remembering to indent lines after each colon):

#Code component Beginning of Routine
Pressed = False

#Code component Every Frame

while Pressed == False:
    if mouse.isPressedIn(Polygon):
        Pressed = True
        do something
        continueRoutine = False

    elif mouse.isPressedIn(Polygon2):
        Pressed True
        do something
        continueRoutine = False

This loop will keep going until a press is registered and then stop checking as soon as it is… Also, make sure your mouse event is not set to end routine on click - that way only a click in the polygon will register.

I am very sorry if you’ve received so many editing notifications for this post!

1 Like

Hi @Oli, if you wrap your code blocks in triple backticks, the indentation will be preserved, and automatic syntax highlighting will be enabled.

1 Like

Thank you so much!! The loop worked to constrain the clickable area. The only minor problem is that the text and polygon don’t appear on the screen, even though they’re within the loop. Unfortunately, taking the text and polygon part out of loop didn’t fix the problem. I’m sure I’m missing something fairly simple with this (the woes of being a newbie), so if you wouldn’t mind looking the code over I’d really appreciate it!

Here’s what I have for the instructional screen (which has only a continue button):

InstructionsClock = core.Clock()
Pressed= False
mouse = event.Mouse(win=win)
x, y = [None, None]

while Pressed == False:
    text_2 = visual.TextStim(win=win, name='text_2',
        text='You will be presented with words or images to classify into categories using the buttons on the screen. \n \nTry to go as fast as possible while making as few mistakes as possible. \n',
        font='Arial',
        pos=[0, 0.1], height=0.1, wrapWidth=None, ori=0, 
        color='white', colorSpace='rgb', opacity=1,
        depth=0.0);
    polygon = visual.Rect(
        win=win, name='polygon',
        width=(0.4, 0.4)[0], height=(0.4, 0.4)[1],
        ori=0, pos=(0, -.5),
        lineWidth=1, lineColor=[1,1,1], lineColorSpace='rgb',
        fillColor=[1,1,1], fillColorSpace='rgb',
        opacity=1, depth=-1.0, interpolate=True)
    text_4_Continue = visual.TextStim(win=win,       name='text_4_Continue',
        text='Continue',
        font='Arial',
        pos=(0, -.5), height=0.1, wrapWidth=None, ori=0, 
        color='black', colorSpace='rgb', opacity=1,
        depth=-2.0);
    if mouse.isPressedIn(polygon):
        continueRoutine = False
        Pressed = True
    elif mouse.isPressedIn(polygon)== False: 
        continueRoutine = True

Thanks again!

  • Paige

You’re not displaying your stimuli. You will want to create the stimuli outside the loop, and just display them inside the loop via their respective draw() methods and win.flip().

text_2 = visual.TextStim(win=win, name='text_2',
    text='You will be presented with words or images to classify into categories using the buttons on the screen. \n \nTry to go as fast as possible while making as few mistakes as possible. \n',
    font='Arial',
    pos=[0, 0.1], height=0.1, wrapWidth=None, ori=0,
    color='white', colorSpace='rgb', opacity=1,
    depth=0.0)

polygon = visual.Rect(
    win=win, name='polygon',
    width=(0.4, 0.4)[0], height=(0.4, 0.4)[1],
    ori=0, pos=(0, -.5),
    lineWidth=1, lineColor=[1,1,1], lineColorSpace='rgb',
    fillColor=[1,1,1], fillColorSpace='rgb',
    opacity=1, depth=-1.0, interpolate=True)

text_4_Continue = visual.TextStim(win=win, name='text_4_Continue',
    text='Continue',
    font='Arial',
    pos=(0, -.5), height=0.1, wrapWidth=None, ori=0,
    color='black', colorSpace='rgb', opacity=1,
    depth=-2.0)

mouse = event.Mouse(win=win)
Pressed = False

while not Pressed:
    text_2.draw()
    polygon.draw()
    text_4.draw()
    win.flip()

    if mouse.isPressedIn(polygon):
        Pressed = True
        continueRoutine = False

I also simplified your while condition and the if block a bit.

You could even further simplify the while loop and get rid of the Pressed variable:

while True:  # Forever.
    text_2.draw()
    polygon.draw()
    text_4.draw()
    win.flip()

    if mouse.isPressedIn(polygon):
        continueRoutine = False
        break  # Exit the while loop.
1 Like

Thanks again for all the help!

I think the issue I’m running into now is that the routine isn’t ended once the button is pressed. It prints “A” when pressed, but continueRoutine = False doesn’t seem to be working. The stimuli are displayed, it only registers clicks within the bounded area of the polygon, and I’m not getting any error messages. The program just doesn’t move forward.

InstructionsClock = core.Clock()
Pressed= False
mouse = event.Mouse(win=win)
x, y = [None, None]

text_2 = visual.TextStim(win=win, name='text_2',
    text='You will be presented with words or images to classify into categories using the buttons on the screen. \n \nTry     to go as fast as possible while making as few mistakes as possible. \n',
    font='Arial',
    pos=[0, 0.1], height=0.1, wrapWidth=None, ori=0,
    color='white', colorSpace='rgb', opacity=1,
    depth=0.0)

polygon = visual.Rect(
    win=win, name='polygon',
    width=(0.4, 0.4)[0], height=(0.4, 0.4)[1],
    ori=0, pos=(0, -.5),
    lineWidth=1, lineColor=[1,1,1], lineColorSpace='rgb',
    fillColor=[1,1,1], fillColorSpace='rgb',
    opacity=1, depth=-1.0, interpolate=True)

text_4_Continue = visual.TextStim(win=win, name='text_4_Continue',
    text='Continue',
    font='Arial',
    pos=(0, -.5), height=0.1, wrapWidth=None, ori=0,
    color='black', colorSpace='rgb', opacity=1,
    depth=-2.0)

Pressed = False

while not Pressed:
    text_2.draw()
    polygon.draw()
    text_4_Continue.draw()
    win.flip()
    if mouse.isPressedIn(polygon):
        Pressed = True
        print "A"
        continueRoutine = False 

Any help would be appreciated. Thanks again!

I think continueRoutine is a builder feature - since you’re using coder you might just need to skip to the next trial using continue - try:

continueRoutine = False
continue

If that works you can delete continueRoutine = False

Hi Paige!

Did you use images in your IAT? Could you help point me in the direction of where to learn how to input images into a psychopy experiment?

Thank you!
Jennifer

Hi Jennifer!

I would really suggest looking at the Open IAT here. If you change the images in the stimuli folder to your own (making sure they’re close to the same size as the originals, I got a memory error when trying to use images that were much larger in pixel size), then you should be good to go!

Best of luck,

Paige