Form Component coding in pycharm

Does anyone know if there is any possible way to implement Form Component or similar when coding in pycharm and not in the builder?

thank you very very much!

@galaharon, if you add a Form component to Builder and compile the Python code, then you can ooen the .py file in Pycharm and see how to create and draw a Form component.

thank you very much!
do you know if it possible to write in Hebrew?

Sorry I don’t know , you could try. Also, @Michael may know about presenting Hebrew using Form, which is essentially presenting many TextStim components.

@Michael it’s written LTR instead of RTL
(also the text, and also the whole form - I would like the questions to be on the right and the answers on the left)

Thank you!!

Great, btw swapping the position of the items on the x-axis can be done using code. In the “begin routine” tab of a code component:

for item in yourForm.items:
    item['responseCtrl'].pos = list(item['responseCtrl'].pos)
    item['itemCtrl'].pos = list(item['itemCtrl'].pos)
    item['responseCtrl'].pos[0], item['itemCtrl'].pos[0] = item['itemCtrl'].pos[0], item['responseCtrl'].pos[0]

thank you!!!
what is the item name for the response answers (not the “responseCtrl”
because this doesn’t move

@dvbridges
this is a better image explaining

the problem

for item in TIPI_form.items:
    item['responseCtrl'].pos, item['itemCtrl'].pos = item['itemCtrl'].pos, item['responseCtrl'].pos
    # If the response slider is too far left, use below code
    sliderOffset = .3
    item['responseCtrl'].pos = [item['responseCtrl'].pos[0]+sliderOffset, item['responseCtrl'].pos[1]]

@galaharon try the above instead. Also, you can change the size of your item and response sliders using itemWidth and responseWidth values for each item in your spreadsheet.

sorry but i have another question - I have this code to end the survey once all the questions have been answered but it is not ending. (it seems like there are more questions that are supposed to be but there are not - I’m attaching a picture):

    if BFI.status == NOT_STARTED and tThisFlip >= 0.0 - frameTolerance:
        # keep track of start time/frame for later
        BFI.frameNStart = frameN  # exact frame index
        BFI.tStart = t  # local t and not account for scr refresh
        BFI.tStartRefresh = tThisFlipGlobal  # on global time
        win.timeOnFlip(BFI, 'tStartRefresh')  # time at next scr refresh
        BFI.setAutoDraw(True)

    # check for quit (typically the Esc key)
    if endExpNow or defaultKeyboard.getKeys(keyList=["escape"]):
        core.quit()

    # check if all components have finished
    if not continueRoutine:  # a component has requested a forced-end of Routine
        break
    continueRoutine = False  # will revert to True if at least one component still running
    for thisComponent in trialComponents:
        if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
            continueRoutine = True
            break  # at least one component has not yet finished

    # refresh the screen
    if continueRoutine:  # don't flip if this routine is over or we'll get a blank screen
        win.flip()

# -------Ending Routine "trial"-------
for thisComponent in trialComponents:
    if hasattr(thisComponent, "setAutoDraw"):
        thisComponent.setAutoDraw(False)
BFI.addDataToExp(thisExp, 'rows')
BFI.autodraw = False
# the Routine "trial" was not non-slip safe, so reset the non-slip timer
routineTimer.reset()

# Flip one final time so any remaining win.callOnFlip()
# and win.timeOnFlip() tasks get executed before quitting
win.flip()

In the “Each Frame” tab, add the following:

if bfi.complete:
    continueRoutine = False

Alternatively, you could add a a continue button that activates only when the Form is complete. For this, see the BigFive Demo in Builder.

thank you!!

Hi @dvbridges ! i think this will be my last question using the form component :slight_smile:
I managed to write in Hebrew by reversing the order of the characters

BUT for some unknown reason each run the questions are displayed differently - Hebrew (the way it need to be every run), or small boxes. It seems the problem is only in windows.
do you have any thoughts that can maybe help me?

my code is:

    # ------Prepare to start Routine "trial"-------
    original_allowStencil = win.allowStencil
    win.allowStencil = True

    BFI = visual.Form(
        win=win, name='BFI',
        items='bigFiveItems1.xlsx',
        textHeight=0.04,
        randomize=False,
        size=(1.7, 0.7),
        pos=(0, 0),
        style=('dark',),
        itemPadding=0.05
    )

    # update component parameters for each repeat
    # keep track of which components have finished
    trialComponents = [BFI]
    for thisComponent in trialComponents:
        thisComponent.tStart = None
        thisComponent.tStop = None
        thisComponent.tStartRefresh = None
        thisComponent.tStopRefresh = None
        if hasattr(thisComponent, 'status'):
            thisComponent.status = NOT_STARTED

    # reset timers
    _timeToFirstFrame = win.getFutureFlipTime(clock="now")
    trialClock.reset(-_timeToFirstFrame)  # t0 is time of first possible flip
    frameN = -1

    # change components from right to left
    for item in BFI.items:
        item['itemCtrl'].pos, item['responseCtrl'].pos = item['responseCtrl'].pos, item['itemCtrl'].pos
        # If the response slider is too far left, use below code
        sliderOffset = .7
        item['responseCtrl'].pos = [item['responseCtrl'].pos[0] + sliderOffset, item['responseCtrl'].pos[1]]

        # Reverse text
        item['itemCtrl'].text = item['itemCtrl'].text[::-1]
        for label in item['responseCtrl'].labelObjs:
            label.text = label.text[::-1]

    # -------Run Routine "trial"-------
    continueRoutine = True
    while continueRoutine:
        # # get current time
        t = trialClock.getTime()
        tThisFlip = win.getFutureFlipTime(clock=trialClock)
        tThisFlipGlobal = win.getFutureFlipTime(clock=None)
        frameN = frameN + 1  # number of completed frames (so 0 is the first frame)

        # # update/draw components on each frame
        #
        # *BFI* updates
        if BFI.status == NOT_STARTED and tThisFlip >= 0.0 - frameTolerance:
            # keep track of start time/frame for later
            BFI.frameNStart = frameN  # exact frame index
            BFI.tStart = t  # local t and not account for scr refresh
            BFI.tStartRefresh = tThisFlipGlobal  # on global time
            win.timeOnFlip(BFI, 'tStartRefresh')  # time at next scr refresh
            BFI.setAutoDraw(True)

        # check for quit (typically the Esc key)
        if kb.getKeys(keyList=["escape"]):
            core.quit()
            return

        # check if all components have finished
        if not continueRoutine:  # a component has requested a forced-end of Routine
            break
        continueRoutine = False  # will revert to True if at least one component still running
        for thisComponent in trialComponents:
            if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
                continueRoutine = True
                break  # at least one component has not yet finished

        # refresh the screen
        if continueRoutine:  # don't flip if this routine is over or we'll get a blank screen
            win.flip()

        # end if all questions were answered:
        if BFI.complete:
            continueRoutine = False


    BFI_rawdata = BFI.getData()

    # Cleanup
    for thisComponent in trialComponents:
        if hasattr(thisComponent, "setAutoDraw"):
            thisComponent.setAutoDraw(False)
    BFI.autodraw = False
    win.allowStencil = original_allowStencil
    win.flip()

and I get this error in all times (although it is running):
Exception ignored in: <function ImageStim.del at 0x0000020394085488>
Traceback (most recent call last):
File “C:\Users\schec\PycharmProjects\Reward_Effort_experiment\venv\lib\site-packages\psychopy\visual\image.py”, line 239, in del
File “C:\Users\schec\PycharmProjects\Reward_Effort_experiment\venv\lib\site-packages\pyglet\gl\lib.py”, line 99, in errcheck
TypeError: ‘NoneType’ object is not callable
Exception ignored in: <function TextStim.del at 0x000002039411A400>
Traceback (most recent call last):
File “C:\Users\schec\PycharmProjects\Reward_Effort_experiment\venv\lib\site-packages\psychopy\visual\text.py”, line 240, in del
File “C:\Users\schec\PycharmProjects\Reward_Effort_experiment\venv\lib\site-packages\pyglet\gl\lib.py”, line 99, in errcheck
TypeError: ‘NoneType’ object is not callable
Exception ignored in: <function TextStim.del at 0x000002039411A400>
Traceback (most recent call last):
File “C:\Users\schec\PycharmProjects\Reward_Effort_experiment\venv\lib\site-packages\psychopy\visual\text.py”, line 240, in del
File “C:\Users\schec\PycharmProjects\Reward_Effort_experiment\venv\lib\site-packages\pyglet\gl\lib.py”, line 99, in errcheck
TypeError: ‘NoneType’ object is not callable
thank you!!

Oh, do you have any rows in your Form file that only contain text? I.e., text with no response slider?

gal.xlsx (13.0 KB)
no. it looks like this

@galaharon , for some reason the Textbox2 used in Forms does not support Hebrew letters. It looks like the text shows up on the sliders (radio buttons) because Sliders use TextStim to present text. Do you plan on presenting this task online?

Regarding the error above, do you have any images presented in your task?

I’m not planning on presenting it online. is there a way to work around it?

no, I have no images, just the form questions on the screen and that’s all.

First, try setting the version to PsychoPy 2020.1.3 and running the task, as this version does not implement TextBox2. If that fails, please let me know the version of PsychoPy you are using and I can send you a modified Form component which uses TextStim in place of TextBox2.

for some reason i don’t have this version. another version maybe?
image

I would attempt this from the Builder interface. Oh, you can also use any of the 2020.1 versions.