SWT Shell随子项大小调整大小

5
我正在处理这个“Composite”画布,其他的“Composite”可以被添加和移除。
我对整个布局概念的理解还不够清晰。
当子级被添加到容器中时,考虑到容器有一个填充父级的“GridData”,难道父级也不知道子级已经调整大小了吗?子级在其容器布局完成后仍然隐藏,因为有一个shell(顶级父级)。
如果问题不太清楚,请随时要求更多细节。同时,请尽量不要指向“了解SWT中的布局”文章。
/**
 * 
 * @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++) );
    }
}
有趣的事实: 这个问题非常相关,与另一个问题非常相似,该问题是9分钟前发布的。有人要么是通灵,要么是在跟踪我。
3个回答

14

要让 Shell 调整大小,您需要布局所有内容并重新计算其大小:

shell.layout(true, true);

final Point newSize = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);  

shell.setSize(newSize);

根据更改的内容,您可能可以通过调用 shell 的子组合对象上的 layout() 方法来实现。


你的解决方案似乎适用于更复杂的示例。我想知道在我的情况下是否必须使用 shell.setSize(Point)(它基本上是 pack(true))。在我完成整个实现后,我会回来告诉你们的。 - Georgian
pack(true) 执行的与我上面两行代码相同的操作。从中提取出来的代码还检查了最小大小,这是 pack 无法完成的。 - greg-449
@greg-449对于JFace的下拉框也是一样的吗?我在这里提了一个问题链接 - Saras Arya
@SarasArya 这仅适用于 Shell。每个控件的大小取决于您使用的布局。 - greg-449
shell.pack(true) 解决了我的问题,当我添加/删除子元素时自动更改对话框大小。谢谢。 - WineYe
pack(true) 允许我的对话框变得比显示器更大,因此我使用了 @greg-449 的代码,并将 newSize 与 shell.getDisplay().getPrimaryMonitor().getClientArea().width 和 height 进行了比较。 - Danny

3

解决问题的关键在于告诉父容器子元素已经被重新调整大小,因此不会自动知道发生的变化。

修复此问题的方法是调用以下代码:

Parent.layout(true)

该代码来自SWT API。

public void layout(boolean changed)

如果接收器拥有一个布局,则要求该布局对接收器的子项进行布局(即设置其大小和位置)。如果参数为true,则布局不能依赖于它缓存的有关立即子项的任何信息。如果为false,则布局可能会(潜在地)通过假设接收器的所有子项自上次布局以来均未改变状态来优化其工作。如果接收器没有布局,则不执行任何操作。
如果由于调用布局而使子项调整大小,则重新调整大小事件将调用子项的布局。布局将级联到接收器小部件树中的所有子小部件中,直到遇到一个不调整大小的子项为止。请注意,由于调整大小而引起的布局不会刷新任何缓存的信息(与布局(false)相同)。
注意:布局不同于绘画。如果移动或调整子项以暴露父项中的某个区域,则父项将进行绘画。如果没有子项受到影响,则父项不会绘画。
参数: changed - 如果布局必须刷新其缓存,则为true;否则为false 抛出: SWTException - ERROR_WIDGET_DISPOSED - 如果接收器已被处理 ERROR_THREAD_INVALID_ACCESS - 如果不是从创建接收器的线程调用
因此,在您的情况下,每次添加复合控件时在其父级上调用layout()函数应该有所帮助。

在另外一个案例中,我尝试在Shell上调用layout。当时似乎没有起作用。这也适用于DialogWizard吗?你需要向上调用API到多高的层次? - Georgian
我有一份我之前写的代码副本,做着完全相同的事情,等我下班回家后,我会打开它,看看有什么不同。我记得有一些微妙的地方需要调整,直到它能够正常工作。其中一个就是每次创建新的组合时确实需要调用 layout(true),但我会在几个小时内与您联系!除非我有灵感和记忆,那么会更快。 - WillBD
好的,重新阅读了你的问题和底部提到的那个问题后,我可能在这里把自己搞糊涂了。主要问题是你根本看不到新的动态按钮吗?还是说当你制作太多按钮后整个外壳无法调整大小? - WillBD
主要问题是容器布局良好,但外壳不行。无论我添加什么新的子元素,例如我编写带标签的复合组件来证明一点。我只想将外壳/向导/对话框打包,以便我可以看到所有组件的美观布局。 - Georgian
我问这些问题的原因是因为我希望我的组件容器(包括ADD按钮)成为一个独立的小部件,可以插入到其他地方。而那些地方需要符合这个小部件的大小和需求。 - Georgian
显示剩余2条评论

0

正如你所说,我们两个的问题很相似,我在这里发布了我所得到的解决方案。如果这对你有帮助,请告诉我。

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();

}
}

显然这解决了你的问题,但并没有解决我的。问题在于,当你添加太多时,它们往往会超出屏幕范围,而你无法手动调整对话框大小以查看它们。对话框应该自动调整大小 -> 参见其他两个答案。 :-) - Georgian
@GGrec 是的,完全正确。现在我的问题是,每当我在组合中创建新的小部件时,当它达到默认大小的末尾时,它会下降到对话框中,而滚动条不会出现。你知道如何解决这个问题吗?因为我没有完全理解上面的解决方案。谢谢。 - Juseeth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接