psychopy.org | Reference | Downloads | Github

Creating Multiple Lines of Text Input

OS : macOS Catalina 10.15.4
PsychoPy version: 2020.1.2
Standard Standalone? (y/n) : Yes
What are you trying to achieve?: I am trying to get participants to write a 10 line story on one page and be able to see all lines 1-10 of their story, and be able to go back and edit it if they have an issue with it.

What did you try to make it work?: I tried adapting the inputtext demo to display the numbers 1-10 so they would have the ability to click on each number and start writing the story on that line

What specifically went wrong when you tried that?: There was no error message but only numbers 1-4 showed up and instead of 1 being shown as 1 it was shown as 10 and it does not allow for the participants to click on the next line to input text there.

We’re currently working on some functionality to do this. While it’s in progress I think you might be able to do something like this using a keyboard component, a mouse component, 10 text components and a code component, but it will be pretty rudimentary and complicated to code…

Essentially what you want is to have the mouse set up to look for clicks on any of the 10 text components. You could then put something in the Each Frame tab of the code component to check what is stored in mouseComponent.clicked_name, and if it is one of your 10 text components, start listening to keyboardComponent.keys for new keypresses and add them to textComponent.text. However, this is likely to be very slow, complicated and prone to error! They also wouldn’t be able to use backspace, and you’d have to manually add in things like replacing space with an actual space, so I’m not sure it would work as a solution to this problem.

1 Like

Hi There,

This might not be exactly what you need but this is a code snippit I used to allow users to write over several lines, use return to go to next line, use backspace to delete and correct the text, and use the ‘/’ key to submit the answer and move to next trial. Just create a routine with a single code component and paste this into the “begin routine” tab of that component:


#show an introductory message
msg = visual.TextStim(win, 'type something:', height=0.1)

msg.draw()#this draws it
win.flip()#this flips the window to draw the message
event.waitKeys()
keyNames = {}
txt = ''
kb = keyboard.Keyboard()
while True:
    keys = kb.getKeys(waitRelease=False)
    for key in keys:
        if key.name!='backspace' and key.name!='escape':
            if key.name!='space' and key.name!='return'and key.name!='slash':
                thisKey=key.name
            elif key.name=='space':
                thisKey=' '
            elif key.name=='return':
                thisKey='\n'
            txt += "%s"%(thisKey)
        elif key.name=='backspace':
            txt = txt[:-1]
        elif pygKey=='escape':
            core.quit()
        if key.name=='slash':
            #save what they wrote
            break
    if key.name=='slash':
        #save what they wrote
        txt = txt[:-1]
        break
    #draw the message
    msg.text = txt
    msg.draw()
    win.flip()

if you want to save the whole story the participant writes paste this into the “end routine” tab of the code component:

thisExp.addData('response', txt)

Hope that helps!
Becca

1 Like

Hi! When I tried this, I kept getting an error saying there is a syntax error

I’ve just written a routine for serial recall that saves text responses into an array using arrow keys, enter and backspace to move between lines. Is that what you’re looking for?

Yes! That would work as well

Begin Routine

cursorCounter=0
cursorVariable='|'
subject_response_finished=False
thisitem=0
event.clearEvents()
recallitems=['','','','','','','']
displayText=""

Each Frame

if cursorCounter >= 30:
    if cursorVariable=='|':
        cursorVariable='.'
    else:
        cursorVariable='|'
    cursorCounter=0
cursorCounter+=1

if subject_response_finished:
    continueRoutine=False
    
keys = event.getKeys()
if len(keys):
    if 'escape' in keys:
        core.quit()
    elif 'backspace' in keys:
        if len(recallitems[thisitem])>0:
            recallitems[thisitem] = recallitems[thisitem][:-1]
        else:
            recallitems[thisitem-1]=recallitems[thisitem-1]+recallitems[thisitem]
            for Idx in range(thisitem,6):
                recallitems[Idx] = recallitems[Idx+1]
            recallitems[6]=''
            thisitem=thisitem-1
    elif 'delete' in keys:
        recallitems[thisitem] = recallitems[thisitem][:-1]
    elif 'space' in keys:
        subject_response_finished=True
    elif 'return' in keys and thisitem<6:
        thisitem=thisitem+1
        for Idx in range(6,thisitem,-1):
            recallitems[Idx] = recallitems[Idx-1]
        recallitems[thisitem] = ''
    elif 'up' in keys and thisitem>0:
        thisitem=thisitem-1
    elif 'down' in keys and thisitem<6:
        thisitem=thisitem+1
    elif 'a' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'A'
    elif 'b' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'B'
    elif 'c' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'C'
    elif 'd' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'D'
    elif 'e' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'E'
    elif 'f' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'F'
    elif 'g' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'G'
    elif 'h' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'H'
    elif 'i' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'I'
    elif 'j' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'J'
    elif 'k' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'K'
    elif 'l' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'L'
    elif 'm' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'M'
    elif 'n' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'N'
    elif 'o' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'O'
    elif 'p' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'P'
    elif 'q' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'Q'
    elif 'r' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'R'
    elif 's' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'S'
    elif 't' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'T'
    elif 'u' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'U'
    elif 'v' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'V'
    elif 'w' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'W'
    elif 'x' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'X'
    elif 'y' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'Y'
    elif 'z' in keys:
        recallitems[thisitem] = recallitems[thisitem]+'Z'
    else:
        pass

newText=''
for Idx in range(7):
    if numberText==1:
        newText = newText+str(nWords-6+Idx)+') '
    newText = newText+recallitems[Idx]
    if Idx == thisitem:
        newText = newText+cursorVariable
    newText = newText + '\n'
newText=newText + '______________'
if newText != displayText:
    displayText=newText
    recall_text.text=displayText

This auto translates with one serious exception.

for (var Idx = 6, _pj_a = thisitem; (Idx < _pj_a); Idx += (- 1)) {
needs to be corrected to
for (var Idx = 6, _pj_a = thisitem; (Idx > _pj_a); Idx += (- 1)) {

Also, since the text is centred locally but left justified online, I set the local cursor to lash between ‘|’ and ‘.’ instead of ‘|’ and ’ ’ .

core.quit(); also needs to be edited to psychoJS.quit();

Hey there,

If you are still having this issue, please could you copy and paste the exact syntax error you get here ?

That said @wakecarter might have provided the solution :slight_smile: in which case mark that response as the solution there for future users :slight_smile:

Best,
Becca

Hi! Thank you so much for your help, however, when I attempted to run this with your recommended edits, I get the error:
if numberText==1:
NameError: name ‘numberText’ is not defined

Hi I fixed the error I was having with your suggested code, however, is there a way to allow participants to see all 10 lines at a time so once they are done typing, it will move up and to the left corner of the screen or something along those lines

My code puts all the lines as a single text component on the screen at one time so I’m not sure I understand your question.

Did you solve the numberText error by adding numbersText=0 to Begin Experiment?

Yes I attempted that and I get a new error:
recall_text.text=displayText
NameError: name ‘recall_text’ is not defined

Where do you define recall_text ? Is it a Builder component or code? If it’s a Builder component in the same routine as the code with the error then move the code component down to after the text

Hi, Not sure if this was intended for my code component or @wakecarter. For mine it should show it all at once as well, but to change the position of TextStim use something like msg.setPos(x, y) - see here for details https://www.psychopy.org/api/visual/textstim.html