tags:

views:

2312

answers:

3

I am trying to put together a dialog that should look like this:

Fill in the below fields
___________ likes ________________

where the "_" lines are the EditFields.

I am sticking all the fields in a HorizontalFieldManager, which I add to the dialog. Unfortunately, the first EditField consumes all the space on the first line. I have tried to override the getPreferredWidth() method of the EditField by creating my own class extending BasicEditField, but have had no success.

Surely there must be a simple way to force a certain size for an edit field. What am I missing?

+1  A: 

Try subclassing HorizontalFieldManager and override the sublayout method:

protected void sublayout(int maxWidth, int maxHeight) { }

In this method you should call setPositionChild and layoutChild for each component you are adding so you can control the positioning and size of each.

You should also override the layout method of each component and call setExtent(getPreferredWidth(), getPreferredHeight()); this will make use of your implementation of the getPreferred... methods you have already written.

Hope this helps.

DaveJohnston
+3  A: 

Just like DaveJohnston said:

class LikesHFManager extends HorizontalFieldManager {
    EditField mEditFieldLeft;
    LabelField mLabelField;
    EditField mEditFieldRight;
    String STR_LIKES = "likes";
    int mLabelWidth = 0;
    int mEditWidth = 0;
    int mOffset = 4;

    public LikesHFManager() {
     mEditFieldLeft = new EditField();
     mLabelField = new LabelField(STR_LIKES);
     mEditFieldRight = new EditField();

     mLabelWidth = mLabelField.getFont().getAdvance(STR_LIKES);
     int screenWidth = Display.getWidth();
     mEditWidth = (screenWidth - mLabelWidth) >> 1;
     mEditWidth -= 2 * mOffset;

     // calculate max with of one character
     int chMaxWith = mEditFieldLeft.getFont().getAdvance("W");
     // calculate max count of characters in edit field
     int chMaxCnt = mEditWidth / chMaxWith;

     mEditFieldLeft.setMaxSize(chMaxCnt);
     mEditFieldRight.setMaxSize(chMaxCnt);

     add(mEditFieldLeft);
     add(mLabelField);
     add(mEditFieldRight);
    }

    protected void sublayout(int maxWidth, int maxHeight) {

     int x = 0;
     int y = 0;

     int editHeight = mEditFieldLeft.getPreferredHeight();
     int labelHeight = mLabelField.getPreferredHeight();

     setPositionChild(mEditFieldLeft, x, y);
     layoutChild(mEditFieldLeft, mEditWidth, editHeight);
     x += mEditWidth;
     x += mOffset;

     setPositionChild(mLabelField, x, y);
     layoutChild(mLabelField, mLabelWidth, labelHeight);
     x += mLabelWidth;
     x += mOffset;

     setPositionChild(mEditFieldRight, x, y);
     layoutChild(mEditFieldRight, mEditWidth, editHeight);
     x += mEditWidth;

     setExtent(x, Math.max(labelHeight, editHeight));
    }
}
Max Gontar
Thanks! This example definitely makes things clearer.
Eric
You're welcome!
Max Gontar
A: 

Building on Max Gontar's solution, this should solve the general problem of assigning width to sub Fields of HorizontalFieldManagers:

import net.rim.device.api.ui.container.*;
import net.rim.device.api.ui.*;

public class FieldRowManager extends HorizontalFieldManager {
    public FieldRowManager(final long style)
    {
        super(style);
    }
    public FieldRowManager()
    {
        this(0);
    }

    private SubField FirstSubField = null;
    private SubField LastSubField = null;
    private static class SubField
    {
        public final Field Field;
        public final int Width;
        public final int Offset;
        private SubField Next;
        public SubField(final FieldRowManager container, final Field field, final int width, final int offset)
        {
            Field = field;
            Width = width;
            Offset = offset;

            if (container.LastSubField == null)
            {
                container.FirstSubField = this;
            }
            else
            {
                container.LastSubField.Next = this;
            }
            container.LastSubField = this;
        }
        public SubField getNext()
        {
            return Next;
        }
    }

    public void add(final Field field)
    {
        add(field, field.getPreferredWidth());
    }
    public void add(final Field field, final int width)
    {
        add(field, width, 0);
    }
    public void add(final Field field, final int width, final int offset)
    {
        new SubField(this, field, width, offset);
        super.add(field);
    }

    protected void sublayout(final int maxWidth, final int maxHeight)
    {
        int x = 0;
        int height = 0;
        SubField subField = FirstSubField;
        while (subField != null)
        {
            final Field field = subField.Field;
            final int fieldHeight = field.getPreferredHeight();
            this.setPositionChild(field, x, 0);
            this.layoutChild(field, subField.Width, fieldHeight);
            x += subField.Width+subField.Offset;
            if (fieldHeight > height)
            {
                height = fieldHeight;
            }

            subField = subField.getNext();
        }
        this.setExtent(x, height);
    }
}

Just call the overloads of the add method to specify the width, and the offset space before the next Field. Though this does not allow for deleting/replacing Fields.

It is irksome that RIM does not provide this functionality in the standard library. HorizontalFieldManager should just work this way.

JGWeissman