tl;dr Is there a good way to hide a column in a GridLayout
and also hide the remaining column spacing on the parent Composite
?
I have a composite with several columns in a GridLayout
. One column is a Composite
with a StackLayout
so that given some action I can hide/show that Composite
.
To do the hiding/showing I've been setting the exclude
attribute on the GridData
and the topControl
attribute on the StackLayout
:
// To hide
stackLayout.topControl = null;
stackComposite.setVisible(false);
((GridData) stackComposite.getLayoutData()).exclude = true;
Now, when I hide the middle Composite
, I see extra space appear at the far end of the row.
This is presumably because the GridLayout
on the base Composite
still has the same number of columns, so what we see is a column with 0 width, and the specified column spacing on either side.
To fix this I've come up with several (not-ideal) solutions:
Decrement/increment the number of columns when hiding/showing.
Instead of using the exclude
attribute, we override the Composite
with the StackLayout
and change the computeSize(...)
functions to either return 0, or compute the real size depending on whether we want it to appear or not. (This is by far my least favorite option and I feel bad even writing it)
Set the horizontalSpacing
on the base Composite
to 0, and instead using the spacing inside each columns Composite
to dictate the spacing. It would look like this when hidden:
Option 1 has been the most enticing so far, however there's an clear drawback here when trying to keep code modular. For example, if the Composite
for each column is setup by some reusable component, decrementing/incrementing a column count depends on that component knowing that its parent Composite
has a GridLayout
- not a safe assumption!
Option 2 I flat-out do not like.
Option 3 isn't horrible, however it still feels like a misuse of spacing and margins. Plus, back to the point of modularity, the other column components would be responsible spacing which affects the larger view, instead of letting the larger view dictate the spacing.
So my question comes down to: is there another option that's better than these three?
MCVE used to get the images above:
public class MCVE {
final Display display;
final Shell shell;
public MCVE() {
display = new Display();
shell = new Shell(display);
shell.setLayout(new GridLayout());
shell.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
final Composite baseComposite = new Composite(shell, SWT.NONE);
baseComposite.setLayout(new GridLayout(3, false));
baseComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
baseComposite.setBackground(new Color(display, new RGB(125, 125, 255)));
final Composite contentComposite1 = new Composite(baseComposite, SWT.NONE);
contentComposite1.setLayout(new GridLayout());
contentComposite1.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
final Label contentLabel1 = new Label(contentComposite1, SWT.NONE);
contentLabel1.setText("I stretch to fill available space!");
final Composite stackComposite = new Composite(baseComposite, SWT.NONE);
final StackLayout stackLayout = new StackLayout();
stackComposite.setLayout(stackLayout);
stackComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true));
final Composite stackContentComposite = new Composite(stackComposite, SWT.NONE);
stackContentComposite.setLayout(new GridLayout());
stackContentComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
final Label stackContentLabel = new Label(stackContentComposite, SWT.NONE);
stackContentLabel.setText("I can disappear and reappear!");
stackLayout.topControl = stackContentComposite;
final Composite contentComposite3 = new Composite(baseComposite, SWT.NONE);
contentComposite3.setLayout(new GridLayout());
contentComposite3.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true));
final Label contentLabel3 = new Label(contentComposite3, SWT.NONE);
contentLabel3.setText("I live on the end :(");
final Button flipButton = new Button(shell, SWT.PUSH);
flipButton.setText("Flip");
flipButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
if (stackLayout.topControl == null) {
stackLayout.topControl = stackContentComposite;
((GridData) stackComposite.getLayoutData()).exclude = false;
// ((GridLayout) baseComposite.getLayout()).numColumns++;
stackComposite.setVisible(true);
baseComposite.layout(true, true);
} else {
stackLayout.topControl = null;
((GridData) stackComposite.getLayoutData()).exclude = true;
// ((GridLayout) baseComposite.getLayout()).numColumns--;
stackComposite.setVisible(false);
baseComposite.layout(true, true);
}
}
});
}
public void run() {
shell.setSize(600, 115);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
public static void main(final String... args) {
new MCVE().run();
}
}
I can't think of any other way.
Option 1 is definitely what I would use and is used widely by Eclipse code (buttons on the dialog button bar for example).
Since you are already assuming the control layout data is GridData
it is safe to assume the parent layout is GridLayout
(setting GridData
as layout data on some other layout will generally give a run time error).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.