StackLayout中的SWT Text Widgets——切换顶部控件时无法调整高度

SWT Text Widgets in StackLayout—Can't adjust height when switching top control

我在 JFace 对话框中有一个 SWT 组合。在复合材料的一行上,我有一个 Group,其中有 4 个垂直堆叠的按钮。旁边是一个文本小部件,需要根据用户输入在多行和单行之间来回切换。

我在 StackLayout 中有两个不同的文本小部件,我会根据需要显示一个或另一个。但是我找不到一种方法来根据哪个文本是顶部控件来调整 Stack Composite 和 Text 小部件的高度。我在单一模式下只需要一个行高,而在多模式下填充与其旁边的组相同的垂直space。我可以在创建 Composite 时将文本的高度调整到这些条件中的任何一个,但是当我告诉他们从一个文本切换到另一个文本后它们不会调整高度。

这是一个代码片段,它导致文本小部件总是太高,并且在单一模式下永远不会缩小到一个行高的大小。

这是复合

        @Override
        protected Control createDialogArea(Composite parent) {
            container = (Composite) super.createDialogArea(parent);
            GridDataFactory.fillDefaults().grab(true, true).applyTo(container);
            GridLayoutFactory.fillDefaults().numColumns(2).margins(5, 5).applyTo(container);

            Group group = new Group(container, SWT.NONE);
            GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true,  true).applyTo(group);
            GridLayoutFactory.fillDefaults().applyTo(group);        
            for (M_ATTRIBUTE attr : M_ATTRIBUTE.values()) {
                Button button = new Button(group, SWT.CHECK);
                GridDataFactory.fillDefaults().applyTo(button);
                button.setText(attr.getDisplayValue());
            }

            stack = new Composite(container, SWT.NONE);
            GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(stack);
            stackLayout = new StackLayout();
            stack.setLayout(stackLayout);
            valueTextMulti = new Text(stack, SWT.BORDER | SWT.MULTI);
            GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(valueTextMulti);
            valueTextMulti.addModifyListener(valueTextModifyListener);

            valueTextSingle = new Text(stack, SWT.BORDER | SWT.SINGLE);
            GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(valueTextSingle);
            valueTextSingle.addModifyListener(valueTextModifyListener);

            stackLayout.topControl = valueTextMulti;

            return container;
        }

这是一个 switch 语句,显示了我在单行和多行文本小部件之间切换的操作。

        @Override
        public void selectionChanged(SelectionChangedEvent event) {
                IStructuredSelection sel = (IStructuredSelection) event.getSelection();
                M_DATA_TYPE type = (M_DATA_TYPE) sel.getFirstElement();
                switch (type) {
                case LIST:
                case HASH_TABLE:
                    stackLayout.topControl = valueTextMulti;
                    setNumRows(valueTextMulti, 10);
                    ((GridData) valueTextMulti.getLayoutData()).verticalAlignment = SWT.FILL;
                    ((GridData) valueTextMulti.getLayoutData()).grabExcessVerticalSpace = true;
                    ((GridData) stack.getLayoutData()).grabExcessVerticalSpace = true;
                    container.getParent().layout();
                    break;
                default:
                    stackLayout.topControl = valueTextSingle;
                    ((GridData) valueTextSingle.getLayoutData()).verticalAlignment = SWT.TOP;
                    ((GridData) valueTextSingle.getLayoutData()).grabExcessVerticalSpace = false;
                    ((GridData) stack.getLayoutData()).grabExcessVerticalSpace = false;
                    setNumRows(valueTextSingle, 1);
                    container.getParent().layout();
                    break;
                }
            }

这是根据字符行调整文本高度的方法,我从 another Whosebug post.

获得
protected void setNumRows(Text text, int rows) {
            GC gc = new GC(text);
            try
            {
                gc.setFont(text.getFont());
                FontMetrics fm = gc.getFontMetrics();

                int height = rows * fm.getHeight();
                text.setSize(text.getSize().x, height);
                text.getParent().layout();
            }
            finally
            {
                gc.dispose();
            }
        }

我通过在 StackLayout 组合中创建额外的组合来实现它,每个 Text 小部件实例一个。每个 Text 小部件都有固定的布局数据,一个是 align = SWT.FILL,另一个是 SWT.TOP。然后我只是在 StackLayout 中切换容器组合,而不是切换文本小部件。这具有不需要直接设置小部件高度的额外优势。还必须在切换内容后在 StackLayout 组合上调用 layout()。在层次结构中更高层的容器上调用 layout() 无效。

这是我修改后的代码:

@Override
protected Control createDialogArea(Composite parent) {
    container = (Composite) super.createDialogArea(parent);
    GridDataFactory.fillDefaults().grab(true, true).applyTo(container);
    GridLayoutFactory.fillDefaults().numColumns(2).margins(5, 5).applyTo(container);

    Group group = new Group(container, SWT.NONE);
    GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true,  false).applyTo(group);
    GridLayoutFactory.fillDefaults().applyTo(group);        
    for (M_ATTRIBUTE attr : M_ATTRIBUTE.values()) {
        Button button = new Button(group, SWT.CHECK);
        GridDataFactory.fillDefaults().applyTo(button);
        button.setText(attr.getDisplayValue());
        this.buttons.put(attr, button);
    }
    stack = new Composite(container, SWT.NONE);
    GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(stack);
    stackLayout = new StackLayout();
    stack.setLayout(stackLayout);               
    compMultiLine = new Composite(stack, SWT.NONE);
    GridDataFactory.fillDefaults().applyTo(compMultiLine);
    GridLayoutFactory.fillDefaults().applyTo(compMultiLine);
    valueTextMulti = new Text(compMultiLine, SWT.BORDER | SWT.MULTI |SWT.WRAP);
    GridDataFactory.fillDefaults().grab(true, true).applyTo(valueTextMulti);
    valueTextMulti.addModifyListener(valueTextModifyListener);              
    compSingleLine = new Composite(stack, SWT.NONE);
    GridDataFactory.fillDefaults().applyTo(compSingleLine);
    GridLayoutFactory.fillDefaults().applyTo(compSingleLine);
    valueTextSingle = new Text(compSingleLine, SWT.BORDER | SWT.SINGLE | SWT.WRAP);
    GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(valueTextSingle);
    valueTextSingle.addModifyListener(valueTextModifyListener);         
    stackLayout.topControl = compMultiLine;
    return container;
}


@Override
public void selectionChanged(SelectionChangedEvent event) {
    IStructuredSelection sel = (IStructuredSelection) event.getSelection();
    M_DATA_TYPE type = (M_DATA_TYPE) sel.getFirstElement();
    switch (type) {
    case LIST:
    case HASH_TABLE:
        stackLayout.topControl = compMultiLine;
        stack.layout();
        break;
    default:
        stackLayout.topControl = compSingleLine;
        stack.layout();
        break;
    }
}