psychopy.org | Reference | Downloads | Github

Clickable text fails

What are you trying to achieve?:
I am following the recent psychopy training that was given, trying to make a clickable text component with my instructions in order to move to the next frame in the instructions.

What did you try to make it work?:
I have instructions, a mouse component, and a clickable text component. The mouse component is set to save all valid clicks and the clickable stimuli is set as the clickable components name.

What specifically went wrong when you tried that?:
I get the following error message:

if obj.contains(startMouse):

AttributeError: ‘list’ object has no attribute ‘contains’

Experiment ended.

Please let me know if I’m missing something.

What does obj represent?

I think it represents my mouse component? I’m not entirely sure. I have a set of instructions, a mouse component, and a clickable text instruction. I linked the clickable text to the mouse and when I run the experiment everything shows up correctly but as soon as I click on my clickable text the experiment crashes and I get this error.

Some pictures for reference

Screen Shot 2021-03-01 at 11.08.06 PM Screen Shot 2021-03-01 at 11.08.10 PM

I think that your mouse component is actually called startMouse.

What component is named obj?

What custom code do you have that refers to an object of that name?

My guess is that you have a stimulus called obj but then also some custom code that redefines that name to point to a list.

I didn’t write any custom code for this. I’m following along the video from the workshop that was given the other week, so I’m using everything via the builder - so I’m not sure where obj is coming from.

These are the only components that I have

OK. Perhaps best if you post your .psyexp file here for us to look at.

posnerTarget.psyexp (17.0 KB)

Hopefully this is helpful. I’m using the example files listed on the workshop website for reference

OK, that’s really weird - you’ve come across a bug in PsychoPy itself that must be new and definitely shouldn’t be happening.

Hi Todd, @TParsons this might be one for you. Builder (v 2021.1.0) generates this code when checking if a stimulus contains a mouse click:

for obj in [[image, image1]]:
    if obj.contains(mouse):

i.e. the stimuli to be checked are nested within a list within a list, so obj.contains() will always fail when iterating over the elements of the outer list, as it only sees it containing one entry, which is a list rather than a stimulus. Seems odd that no other users have been hit by this though, as it should be a show-stopper for many (unless I’ve missed it)?

Okay thanks @Michael for letting me know. I will wait to hear back from you all about whether it’s fixed before doing anything else!

if nextButton.contains(startMouse):
     continueRoutine=False

Thanks for your response @wakecarter, it makes sense that obj should be nextButton. Unfortunately obj seems to have been set due to the bug.

You could remove nextButton from clickable stimuli and add my suggested code into the Each Frame tab of an auto translated code component.

Okay I can try this today! Thanks

Actually I think my code will count a hover. I use that form of code for mobile devices. For a click use if startMouse.isPressedIn(nextButton) or end the routine on any click and then check using contains in End Routine.

Ah, I see where this has come from! As conversion to a list is now handled by the parameter’s innate string conversion, the bit of code in Mouse which adds a [] is no longer needed, it adds [] around what is already a list… It’s an easy fix, so will put that in for the next bugfix release :slight_smile:

2 Likes

Thanks @TParsons ! Should I fix this in my code for now just so that I can keep moving ?

I think the best solution for now (and we’re talking just a few weeks at most, as we’ll be releasing minor versions fairly regularly as these little bugs crop up) is to leave “clickable stimuli” blank and instead add a Code component with this bit of your code:

if sum(buttons) > 0:  # state changed to a new click
    # check if the mouse was inside our 'clickable' objects
    gotValidClick = False
    for obj in [nextButton]:
        if obj.contains(startMouse):
            gotValidClick = True
             startMouse.clicked_name.append(obj.name)
    x, y = startMouse.getPos()
     startMouse.x.append(x)
     startMouse.y.append(y)
     buttons = startMouse.getPressed()
     startMouse.leftButton.append(buttons[0])
     startMouse.midButton.append(buttons[1])
     startMouse.rightButton.append(buttons[2])
     startMouse.time.append(startMouse.mouseClock.getTime())
     if gotValidClick:  # abort routine on response
          continueRoutine = False

copied into the Each Frame tab - essentially simulating what the Mouse component does, but editable at the code level.

This also doesn’t affect the Button component, so you could also replace startMouse and nextButton with a Button component and this would do the same thing.

1 Like