SWT RowLayout with last element grabbing excess horizontal space?

隐身守侯 提交于 2019-12-08 04:26:05

问题


I have two elements in a horizontal RowLayout. I am able to specify a (minimal) with for the second element (e.g. 200 px). Furthermore...

a) If the total width of the shell is too small, the second element wraps to a new line. That works fine with the RowLayout.

b) If the total with is "large", the second (=last) element should grab the excess horizontal space.

Is b) possible with the RowLayout? Or do I need to use a GridLayout and implement the wrapping on my own (e.g. use one or two columns in the grid layout, depending on the size of the elements)?

public class RowLayoutDemo {

    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setLayout(new RowLayout());

        Text firstElement = new Text(shell, SWT.NONE);
        firstElement.setText("firstElement");

        Text secondElement = new Text(shell, SWT.NONE);
        secondElement.setText("secondElement");
        secondElement.setBackground(new Color(null, 200, 0, 0));

        int minWidth = 200;
        RowData rowData = new RowData();
        rowData.width = minWidth;
        secondElement.setLayoutData(rowData);

        shell.pack();
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
    }
}


回答1:


The RowLayout does not support what you are looking for. I recommend using a GridLayout with a resize listener as you suggested or implement your own layout.




回答2:


I first tried to write a custom layout which turned out to be be hard. The second strategy based on GridLayout was easier. Here is a first draft for a custom Composite that switches the number of columns of its GridLayout to have one or two columns, depending on the size of its children.

(I still have an issues with flickering when resizing my Sections.)

package org.treez.core.adaptable.composite;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Layout;

/**
 * A row composite for only two children. If the children are too large for a single line, the second child is wrapped
 * on a second line. The second child always grabs excess horizontal space. This composite automatically sets the
 * LayoutData of its children. Therefore the LayoutData of the children should not be set manually.
 */
public class GrabbingRowComposite extends Composite {

    //#region ATTRIBUTES

    private int widthHintForFirstChild = 80;

    private int minWidthForSecondChild = 200;

    private boolean isSingleLine = true;

    //#end region

    //#region CONSTRUCTORS

    public GrabbingRowComposite(Composite parent) {
        super(parent);
        super.setLayout(createLayout());

        if (parent.getLayout() instanceof GridLayout) {
            GridData gridData = new GridData(SWT.FILL, SWT.BEGINNING, true, false);
            setLayoutData(gridData);
        }

    }

    //#end region

    //#region METHODS

    private GridLayout createLayout() {

        //create default layout for single line
        GridLayout gridLayout = new GridLayout(2, false);

        //change layout to use several lines if required
        this.addControlListener(new ControlAdapter() {

            @Override
            public void controlResized(ControlEvent e) {
                adaptLayout();
            }
        });

        return gridLayout;
    }

    private void adaptLayout() {

        int totalWidth = this.getBounds().width;

        Control[] children = getChildren();
        if (children.length < 2) {
            return;
        }

        Control firstChild = children[0];
        Control secondChild = children[1];
        int firstChildWidth = children[0].getBounds().width;

        setWidthHintForFirstChild(firstChild);
        setGrapHorizontalSpaceForSecondChild(secondChild);

        boolean isTooSmallForOneLine = totalWidth < firstChildWidth + minWidthForSecondChild;
        if (isTooSmallForOneLine) {
            setTwoLineLayout();
        } else {
            setSingleLineLayout();
        }
    }

    private void setTwoLineLayout() {
        if (isSingleLine) {
            super.setLayout(new GridLayout(1, false));
            updateLayoutOfParentAndGrandParent();
            isSingleLine = false;
        }
    }

    private void setSingleLineLayout() {
        if (!isSingleLine) {
            super.setLayout(new GridLayout(2, false));
            updateLayoutOfParentAndGrandParent();
            isSingleLine = true;
        }
    }

    private void setWidthHintForFirstChild(Control firstChild) {
        GridData firstGridData = new GridData();
        firstGridData.widthHint = widthHintForFirstChild;
        firstChild.setLayoutData(firstGridData);
    }

    private static void setGrapHorizontalSpaceForSecondChild(Control secondChild) {
        GridData secondGridData = new GridData(SWT.FILL, SWT.FILL, true, false);
        secondChild.setLayoutData(secondGridData);
    }

    private void updateLayoutOfParentAndGrandParent() {
        Composite parent = getParent();
        if (parent != null) {
            parent.layout(true);
            Composite grandParent = parent.getParent();
            if (grandParent != null) {
                grandParent.layout(true);
            }
        }
    }

    //#end region

    //#region ACCESSORS

    @Override
    public void setLayout(Layout layout) {
        throw new IllegalStateException("The layout of this composite must not be changed");
    }

    //#end region

}

Example usage

package org.treez.core.adaptable.composite;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.forms.widgets.ExpandableComposite;
import org.eclipse.ui.forms.widgets.Section;

public class GrabbingRowCompositeDemo {

    public static void main(String[] args) {

        Shell shell = createShell();

        shell.setSize(500, 300);

        Section section = createSection(shell);

        Composite parentComposite = createParentComposite(section);

        createRow(parentComposite, "first");

        createRow(parentComposite, "second");

        createRow(parentComposite, "third");

        section.clientVerticalSpacing = 0;

        showUntilClosed(shell);

    }

    private static Shell createShell() {
        Display display = new Display();
        Shell shell = new Shell(display);

        GridLayout shellGridLayout = new GridLayout(1, false);
        shell.setLayout(shellGridLayout);
        return shell;
    }

    private static Section createSection(Shell shell) {
        Section section = new Section(
                shell,
                ExpandableComposite.TWISTIE | //
                        ExpandableComposite.EXPANDED | //
                        ExpandableComposite.TITLE_BAR | //
                        ExpandableComposite.CLIENT_INDENT);

        GridData gridData = new GridData(SWT.FILL, SWT.BEGINNING, true, false);
        section.setLayoutData(gridData);
        return section;
    }

    private static Composite createParentComposite(Section section) {

        Composite parentComposite = new Composite(section, SWT.NONE);
        section.setClient(parentComposite);

        parentComposite.setBackground(new Color(null, 0, 0, 255));

        GridData gridData = new GridData(SWT.FILL, SWT.BEGINNING, true, false);
        parentComposite.setLayoutData(gridData);

        GridLayout gridLayout = new GridLayout(1, false);
        parentComposite.setLayout(gridLayout);

        return parentComposite;
    }

    private static Composite createRow(Composite parent, String text) {

        GrabbingRowComposite row = new GrabbingRowComposite(parent);
        row.setBackground(new Color(null, 255, 255, 255));

        Label label = new Label(row, SWT.NONE);
        label.setText(text);

        Button checkBox = new Button(row, SWT.CHECK);
        checkBox.setBackground(new Color(null, 255, 0, 0));

        return row;

    }

    private static void showUntilClosed(Shell shell) {

        shell.open();
        Display display = Display.getCurrent();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        display.dispose();
    }

}


来源:https://stackoverflow.com/questions/44999852/swt-rowlayout-with-last-element-grabbing-excess-horizontal-space

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!