Hi, I’m a PhD student, new to Psychopy and definitely new to coding in Python. I’m designing an experiment using the Builder, but will need to use code to achieve one particular part of the experiment.
I want participants to write a description/narration of a storyboard which consists of 22 images. Since they are narrating the whole thing, they need to be able to look through all of the slides at their leisure while they produce and edit their text. For this reason I assumed it would be best to keep it all on one routine.
Here is a quick slide showing more or less what I imagined the storyboard narration routine to look like. The part with the images could consist of some kind of frame including the images, maybe 2 or 3 at a time, and some kind of mechanism for going back and forward through them. I have depicted it with ‘next’ and ‘previous’ buttons, but I don’t really care exactly what mechanism is used, as long as it is easy for participants to use, and easy enough for me (with your help) to create.
I have been told this should be achievable using code, but I wouldn’t know where to start with making it happen. Also if you have any ideas of alternative ways of achieving what I want that you think would be better/easier, I’d love to hear them.
I’d be really grateful if someone can help me! Thank you in advance.
Hi there @Michaeljc53,
A good place to start here might be this YouTube tutorial.
Thank you so much for taking the time to reply to my post!
The video is helpful, the only problem is that if I use a loop like she does, wouldn’t that kind of ‘reset’ the textbox and wipe what the participant has written every time the participant changes what image to look at?
It would, we can get around this by inserting a code component like the one in this very basic experiment I’ve popped together (attached).
What’s going on in the code component in the trial routine is:
- A variable called
current_text is created at the start of the experiment (if you wanted to reset the text at a different point just put this code into a routine at a place that makes sense)
- At the start of the trial routine, the textbox text is set to =
current_text (so for the first iteration this will be blank)
- The user writes something in the textbox
- The text written by the user is saved to
current_text at the end of the routine
- The textbox text is then set to =
current_text (which is now whatever the user has written)
- The final response is stored to the data output in the save_text routine (again just add this into your experiment wherever makes sense for you)
Hope this helps!
textbox_example.psyexp (14.5 KB)
This is great, thank you so much for putting this together for me. I’ll have a go at integrating it all using the video too and might be back with more questions in the next couple of weeks!
Thank you for your help,
I’ve integrated the code from the tutorial and your ‘current text’ code and it is all working smoothly! There is a small issue though, which is that I will need to use something like ‘next’ and ‘previous’ buttons instead of key inputs to scroll back and forth through the slides, because I’ve got an editable textbox on the same routine, so the key inputs get confused sometimes.
I assume all it will need is a slight change of code, however I don’t quite know exactly how to express it. The relevant part of code right now is below (with the method of typing ‘1’ to go back and typing ‘2’ to go forward):
if Sb_key_resp.keys == ‘1’:
imageN -= 1
elif Sb_key_resp.keys == ‘2’:
imageN += 1
I assume it should be a simple case of replacing the if and elif lines to something that translates to:
“if next_button is pressed…”
“elif previous_button is pressed…”
However, I’m not sure how to express a button being pressed in Python code. To clarify what I mean by button, I’m thinking of using the button component in the Builder.
I’ll be very grateful if you or anyone can help!
So pleased that this has helped!
Your intuition is completely correct. What I actually tend to do, rather than using the button component itself, is create a nice looking ‘button’ in something like PowerPoint. This is easily done just by creating a shape with text and saving that shape as a .png. I then insert that as an image component into my routine. You’ll also need to add a mouse component, in order to do the clicking. Then, the code you need is pretty much the same as you have currently:
#This is assuming you have stored your images as "prev_button" and "next_button"
#and that your mouse is called "mouse"
imageN -= 1
imageN += 1
#Then just to make sure you don't end up with an imageN greater/less than the number
#of images you have, set min and max values - this assumes you have 3 images
if imageN < 1:
imageN = 1
elif imageN > 3:
imageN = 3
You’ll need to remove the keyboard component and set up the mouse to end the routine on a valid click, and list the clickable stimuli as
I’ve put a quick demo of this in the attached folder, hope it helps! Also, I’ve got nothing against the button component, this is just personal preference!
Textbox demo.zip (49.5 KB)
This is perfect, thank you so much for taking the time out to help me! I’ll be back in touch if something goes awry but it seems like it should all work.
Hopefully I won’t be bothering you any more! Thanks,
It’s really not a bother, and will benefit other future forum users too!
Let me know if you run into issues,
Hope you’re well!
I have progressed with my study and am almost ready to run it online using Pavlovia - but when I pilot run it online, there is a slight difference with how it runs locally. Online, when a next_button or prev_button is clicked, the text is retained as I require, but for some reason 2 things happen:
The cursor automatically moves back to the beginning of the text, meaning participants would have to use the arrow keys to scroll back to where they were so they can continue adding text to the end of their narration.
Any line breaks, as in when participants have pressed enter to start a new line or paragraph, get removed, meaning the text all ends up being one big block.
These are both relatively minor issues but they do affect how user-friendly the study is for participants. I presume they could also be resolved using code, but I don’t know what it would be - do you have any suggestions or ideas to point me in the right direction? Thanks!
EDIT: I asked chatGPT about this, and after a number of code suggestions that failed, it ended up telling me this:
"(…) it appears that preserving these aspects in an editable textbox while navigating between pages is not easily achievable using the current capabilities of Psychopy and Pavlovia.
The issue stems from the way Pavlovia handles HTML elements, which results in the loss of cursor position and line breaks when the routine restarts. Unfortunately, this limitation cannot be easily overcome with a straightforward code solution within the Psychopy/Pavlovia framework."
Is this really the case? It seems like a pretty basic thing that one should be able to do.
Great to hear you’ve made such good progress! In answer to your points:
- I’ve managed to solve this in my minimal experiment by moving the
current_text = textbox.text from the End Routine tab to the Each Frame tab, do let me know if this also solves the issue for you!
- This isn’t something I have the answer to right now, but I’ve asked our JS team for advice. I’ll get back to you as soon as I have an answer from them.
Hope this helps a little!
Hi @Kimberley_Dundas ,
Thank you for getting back to me again!
Just tested it and for me, changing it to the each frame tab now keeps line breaks, but actually sometimes increases them! So if I tap enter twice to start a new paragraph, when I press ‘next’ or ‘previous’ it actually moves the new paragraph text down another line as if I’ve tapped enter 3 times. This extra line can then be deleted with a backspace but it’s definitely not ideal. If I only press enter once though, the format is retained exactly, so it’s on the line below and there is no extra line created when pressing next or previous.
And yes the cursor still goes back to the beginning of the text each time. Thank you for following up with the JS team!