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.
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
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.
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
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