WizardDialog 中的 StackLayout 以及具有固定高度和动态显示滚动条的可变多行文本

StackLayout in WizardDialog and varying multiline Text with fixed height and dynamically showed scrollbar

我正在开发一个向导,如果发生错误,它应该在控件顶部显示一个错误组合。该组合包含一个列出所有错误的 Text 和两个 Label:位于该组件上方和下方。错误列表下面的Label可以省略。根据错误的数量,错误列表的高度应该有所不同。但是它不应超过父组合的高度。如果错误不适合整个高度的 Text,则应显示滚动条。

这是我到目前为止所达到的最小化片段:

package de.dannylo.issues;


import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;


public class TestWizardPage
    extends WizardPage
{
    private static final String PLUGIN_ID = "de.dannylo.issues.TestPlugin";

    private Composite mainComposite;

    private Composite stackComposite;

    private StackLayout stackLayout;

    private Composite defaultMessageComposite;

    private Text idText;

    private static Wizard wizard;

    public TestWizardPage()
    {
        super("portalAppWizardMavenPage");
        setTitle("TestWizard");
        setDescription("Testing...");
    }


    @Override
    public void createControl(Composite parent)
    {
        mainComposite = new Composite(parent, SWT.NONE);
        GridLayout layout = new GridLayout();
        mainComposite.setLayout(layout);
        layout.numColumns = 1;
        layout.verticalSpacing = 15;

        // source folder
        Composite idComposite = new Composite(mainComposite, SWT.NONE);
        idComposite.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false));
        idComposite.setLayout(new GridLayout(2, false));
        Label label = new Label(idComposite, SWT.NONE);
        label.setText("ID:");
        idText = new Text(idComposite, SWT.BORDER | SWT.SINGLE);
        idText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

        label = new Label(mainComposite, SWT.SEPARATOR | SWT.HORIZONTAL);
        label.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false));

        stackComposite = new Composite(mainComposite, SWT.NONE);
        GridData layoutData = new GridData(SWT.FILL, SWT.NONE, true, false);
        layoutData.heightHint = 250; // For testing purposes in the real GUI
                                     // there are several components filling
                                     // this composite
        stackComposite.setLayoutData(layoutData);
        stackLayout = new StackLayout();
        stackComposite.setLayout(stackLayout);

        defaultMessageComposite = new Composite(stackComposite, SWT.NONE);
        defaultMessageComposite.setLayout(new GridLayout());
        stackLayout.topControl = defaultMessageComposite;

        label = new Label(defaultMessageComposite, SWT.NONE);
        label.setText("Enter \"1\", \"2\" or \"3\"  into the text field above.");

        idText.addModifyListener(new ModifyListener()
        {
            @Override
            public void modifyText(ModifyEvent e)
            {
                if ("1".equals(idText.getText()))
                    showErrorComposite("You entered id 1", "Nice job!", createTestStatusList(4));
                else if ("2".equals(idText.getText()))
                    showErrorComposite("You entered id 2", "Oops", createTestStatusList(20));
                else if ("3".equals(idText.getText()))
                    showErrorComposite("You entered id 3", null, createTestStatusList(20));
                else
                {
                    stackLayout.topControl = defaultMessageComposite;
                    stackComposite.layout();
                }
            }
        });

        setControl(mainComposite);
    }


    private static List<IStatus> createTestStatusList(int amount)
    {
        List<IStatus> toRet = new ArrayList<IStatus>();
        for (int i = 0; i < amount; i++)
        {
            toRet.add(new Status(IStatus.ERROR, PLUGIN_ID, "Error message " + i + ": " + toRet.hashCode()));
        }
        return toRet;
    }


    private void showErrorComposite(String topMessage, String bottomMessage, List<IStatus> statusList)
    {
        final Composite errorComposite = new Composite(stackComposite, SWT.BORDER);
        final GridLayout layout = new GridLayout();
        layout.verticalSpacing = 20;
        errorComposite.setLayout(layout);
        errorComposite.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false));

        final Label topLabel = new Label(errorComposite, SWT.WRAP | SWT.BORDER);
        topLabel.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false));
        topLabel.setText(topMessage);

        final Text errorList = new Text(errorComposite, SWT.MULTI | SWT.WRAP | SWT.READ_ONLY | SWT.V_SCROLL
                                                        | SWT.BORDER);
        final GridData gd_errorList = new GridData(SWT.FILL, SWT.NONE, true, false);
        gd_errorList.horizontalIndent = 20;
        errorList.setLayoutData(gd_errorList);

        for (int i = 0; i < statusList.size(); i++)
        {
            IStatus status = statusList.get(i);
            errorList.append("\u2022 " + status.getMessage());
            if (i != statusList.size() - 1)
                errorList.append("\n\n");
        }

        final Label bottomLabel;
        if (bottomMessage != null)
        {
            bottomLabel = new Label(errorComposite, SWT.WRAP | SWT.BORDER);
            bottomLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
            bottomLabel.setText(bottomMessage);
        }
        else
            bottomLabel = null;

        final Listener scrollBarListener = new Listener()
        {

            @Override
            public void handleEvent(Event event)
            {
                errorList.removeListener(SWT.Resize, this);
                int marginHeight = ((GridLayout)errorComposite.getLayout()).marginHeight;
                int stackCompositeHeight = stackComposite.getClientArea().height;
                int topLabelHeight = topLabel.getSize().y;
                int verticalSpacing = layout.verticalSpacing;
                int bottomLabelHeight = bottomLabel == null ? 0 : bottomLabel.getSize().y;
                int spaceAboveErrorList = marginHeight + topLabelHeight + verticalSpacing;
                int spaceBelowErrorList = bottomLabel == null ? marginHeight + 15 : verticalSpacing
                                                                                    + bottomLabelHeight
                                                                                    + marginHeight + 15;
                int hHint = stackCompositeHeight - spaceAboveErrorList - spaceBelowErrorList;

                Rectangle errorListClientArea = errorList.getClientArea();
                Point errorListSize = errorList.computeSize(errorListClientArea.x, SWT.DEFAULT, true);
                if (stackCompositeHeight < spaceAboveErrorList + errorListSize.y + spaceBelowErrorList)
                {
                    gd_errorList.heightHint = hHint;
                    errorList.getVerticalBar().setVisible(true);
                }
                else
                {
                    gd_errorList.heightHint = errorListSize.y;
                    errorList.getVerticalBar().setVisible(false);
                }

                errorComposite.layout();
                errorList.addListener(SWT.Resize, this);
            }
        };
        errorList.addListener(SWT.Resize, scrollBarListener);

        stackLayout.topControl = errorComposite;
        stackComposite.layout();
    }


    public static void main(String[] args)
    {
        Display.getDefault().syncExec(new Runnable()
        {

            @Override
            public void run()
            {
                wizard = new Wizard()
                {
                    @Override
                    public void addPages()
                    {
                        addPage(new TestWizardPage());
                    }


                    @Override
                    public boolean performFinish()
                    {
                        MessageDialog.openInformation(getShell(), "Bye!", "Thanks for testing!");
                        return true;
                    }
                };
            }
        });
        new WizardDialog(wizard.getShell(), wizard).open();
    }

}

