如何通过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
相关产品推荐
相关产品推荐

