问题
I'm working on this Composite
canvas on which other Composite
s may be added and removed.
My understanding of how the whole laying-out concept is still in the fog.
When children are added to the container, given the fact that the container has a GridData
which fills in the parent, shouldn't the parent also know that the child resized? Children remain hidden after their container has been laid out, because of the shell (top parent).
If the question is too vague, do not hesitate to ask for more details. Also, try your best not pointing me to the Understanding layouts in SWT article.
/**
*
* @author ggrec
*
*/
public class SSCCE
{
// ==================== 2. Instance Fields ============================
private Composite componentContainer;
private int componentCount = 0;
// ==================== 3. Static Methods =============================
public static void main(final String[] args)
{
new SSCCE();
}
// ==================== 4. Constructors ===============================
private SSCCE()
{
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, false));
createContents(shell);
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
// ==================== 5. Creators ===================================
private void createContents(final Composite parent)
{
parent.setLayout(new GridLayout());
parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
final Button button = new Button(parent, SWT.PUSH);
button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
button.setText("Add New Component");
button.addSelectionListener(new SelectionAdapter()
{
@Override public void widgetSelected(final SelectionEvent e)
{
addNewComponent();
componentContainer.layout();
}
});
componentContainer = new Composite(parent, SWT.BORDER);
componentContainer.setLayout(new GridLayout());
componentContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
}
// ==================== 6. Action Methods =============================
private void addNewComponent()
{
final Composite component = new Composite(componentContainer, SWT.BORDER);
component.setLayout(new FillLayout());
component.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
final Label label = new Label(component, SWT.NONE);
label.setText( String.valueOf(componentCount++) );
}
}
Fun fact: This question is veeeery related to this other one, that was posted 9 minutes ago. Someone is either psychic or stalking me.
回答1:
To get the Shell
to resize you need to layout everything and recalculate its size:
shell.layout(true, true);
final Point newSize = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
shell.setSize(newSize);
You may be able to get away with calling layout()
on a child Composite
of the shell depending on what has changed.
回答2:
The secret here to probably solve your problem is TELLING the parent that the children have been resized. So, no, they do not automatically know it has happened.
the way to fix this, is to call the:
Parent.layout(true)
from the swt api:
public void layout(boolean changed)
If the receiver has a layout, asks the layout to lay out (that is, set the size and location of) the receiver's children. If the argument is true the layout must not rely on any information it has cached about the immediate children. If it is false the layout may (potentially) optimize the work it is doing by assuming that none of the receiver's children has changed state since the last layout. If the receiver does not have a layout, do nothing.
If a child is resized as a result of a call to layout, the resize event will invoke the layout of the child. The layout will cascade down through all child widgets in the receiver's widget tree until a child is encountered that does not resize. Note that a layout due to a resize will not flush any cached information (same as layout(false)).
Note: Layout is different from painting. If a child is moved or resized such that an area in the parent is exposed, then the parent will paint. If no child is affected, the parent will not paint.
Parameters: changed - true if the layout must flush its caches, and false otherwise Throws: SWTException - ERROR_WIDGET_DISPOSED - if the receiver has been disposed ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
So in your case, calling the layout()
function on the parent of your composites anytime they are added should help you out.
回答3:
As you've said our both questions are similar, I'm posting the solution what I've achieved. Let me know if this helps you.
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Combo;
public class DynamicDialog extends Dialog {
private Composite composite_2;
/**
* Create the dialog.
* @param parentShell
*/
public DynamicDialog(Shell parentShell) {
super(parentShell);
}
/**
* Create contents of the dialog.
* @param parent
*/
@Override
protected Control createDialogArea(Composite parent) {
Composite container = (Composite) super.createDialogArea(parent);
container.setLayout(new FillLayout(SWT.HORIZONTAL));
ScrolledComposite scrolledComposite = new ScrolledComposite(container, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
scrolledComposite.setExpandHorizontal(true);
scrolledComposite.setExpandVertical(true);
final Composite composite = new Composite(scrolledComposite, SWT.NONE);
composite.setLayout(new GridLayout(1, false));
scrolledComposite.setContent(composite);
scrolledComposite.setSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
Composite composite_1 = new Composite(composite, SWT.NONE);
composite_1.setLayout(new GridLayout(2, false));
GridData gd_composite_1 = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
gd_composite_1.heightHint = 49;
gd_composite_1.widthHint = 427;
composite_1.setLayoutData(gd_composite_1);
Label lblDefault = new Label(composite_1, SWT.NONE);
lblDefault.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
lblDefault.setText("Default:");
Combo combo = new Combo(composite_1, SWT.NONE);
combo.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
composite_2 = new Composite(composite, SWT.NONE);
composite_2.setLayout(new GridLayout(4, false));
GridData gd_composite_2 = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
/*gd_composite_2.heightHint = 32;
gd_composite_2.widthHint = 426;*/
composite_2.setLayoutData(gd_composite_2);
Composite composite_3 = new Composite(composite, SWT.NONE);
composite_3.setLayout(new GridLayout(1, false));
GridData gd_composite_3 = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
gd_composite_3.heightHint = 38;
gd_composite_3.widthHint = 427;
composite_3.setLayoutData(gd_composite_3);
Button btnAdd = new Button(composite_3, SWT.NONE);
btnAdd.setText("Add");
btnAdd.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
Label label2 = new Label(composite_2, SWT.NONE);
label2.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false,
false, 1, 1));
label2.setText("1");
Text text_12 = new Text(composite_2, SWT.BORDER);
text_12.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
false, 1, 1));
Text text13 = new Text(composite_2, SWT.BORDER);
text13.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
false, 1, 1));
Button btnDelete = new Button(composite_2, SWT.NONE);
btnDelete.setText("delete");
composite_2.layout(true);
composite_2.layout();
// Point p = composite.getSize();
// composite.setSize(SWT.DEFAULT,SWT.DEFAULT);
// composite.setSize(p);
composite.layout();
}
});
return container;
}
/**
* Create contents of the button bar.
* @param parent
*/
@Override
protected void createButtonsForButtonBar(Composite parent) {
createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL,
true);
createButton(parent, IDialogConstants.CANCEL_ID,
IDialogConstants.CANCEL_LABEL, false);
}
/**
* Return the initial size of the dialog.
*/
@Override
protected Point getInitialSize() {
return new Point(450, 300);
}
public static void main(String[] args){
Shell shell = new Shell(new Display());
//shell.setLayout(new FillLayout());
DynamicDialog dd = new DynamicDialog(shell);
dd.open();
}
}
来源:https://stackoverflow.com/questions/20204381/swt-shell-resize-depending-on-children