【问题标题】:How to initial check elements in a CheckboxTreeviewer如何在 CheckboxTreeviewer 中初始化检查元素
【发布时间】:2013-11-10 16:18:39
【问题描述】:

我在我的 GMF 编辑器中使用带有 CheckboxTreeViewer 的自定义对话框,到目前为止效果很好,如下所示:

关闭Dialog后,被选中的元素保存至今。现在我的问题:

当我再次打开对话框时,所有元素都未选中。所以我认为告诉 treeViewer 最初应该检查特定元素会很容易。

但事实证明这并不容易,因为树最初由根元素组成。在树展开之前不会添加其他元素。通过调用 ContentProvider 的 getChildren(Object parentElement) 添加元素。

所以看起来我最初无法检查特定元素,而是必须提供一种动态方法。我正在寻找类似元素添加侦听器的东西,但似乎不存在。

这是我创建 CheckboxTreeViewer 的部分

Composite container = (Composite) super.createDialogArea(parent);
        tv = new CheckboxTreeViewer(container, SWT.MULTI | SWT.H_SCROLL
                | SWT.V_SCROLL);
        tv.getTree().setLayoutData(new GridData(GridData.FILL_BOTH));
        tv.setAutoExpandLevel(2);
        tv.setContentProvider(new FeaturePropertyDialogContentProvider(this));
        tv.setLabelProvider(new FeaturePropertyDialogLabelProvider());
        tv.setInput(productLine);
        tv.setExpandPreCheckFilters(true);
        return container;

这是我的 ContentProvider 的 getChildren 方法:

@Override
    public Object[] getChildren(Object parentElement) {
        if (parentElement instanceof PL) {
            PL p = (PL) parentElement;
            return new Object[] { p.getPropertyList() };
        }
        else if (parentElement instanceof PropertyList) {
            PropertyList propertyList = (PropertyList) parentElement;
            return propertyList.getGeneralPlatforms().toArray();
        } else if (parentElement instanceof GeneralPlatform) {
            GeneralPlatform platform = (GeneralPlatform) parentElement;
            return platform.getHardwareElements().toArray();
        } 
        } else {
            return null;
        }
    }

对此有什么想法吗?

--------解决方案----------

我自己找到了以下解决方案,到目前为止对我来说效果很好:

tv.expandAll();
tv.setCheckedElements(preSelectedProperties.toArray());
tv.collapseAll();
tv.expandToLevel(2);

【问题讨论】:

  • 解决方法:展开树 -> 选择项目 -> 折叠树。全部以编程方式完成。
  • 但是怎么做呢?当用户打开树时,我不知道在哪里挂钩。它必须在树第一次构建时发生。之后,用户可以选择/取消选择什么。我在上面附加了一些代码以使其更清晰。不过还是谢谢

标签: java checkbox treeview swt jface


【解决方案1】:

您应该在树查看器上添加一个侦听器,以便在节点展开时获得通知(TreeViewer 上的方法 addTreeListener())。此时节点已经在树中,可以勾选复选框。

这是一个树的 sn-p,它设置树展开时的检查状态:

public class Snippet {

public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setLayout(new FillLayout());

    final Map<String, Boolean> userChecks = new HashMap<>();

    final CheckboxTreeViewer tv = new CheckboxTreeViewer(shell, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
    GridData gridData = new GridData(GridData.FILL_BOTH);
    tv.getTree().setLayoutData(gridData);
    final FeaturePropertyDialogContentProvider provider = new FeaturePropertyDialogContentProvider(tv);
    tv.setContentProvider(provider);
    tv.setInput("root");
    tv.addCheckStateListener(new ICheckStateListener() {
        @Override
        public void checkStateChanged(CheckStateChangedEvent event) {
            userChecks.put((String) event.getElement(), event.getChecked());
        }
    });
    tv.addTreeListener(new ITreeViewerListener() {
        @Override
        public void treeCollapsed(TreeExpansionEvent event) {
        }

        @Override
        public void treeExpanded(TreeExpansionEvent event) {
            final Object element = event.getElement();
            final Object[] children = provider.getChildren(element);
            for (Object child : children) {
                if (userChecks.containsKey(child)) {
                    tv.setChecked(child, userChecks.get(child));
                } else if (child.equals("b")) {
                    tv.setChecked(child, true);
                }
            }
        }
    });

    shell.setSize(200, 200);
    shell.open();
    while (!shell.isDisposed()) {
        if (!display.readAndDispatch()) {
            display.sleep();
        }
    }
    display.dispose();
}

private static class FeaturePropertyDialogContentProvider implements ITreeContentProvider {

    final CheckboxTreeViewer tv;

    private FeaturePropertyDialogContentProvider(CheckboxTreeViewer tv) {
        this.tv = tv;
    }

    @Override
    public Object[] getElements(Object inputElement) {
        return this.getChildren(inputElement);
    }

    @Override
    public Object[] getChildren(Object parentElement) {
        switch ((String) parentElement) {
            case "root":
                return new String[]{"1"};
            case "1":
                return new String[]{"a", "b", "c"};
            default:
                return new String[0];
        }
    }

    @Override
    public Object getParent(Object element) {
        return null;
    }

    @Override
    public boolean hasChildren(Object element) {
        return this.getChildren(element).length > 0;
    }

    @Override
    public void dispose() {
    }

    @Override
    public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
    }
}
}

在本例中,我只将节点值与字符串“b”进行比较。


编辑:在这种情况下,元素是不可变的(由于某种原因它们无法更改),并且不接受将对象包装在树节点中的解决方案(请参阅 cmets)。

在这种情况下,您可以将用户检查操作保存在地图中,并在设置检查/未检查状态时,搜索任何以前的用户检查操作。我认为假设地图很简单并且不会增长太多是合理的。用户必须检查很多节点才能使其变大:)

我更新了 sn-p 以跟踪用户检查。

【讨论】:

  • 感谢您的评论。我已经考虑过这个解决方案。这里的问题是你不能再取消选择这个节点了。当用户展开树时,节点会被检查,到目前为止还不错。现在他想取消选择它,这也可以。但是当用户出于某种原因再次展开树时(树还没有关闭),节点将再次检查。这里的一个解决方法是另外检查它是否扩展了第一个(例如使用布尔值),但我想注意这个解决方案。
  • @ph09 为什么不在用户更改检查选择时更新模型。然后,当树再次展开时,您将从模型中读取正确的选中值和未选中值。它不适用于我的 sn-p,因为我有不可变的字符串作为值。如果你不能更新数据模型,你总是可以创建一个树节点类来存储原始值加上选中-未选中状态。
  • 我无法更新模型,因为这是由底层框架完成的,我对此没有足够的了解。额外的树节点对于大型树来说过于复杂且效率低下。我想知道为什么没有简单的解决方案,特别是因为向用户提供了像 setCheckedElements(Object[] elements) 这样的方法,但最初不起作用。
  • @ph09 查看我的更新,以响应修复跟踪用户选中/取消选中操作。
  • 感谢您的努力,但我想我找到了一个更简单的解决方案..请参阅我的问题的更新。不过还是谢谢你!!
猜你喜欢
  • 2012-11-23
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
  • 2017-06-07
  • 2019-09-18
  • 1970-01-01
  • 2021-08-26
  • 2014-05-25
相关资源
最近更新 更多