Java SWT虚拟表格全选后滚动显示异常问题排查
SWT虚拟表格全选后滚动显示异常问题
我开发的Java SWT应用包含虚拟表格,用户搜索关键词后表格展示匹配的文档列表。点击首列表头可全选该列复选框,但全选后滚动表格时,仅全选操作时可见的项正常显示,其他项显示为空;不过点击空白区域仍能显示文档详情。调试发现调用table.redraw()未实现预期的全表重绘效果。
问题根源
SWT虚拟表格(SWT.VIRTUAL)的核心机制是按需加载行数据:只有可见行才会被初始化,滚动时会复用TableItem并触发SWT.SetData事件重新填充数据。当前代码存在两个关键问题:
toggleSelection方法仅修改了当前已初始化的TableItem(即可见行)的复选框状态,未初始化的行(不可见)在滚动触发SWT.SetData时,会调用Column.getImage(element)重新获取图片,而该方法未考虑全选状态,导致显示默认的未选中状态。- 全选状态仅在UI层面修改
TableItem,未与数据模型绑定,导致数据和UI状态不一致。
解决方案
需要将全选状态与数据模型关联,并在SWT.SetData事件中根据全选状态和单个项的选中状态渲染复选框,同时触发全表重新初始化而非仅重绘。
修改后的关键代码
1. 重写toggleSelection方法,更新数据模型并触发全表重新初始化
private void toggleSelection() { Display.getDefault().asyncExec(() -> { // 清除所有已初始化的行,滚动时会重新触发SWT.SetData事件 table.clearAll(); }); // 更新选中集合,保证数据模型与UI状态一致 ResultPanel.selDocument.clear(); if (isAllSelected) { // 全选时添加所有文档 ResultPanel.selDocument.addAll((List<ResultDocument>) (List<?>) elements); } }
2. 修改SWT.SetData事件处理逻辑,根据状态渲染复选框
table.addListener(SWT.SetData, new Listener() { public void handleEvent(org.eclipse.swt.widgets.Event event) { if (event.index < 0 || event.index >= elements.size()) return; Util.checkThat(!columns.isEmpty()); TableItem item = (TableItem) event.item; E element = elements.get(event.index); for (int iCol = 0; iCol < columns.size(); iCol++) { Column<E> column = columns.get(iCol); item.setText(iCol, column.getLabel(element)); // 首列复选框渲染逻辑:优先判断全选状态,再判断单个项是否选中 if (iCol == 0) { if (isAllSelected) { item.setImage(iCol, Img.CHECKBOX_CHECKED.get()); } else { boolean isSelected = ResultPanel.selDocument.contains(element); item.setImage(iCol, isSelected ? Img.CHECKBOX_CHECKED.get() : Img.CHECKBOX_UNCHECKED.get()); } } else { item.setImage(iCol, column.getImage(element)); } item.setForeground(iCol, column.getForeground(element)); item.setBackground(iCol, column.getBackground(element)); } item.setData(element); } });
3. 优化表头点击事件,简化全选状态切换逻辑
tableColumn.addListener(SWT.Selection, event -> { isAllSelected = !isAllSelected; tableColumn.setImage(isAllSelected ? Img.CHECKBOX_CHECKED.get() : Img.CHECKBOX_UNCHECKED.get()); toggleSelection(); });
关键说明
table.clearAll()会清除所有已初始化的TableItem,滚动时会重新触发SWT.SetData事件,确保所有行都使用最新的全选状态渲染;- 将选中状态与
ResultPanel.selDocument集合绑定,保证UI展示和数据模型的一致性; - 首列复选框优先判断全局全选标记,再判断单个项的选中状态,避免状态冲突。
内容的提问来源于stack exchange,提问作者Sanjay
相关产品推荐
相关产品推荐

