You need to enable JavaScript to run this app. 如何通过LabelProvider为SWT TreeViewer添加行按钮并解决重复显示问题
优惠活动
大模型
产品
解决方案
定价
更多

如何通过LabelProvider为SWT TreeViewer添加行按钮并解决重复显示问题

问题根因

  • ColumnLabelProvider的update方法会在单元格每次重绘(列拉伸、滚动、节点展开/收起、内容刷新)时被多次调用,当前代码每次调用都新建Button和TreeEditor实例,旧实例没有被销毁,就会出现残留的冗余按钮,也就是你看到的右侧悬浮的异常按钮。
  • TableViewer和TreeViewer的重绘逻辑存在差异,所以Table上可用的方案直接搬到Tree上会出现适配问题。

修正后的代码实现

修改SelectVariableButtonLabelProvider类即可解决问题:

public class SelectVariableButtonLabelProvider extends ColumnLabelProvider {
    // 自定义存取key,用来缓存单元格对应的控件实例,方便后续销毁
    private static final String KEY_BUTTON = "SELECT_VARIABLE_BUTTON";
    private static final String KEY_EDITOR = "SELECT_VARIABLE_EDITOR";

    private TreeViewer viewer;
    // 这里对应你传入的getAllVariables()返回值,类型根据实际业务调整
    private List<Variable> allVariables;

    public SelectVariableButtonLabelProvider(TreeViewer viewer, List<Variable> allVariables) {
        this.viewer = viewer;
        this.allVariables = allVariables;
        // 列拉伸时刷新,清理残留控件
        viewer.getTree().addControlListener(new ControlAdapter() {
            @Override
            public void controlResized(ControlEvent e) {
                viewer.refresh();
            }
        });
        // 节点展开/收起时刷新,避免按钮错位
        viewer.addTreeListener(new TreeListener() {
            @Override
            public void treeExpanded(TreeEvent e) {
                viewer.refresh();
            }

            @Override
            public void treeCollapsed(TreeEvent e) {
                viewer.refresh();
            }
        });
    }

    @Override
    public void update(ViewerCell cell) {
        TreeItem item = (TreeItem) cell.getItem();
        int columnIndex = cell.getColumnIndex();
        // 先销毁当前单元格之前的旧按钮、旧编辑器
        Object oldBtn = item.getData(KEY_BUTTON + columnIndex);
        if (oldBtn instanceof Button) {
            ((Button) oldBtn).dispose();
        }
        Object oldEditor = item.getData(KEY_EDITOR + columnIndex);
        if (oldEditor instanceof TreeEditor) {
            ((TreeEditor) oldEditor).dispose();
        }

        // 替换为你自己的行按钮显示判断条件
        if (isNeedShowButton(cell.getElement())) {
            addButton(cell);
        }
    }

    private void addButton(ViewerCell cell) {
        TreeItem item = (TreeItem) cell.getItem();
        int columnIndex = cell.getColumnIndex();
        Tree tree = item.getParent();

        // 父控件直接用Tree即可,不需要取row的control
        Button btn = new Button(tree, SWT.NONE);
        btn.setText(" select variable ");
        // 绑定点击事件
        btn.addListener(SWT.Selection, new SelectVariableButtonListener(tree,
                DataTypeTreeUtils.getTreeNodeDataTypeInstance(cell.getElement()), viewer));

        TreeEditor editor = new TreeEditor(tree);
        editor.grabHorizontal = true;
        editor.grabVertical = true;
        // 动态计算按钮尺寸,适配不同字体、系统缩放场景
        editor.minimumWidth = btn.computeSize(SWT.DEFAULT, SWT.DEFAULT).x;
        editor.setEditor(btn, item, columnIndex);

        // 把当前按钮和编辑器存到TreeItem的data中,后续重绘时可以找到销毁
        item.setData(KEY_BUTTON + columnIndex, btn);
        item.setData(KEY_EDITOR + columnIndex, editor);
    }
}

额外优化建议

如果你的Tree数据量很大,全量viewer.refresh()会有性能问题,可以调整为只刷新可视区域的单元格,或者给Tree添加滚动监听,滚动时主动清理可视区域外的控件即可。

内容的提问来源于stack exchange,提问作者rosemerel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.14 00:12:03