如何基于单元格文本对SWT Table(搭配JFace TableViewer)排序?
基于JFace TableViewer单元格文本的通用排序方案
当然有可行方案!你想要的这种基于单元格显示文本而非模型属性的通用排序思路完全可以实现,核心就是自定义一个ViewerComparator,在比较时通过列的LabelProvider获取单元格的显示文本,再对文本进行比较。这样不管你的模型是什么结构,只要LabelProvider能正确返回单元格文本,就能复用这个比较器,不用为每个属性单独写逻辑。
实现步骤与代码示例
1. 自定义通用的单元格文本比较器
这个比较器会根据当前排序的列,获取对应列的LabelProvider,拿到两个元素的单元格文本后进行比较,同时处理排序方向:
import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.swt.SWT; public class CellTextViewerComparator extends ViewerComparator { private int columnIndex = 0; // 设置当前排序的列索引,并切换排序方向 public void setColumnIndex(int columnIndex) { this.columnIndex = columnIndex; setDirection(getDirection() == SWT.UP ? SWT.DOWN : SWT.UP); } @Override public int compare(Viewer viewer, Object e1, Object e2) { TableViewer tableViewer = (TableViewer) viewer; // 获取当前排序列的TableViewerColumn TableViewerColumn targetColumn = tableViewer.getTableViewerColumns().get(columnIndex); ILabelProvider labelProvider = (ILabelProvider) targetColumn.getLabelProvider(); // 通过LabelProvider获取单元格显示的文本 String text1 = labelProvider.getText(e1); String text2 = labelProvider.getText(e2); // 先处理空文本的情况,避免空指针 if (text1 == null) text1 = ""; if (text2 == null) text2 = ""; // 基础的忽略大小写字符串比较 int comparison = text1.compareToIgnoreCase(text2); // 根据排序方向调整结果(升序返回原比较值,降序取反) return getDirection() == SWT.UP ? comparison : -comparison; } }
2. 给TableViewer绑定比较器并配置列排序监听
接下来在初始化TableViewer的时候,把这个通用比较器设置进去,同时给每个列添加点击事件,触发排序逻辑:
import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.widgets.Composite; // 示例模型类 class Employee { private String name; private int age; private String department; // 构造器、getter方法 public Employee(String name, int age, String department) { this.name = name; this.age = age; this.department = department; } public String getName() { return name; } public int getAge() { return age; } public String getDepartment() { return department; } } // 初始化TableViewer的代码 public void createTable(Composite parent) { TableViewer viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION); viewer.setContentProvider(ArrayContentProvider.getInstance()); // 实例化并设置通用比较器 CellTextViewerComparator comparator = new CellTextViewerComparator(); viewer.setComparator(comparator); // 创建表格列并配置 String[] columnTitles = {"姓名", "年龄", "部门"}; for (int i = 0; i < columnTitles.length; i++) { final int columnIdx = i; TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE); column.getColumn().setText(columnTitles[i]); column.getColumn().setWidth(150); // 设置列的LabelProvider(根据你的模型自定义) column.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object element) { Employee emp = (Employee) element; switch (columnIdx) { case 0: return emp.getName(); case 1: return String.valueOf(emp.getAge()); // 数字转字符串,保证显示和排序文本一致 case 2: return emp.getDepartment(); default: return ""; } } }); // 添加列头点击事件,触发排序 column.getColumn().addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { comparator.setColumnIndex(columnIdx); viewer.refresh(); // 刷新表格触发排序 } }); } // 设置示例数据 viewer.setInput(new Employee[]{ new Employee("张三", 28, "技术部"), new Employee("李四", 22, "市场部"), new Employee("王五", 35, "技术部") }); }
额外优化点
- 数字/日期类型文本排序:如果列显示的是数字(比如示例中的年龄),直接字符串排序会出现"100"<"20"的问题。你可以在
compare方法里加个判断,尝试把文本转为数字/日期,再按数值/时间比较:// 在compare方法中替换原比较逻辑 int comparison; try { // 尝试按整数比较 Integer num1 = Integer.parseInt(text1); Integer num2 = Integer.parseInt(text2); comparison = num1.compareTo(num2); } catch (NumberFormatException ex) { // 不是数字,按字符串比较 comparison = text1.compareToIgnoreCase(text2); } - 空文本处理:代码里已经加了空文本的默认值,避免
NullPointerException,如果需要把空文本放在最前或最后,可以调整比较逻辑。 - 自定义排序规则:如果某列需要特殊排序(比如中文拼音排序),可以在
compare方法里针对特定列索引做单独处理,不影响其他列的通用逻辑。
内容的提问来源于stack exchange,提问作者Lii
相关产品推荐
相关产品推荐

