NatTable自定义Cell Painter实现Choice Chips单元格渲染
在NatTable中自定义Cell Painter渲染Choice Chips
要在DisplayMode.NORMAL模式下渲染Choice Chips,你需要实现一个继承自AbstractCellPainter的自定义绘制器,通过SWT的GC(图形上下文)手动绘制Chip样式。以下是完整的实现步骤和代码示例:
核心实现思路
NatTable的单元格绘制器通过paintCell方法完成内容渲染,核心逻辑分为三步:
- 读取单元格绑定的选项数据
- 计算Chip的布局位置和尺寸
- 用GC绘制Chip的背景、文本及样式
自定义ChoiceChipCellPainter代码
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; import org.eclipse.nebula.widgets.nattable.painter.cell.AbstractCellPainter; import org.eclipse.swt.graphics.*; import org.eclipse.swt.widgets.Display; import java.util.List; public class ChoiceChipCellPainter extends AbstractCellPainter { // 可自定义的Chip样式参数 private static final int CHIP_SPACING = 4; private static final int CHIP_PADDING_H = 8; private static final int CHIP_PADDING_V = 2; private static final int CHIP_BORDER_RADIUS = 12; private final Color chipBgColor = Display.getDefault().getSystemColor(SWT.COLOR_LINK_FOREGROUND); private final Color chipTextColor = Display.getDefault().getSystemColor(SWT.COLOR_WHITE); @Override public void paintCell(ILayerCell cell, GC gc, Rectangle bounds, IConfigRegistry configRegistry) { // 1. 获取单元格数据:假设数据为List<String>类型的选中选项集合 @SuppressWarnings("unchecked") List<String> selectedChoices = (List<String>) cell.getDataValue(); if (selectedChoices == null || selectedChoices.isEmpty()) { gc.drawText("无选择", bounds.x + 2, bounds.y + 2, true); return; } // 2. 初始化绘制环境(字体、起始坐标) gc.setFont(configRegistry.getConfigAttribute( CellConfigAttributes.CELL_FONT, DisplayMode.NORMAL, cell.getConfigLabels())); FontMetrics metrics = gc.getFontMetrics(); int currentX = bounds.x + CHIP_SPACING; int currentY = bounds.y + (bounds.height - metrics.getHeight()) / 2; // 3. 逐个绘制Choice Chip for (String choice : selectedChoices) { Point textSize = gc.textExtent(choice); int chipWidth = textSize.x + 2 * CHIP_PADDING_H; int chipHeight = textSize.y + 2 * CHIP_PADDING_V; // 超出单元格宽度时,绘制省略号并停止 if (currentX + chipWidth > bounds.x + bounds.width - CHIP_SPACING) { drawEllipsisChip(gc, currentX, currentY, metrics); break; } // 绘制Chip圆角背景 drawRoundedChipBg(gc, currentX, currentY - CHIP_PADDING_V, chipWidth, chipHeight); // 绘制Chip文本 gc.setForeground(chipTextColor); gc.drawText(choice, currentX + CHIP_PADDING_H, currentY - CHIP_PADDING_V, true); // 更新下一个Chip的起始X坐标 currentX += chipWidth + CHIP_SPACING; } } // 绘制圆角Chip背景 private void drawRoundedChipBg(GC gc, int x, int y, int width, int height) { gc.setBackground(chipBgColor); // 先绘制圆角路径并填充 Path path = new Path(Display.getDefault()); path.addRoundRectangle(x, y, width, height, CHIP_BORDER_RADIUS, CHIP_BORDER_RADIUS); gc.fillPath(path); path.dispose(); // 可选:绘制Chip边框 gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_GRAY)); gc.drawRoundRectangle(x, y, width, height, CHIP_BORDER_RADIUS, CHIP_BORDER_RADIUS); } // 绘制省略号Chip private void drawEllipsisChip(GC gc, int x, int y, FontMetrics metrics) { String ellipsis = "..."; Point textSize = gc.textExtent(ellipsis); int chipWidth = textSize.x + 2 * CHIP_PADDING_H; int chipHeight = metrics.getHeight() + 2 * CHIP_PADDING_V; drawRoundedChipBg(gc, x, y - CHIP_PADDING_V, chipWidth, chipHeight); gc.setForeground(chipTextColor); gc.drawText(ellipsis, x + CHIP_PADDING_H, y - CHIP_PADDING_V, true); } // 重写方法,让NatTable自动计算单元格宽度 @Override public int getPreferredWidth(ILayerCell cell, GC gc, IConfigRegistry configRegistry) { List<String> selectedChoices = (List<String>) cell.getDataValue(); if (selectedChoices == null || selectedChoices.isEmpty()) { return gc.textExtent("无选择").x + 4; } gc.setFont(configRegistry.getConfigAttribute(CellConfigAttributes.CELL_FONT, DisplayMode.NORMAL, cell.getConfigLabels())); int totalWidth = CHIP_SPACING; for (String choice : selectedChoices) { Point textSize = gc.textExtent(choice); totalWidth += textSize.x + 2 * CHIP_PADDING_H + CHIP_SPACING; } return totalWidth; } // 重写方法,让NatTable自动计算单元格高度 @Override public int getPreferredHeight(ILayerCell cell, GC gc, IConfigRegistry configRegistry) { gc.setFont(configRegistry.getConfigAttribute(CellConfigAttributes.CELL_FONT, DisplayMode.NORMAL, cell.getConfigLabels())); return gc.getFontMetrics().getHeight() + 2 * CHIP_PADDING_V; } }
注册自定义Painter到NatTable
将自定义绘制器绑定到目标列的NORMAL模式配置中:
// 假设你的列有自定义标签"CHOICE_COLUMN" configRegistry.registerConfigAttribute( CellConfigAttributes.CELL_PAINTER, new ChoiceChipCellPainter(), DisplayMode.NORMAL, "CHOICE_COLUMN");
关键注意事项
- 数据类型适配:如果你的单元格数据不是
List<String>,需要在paintCell中先提取Chip显示文本(比如自定义选项对象的getLabel()方法)。 - 样式可配置化:可以将颜色、间距等参数通过
IConfigRegistry注册,方便统一管理和修改。 - 交互扩展:如果需要Chip支持点击等交互,需给NatTable添加鼠标监听器,判断点击坐标是否在Chip区域内,再触发相应逻辑。
- 性能优化:如果单元格数量较多,建议缓存文本尺寸计算结果,避免重复计算。
内容的提问来源于stack exchange,提问作者Lăpădat Răzvan
相关产品推荐
相关产品推荐

