0
votes

How can I vertically align a label with a Combo in the first row of an adjacent Composite?

The label and the multi-row control are in a GridLayout with other controls, with left-alignment of the labels and the fields. The multi-row control is re-used elsewhere.

enter image description here

Ideally, the baselines of the text in the label and the Combo would be aligned. In practice, when the label and combo are siblings, vertically centering the two with SWT.CENTER is usually sufficient.

I can't just lower the label by a compile-time constant, because of differences in fonts and look-and-feels.

Ideas that have occurred to me include:

  • At runtime, while constructing the controls, ask Eclipse for the height of its combo widgets, somehow. Embed the label in a Composite and pad or align appropriately.
  • Put the label (possibly embedded in a Composite) in a StackLayout with a dummy Combo that's never displayed, to give the label cell the height of the first row in the sibling control. Center align the label within its parent.

Is there a simpler/cleaner approach?

2
do you also reuse the label in the other places where the stacked combobox component is used?luksch
Even if you get the height of the Combo you don't know where in the control the text is which makes it impossible to align the Label text.greg-449
@luksch - So far, it's just been a standard SWT label, and the only potentially re-usable part beyond that has been the name. But I see your point. If it's not just a standard SWT label, it might be beneficial to have a single definition.Andy Thomas
@greg-449 - That's true, I have no guarantee that the baselines will align. However, in practice, vertically centering the label and the combo tends to work best among the available options, and doesn't look bad.Andy Thomas
Actually on a Mac the label looks better with Bottom alignment at least for a Read/Only Combo, the Read/Write Combo looks quite different.greg-449

2 Answers

1
votes

I confirmed that the problem can be solved by the second approach I suggested in the question. If anyone has a better answer, please post.

This approach has these objects:

AbstractLabelWithHeightOfAnotherControl / custom StackLayout
    <>-- Other control 
         Composite / GridLayout
            <>-- Label / GridData( SWT.BEGINNING, SWT.CENTER, false, true )

The custom StackLayout has the width of the label, but the height of the other control.

This code provides an abstract class that supports the behavior for a variety of other controls.

public abstract class AbstractLabelWithHeightOfAnotherControl extends Composite {

private Label m_label;
private Control m_otherControl;

/** Constructor.
 * @param parent
 * @param style
 */
public AbstractLabelWithHeightOfAnotherControl(Composite parent, int style) {
    super( parent, style );

    StackLayout stackLayout = new MyStackLayout();
    this.setLayout( stackLayout );

    Composite layerLabel = new Composite( this, SWT.NONE );
    GridLayout layerLabelLayout = new GridLayout( 1, false );
    layerLabelLayout.marginWidth = 0;
    layerLabelLayout.marginHeight = 0;
    layerLabel.setLayout( layerLabelLayout );
    m_label = new Label( layerLabel, SWT.NONE);
    m_label.setLayoutData( new GridData( SWT.BEGINNING, SWT.CENTER, false, true ) );

    m_otherControl = makeOtherControl( this );

    stackLayout.topControl = layerLabel;
}

protected abstract Control makeOtherControl( @Nonnull Composite parent );

public Label getLabel() {
    return m_label;
}

private final class MyStackLayout extends StackLayout {
    MyStackLayout() {
        this.marginHeight = 0;
        this.marginWidth = 0;
    }

    @Override
    protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
        int width = m_label.computeSize( wHint, hHint, flushCache ).x;
        int height = m_otherControl.computeSize( wHint, hHint, flushCache ).y;

        if (wHint != SWT.DEFAULT) width = wHint;
        if (hHint != SWT.DEFAULT) height = hHint;
        return new Point(width, height);
    }
}
}

The implementing class can just provide a method like this:

@Override
protected Control makeOtherControl( @Nonnull Composite parent ) {
    return new Combo( parent, SWT.NONE );
}
0
votes

What about creating a component like this:

+-------------------------------+ 
| +---------------------------+ |
| |  +------+ +-------------+ | |
| |  |Label | |Combobox     | | |
| |  +------+ +-------------+ | |
| +---------------------------+ |
| |  +------+ +-------------+ | |
| |  |Dummy | |Combobox     | | |
| |  +------+ +-------------+ | |
| +---------------------------+ |
| |  +------+ +-------------+ | |
| |  |Dummy | |Combobox     | | |
| |  +------+ +-------------+ | |
| +---------------------------+ |
+-------------------------------+ 

Have it created by a method that takes the label text as input. The Dummies are empty labels if you want. If the method label text is null you can omit the creation of the labels altogether or make all empty. That way you can reuse the multi combobox component with or without label.