我的 ID2 有问题。在这种情况下,Text 的高度最大,应该显示 bottomLabel。不幸的是,这个标签并没有像复合标签那样出现,而是仅在 window 的宽度发生变化后才出现。这似乎是布局的一些问题。我已经尝试使用 errorComposite.layout(true, true)(甚至 getShell().layout(true, true))来刷新缓存并重绘子项,但这没有帮助。关于如何解决该问题的任何想法?

我通过完全删除 scrollBarListener 并稍微修复一下布局解决了您的问题。

showErrorComposite(...) 方法现在看起来像这样:

private void showErrorComposite(String topMessage, String bottomMessage, List<IStatus> statusList)
{
    final Composite errorComposite = new Composite(stackComposite, SWT.BORDER);
    final GridLayout layout = new GridLayout();
    layout.verticalSpacing = 20;
    errorComposite.setLayout(layout);
    errorComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

    final Label topLabel = new Label(errorComposite, SWT.WRAP | SWT.BORDER);
    topLabel.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
    topLabel.setText(topMessage);

    final Text errorList = new Text(errorComposite, SWT.MULTI | SWT.WRAP | SWT.READ_ONLY | SWT.V_SCROLL
                                                    | SWT.BORDER);
    final GridData gd_errorList = new GridData(SWT.FILL, SWT.FILL, true, true);
    gd_errorList.horizontalIndent = 20;
    errorList.setLayoutData(gd_errorList);

    for (int i = 0; i < statusList.size(); i++)
    {
        IStatus status = statusList.get(i);
        errorList.append("\u2022 " + status.getMessage());
        if (i != statusList.size() - 1)
            errorList.append("\n\n");
    }

    errorList.setTopIndex(0);

    final Label bottomLabel;
    if (bottomMessage != null)
    {
        bottomLabel = new Label(errorComposite, SWT.WRAP | SWT.BORDER);
        bottomLabel.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false));
        bottomLabel.setText(bottomMessage);
    }
    else
        bottomLabel = null;

    stackLayout.topControl = errorComposite;
    stackComposite.layout();
}

现在看起来像这样:

更新

好的,在你的特定情况下,保持你的代码不变,只需在你的 showErrorComposite(...) 方法的末尾添加这一行:

scrollBarListener.handleEvent(null);