Southpaw Hare
Southpaw Hare

Reputation: 1593

Grid Layout - Sharing Relative Space

Is it possible to define manual ratios for columns in a grid layout which all grab excess horizontal space?

When using a Grid Layout with multiple items that have the grab excessive horizontal space option - particularly Tables, Trees, and the like - the layout automatically determines how to split the space between the multiple items based on various factors, such as how many columns each item has. This leads to the space being split unevenly between them, and this is intentional by design and usually a good thing.

30/70 Split

If one were to want the space to be split perfectly even, there is a make columns the same size option for that, as well.

50/50 Split

However, is it possible to define a different, non-automatic, non-equal-space percentage for columns? Would it be possible to, for instance, have the items in my examples have a 80/20 split with the larger amount going to the item with fewer columns, or which would otherwise be considered smaller through the automatic method?

Upvotes: 4

Views: 2464

Answers (3)

Stefan Haustein
Stefan Haustein

Reputation: 18813

Instead of listening to resize, you could also use a GridLayout with a higher number of columns that lets you distribute the space as desired by letting the contents span multiple columns.

For instance, for a 70:30 distribution, create a 10 column grid layout. Let the first child span 7 columns and the 2nd child span 3 columns.

Depending on your use case, a disadvantage of using GridLayout might be that it doesn't force the children down to the parent size if they want to be larger (a problem I frequently run into with long labels that could just wrap).

An option avoiding this problem is to implement a simple layout manager that supports percentages:

public class ColumnLayout extends Layout {

  int[] percentages;
  public ColumnLayout(int... percentages) {
    this.percentages = percentages;
  }

  @Override
  protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
    Control[] children = composite.getChildren();
    int height = hHint;
    int width = wHint;
    int consumedPercent = 0;
    for (int i = 0; i < children.length; i++) {
      int percent;
      if (i >= percentages.length) {
        percent = (100 - consumedPercent) / (children.length - percentages.length);
      } else {
        percent = percentages[i];
        consumedPercent += percent;
      }
      Point childSize = children[i].computeSize(wHint == -1 ? -1 : wHint * percent / 100, hHint);
      if (wHint == -1) {
        width = Math.max(width, childSize.x * (100 - percent) / 100);
      }
      if (hHint == -1) {
        height = Math.max(height, childSize.y);
      }
    }
    return new Point(width, Math.max(height, 0));
  }

  @Override
  protected void layout(Composite composite, boolean flushCache) {
    Control[] children = composite.getChildren();
    Rectangle available = composite.getClientArea();
    int x = available.x;
    int consumedPercent = 0;
    for (int i = 0; i < children.length - 1; i++) {
      int percent;
      if (i >= percentages.length) {
        percent = (100 - consumedPercent) / (children.length - percentages.length);
      } else {
        percent = percentages[i];
        consumedPercent += percent;
      }
      int w = available.width * percent / 100;
      children[i].setBounds(x, available.y, w, available.height);
      x += w;
    }
    if (children.length > 0) {
        children[children.length - 1].setBounds(x, available.y,
                available.width - (x - available.x), available.height);
    }
  }
}

That said, I am now usually just putting Labels I want to wrap just in a extra "cage" composite that limits their horizontal size request.

Upvotes: 1

superuser
superuser

Reputation: 731

Yes, you would do this programmatically like this:

  1. Get the size of the screen

  2. Edit the GridView's size based on the screen( ei. set the size to 1/2 of the screen for 50%)

  3. Refresh the page by calling view.invalidate()

Upvotes: -1

Baz
Baz

Reputation: 36904

Very related to this answer:

Yes, it's possible, but it's not as easy as GridLayout#setWeight(col, weight). Unfortunately, you have to listen to Resize events of the Shell (or the container that holds your GridLayout) and then setting the GridData of the contained components. The code below will set the percentages to 75% and 25%:

public static void main(String[] args)
{
    Display display = Display.getDefault();
    final Shell shell = new Shell(display);
    shell.setLayout(new GridLayout(2, false));

    Composite left = new Composite(shell, SWT.BORDER);
    Composite right = new Composite(shell, SWT.BORDER);

    final GridData leftData = new GridData(SWT.FILL, SWT.FILL, true, true);
    final GridData rightData = new GridData(SWT.FILL, SWT.FILL, true, true);

    left.setLayoutData(leftData);
    right.setLayoutData(rightData);

    shell.addListener(SWT.Resize, new Listener()
    {
        @Override
        public void handleEvent(Event arg0)
        {
            Point size = shell.getSize();

            leftData.widthHint = (int) (size.x * 0.75);
            rightData.widthHint = size.x - leftData.widthHint;

            System.out.println(leftData.widthHint + " + " + rightData.widthHint + " = " + size.x);
        }
    });

    shell.pack();
    shell.open();
    shell.layout();

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

After starting:

enter image description here

After resizing:

enter image description here

Upvotes: 3

Related Questions