How do I stack fields vertically in Crystal Reports 2008

ShoeLace picture ShoeLace · Jan 19, 2012 · Viewed 10k times · Source

I am using Crystal Reports 2008 to develop some reports (on an oracle database ).

I have a number of text fields in my design/layout that I want to be positioned in a vertical stack with no space between.

Using Oracle reports I can select the fields and do an align->stackvertical, but there does not seem to be a similar option in CR2008

The "Align" option has tops,middles,bottoms,baseline,lefts,centres,rights,to grid. none of which do what i want.

Is there an easy way to do this? or do I just have to position them manually? (maybe using snap-to-grid)

Answer

Rory O'Kane picture Rory O'Kane · May 30, 2013

I already described how to manually align the fields using the Object Size and Position dialog. I have now written a Sikuli script to automate that use of the dialog. I successfully used the script to stack about 70 new fields underneath existing stacked ones.

To use this script, copy and paste its contents into Sikuli IDE. Open Crystal Reports and find the field at the bottom of the existing stack. Make sure the new field you want to add to the bottom of the stack exists and is visible on-screen. Select the field at the bottom of the stack. Then switch to Sikuli and hit CtrlR to start the script. It will switch to Crystal Reports and open the Size and Position dialog, read the existing values for the field at the bottom of the stack, and close the dialog. You now have 1.5 seconds (configurable) to select the new field by clicking on it. Now the script will open the Size and Position dialog again and set the X, Y, Width, and Height so that the selected field is placed underneath the previous one. Specifically, the X, Width, and Height are set to the same as the above field, and the Y is set as I described in my other answer. You can change the configuration variable VERTICAL_SPACE_BETWEEN_FIELDS to add space between each field or cause them to overlap, if you want.

The script takes about 5 seconds to align one field. If that's too slow, you can try decreasing the time in or removing some of the wait() calls. I added the wait() calls because the script sometimes copied or pasted the wrong value if it went too fast.

One nice thing about this script is that it is chainable. Right after it finishes, the newly-aligned field will still be selected. So if you have another field you want to add under that field, you can just run the script again with CtrlR, and get ready to click on the next field in the middle. If you plan to chain many times, you can increase the 1 in range(1) and add wait(<num_of_seconds>) below mainAction() so that the script repeats itself automatically. Just keep in mind that chaining requires that the next field to add be visible on screen, so you can select it with the mouse.

I saved the script file as "Align Fields in Crystal Reports.sikuli".

# Crystal Reports: stack prompt-selected field under start-selected field

VERTICAL_SPACE_BETWEEN_FIELDS = 0.000
WAIT_TIME_FOR_USER_SELECT_NEW_FIELD = 1.5

def mainAction():
    # read size and position of bottom of stack
    above = dict()
    openSizeAndPositionDialog()
    above['x'] = copySelectedText()
    moveToNextField(2)
    above['y'] = copySelectedText()
    moveToNextField()
    above['width'] = copySelectedText()
    moveToNextField(2)
    above['height'] = copySelectedText()
    print("above", above)
    wait(0.05)
    type(Key.ESC)

    # calculate size and position of next field in stack
    new_field = dict()
    new_field['x'] = above['x']
    new_field['y'] = str(float(above['y']) + float(above['height']) + VERTICAL_SPACE_BETWEEN_FIELDS)
    new_field['width'] = above['width']
    new_field['height'] = above['height']
    print("new field", new_field)

    waitForUserToSelectNewField()

    # set size and position of next field
    openSizeAndPositionDialog()
    paste(new_field['x'])
    moveToNextField(2)
    paste(new_field['y'])
    moveToNextField()
    paste(new_field['width'])
    moveToNextField(2)
    paste(new_field['height'])
    wait(0.1)
    type(Key.ENTER)

def openSizeAndPositionDialog():
    type(Key.ALT + "a" + "z")
    wait(0.05)

def copySelectedText():
    type("c", KeyModifier.CTRL)
    wait(0.05)
    return Env.getClipboard()

def moveToNextField(numTimes=1):
    for i in range(numTimes):
        type(Key.TAB)
        wait(0.05)

def waitForUserToSelectNewField():
    # I'll do it without the popup, because switching to the popup and then closing it is a pain
    wait(WAIT_TIME_FOR_USER_SELECT_NEW_FIELD)

    #popup("select the new field to align under the old one, then press OK")
    #wait(0.2)

App.focus("Crystal Reports")
wait(0.2) # give you time to release CTRL, which would interfere with the script
for i in range(1):
    mainAction()