
简介SWTChart是一款基于SWT的Java图表类库面向需要在Eclipse RCP或SWT桌面应用中嵌入数据可视化的Java开发者尤其适合追求轻量、无需额外依赖的图表绘制场景。它支持线图、散点图、堆栈图、柱形图、面积图、步骤图、对数标度、分类轴、多轴、轴取向与系列标签等多种图表类型可满足常规统计与工程数据展示需求。资源包共36个文件约287KB以24个java源码文件为核心另含2个jar包、2个project与classpath配置、2个html说明文档及gif图标、properties、mf、xml等辅助文件目录中同时提供org.swtchart主库与examples示例工程便于直接导入Eclipse运行调试。目前已有640人学习下载。通过阅读源码与示例读者可掌握SWTChart的图表构建流程、坐标轴与系列配置方式并借鉴其扩展接口实现自定义图表适合作为学习SWT绘图或集成轻量图表组件的参考素材。1. 桌面端图表选型为什么我最终把 JFreeChart 换成了 SWTChart做过 Eclipse RCP 或者纯 SWT 桌面应用的人大概都有过这个纠结界面已经用 SWT 搭好了到了要画折线、柱状、饼图的时候第一反应往往是上 JFreeChart。JFreeChart 确实成熟文档多但它是基于 AWT/Swing 的塞进 SWT 容器里要么用SWT_AWT.new_Frame桥接要么干脆另开一个 Swing 窗口。桥接方案在 Windows 上勉强能跑到了 Linux GTK 或者 macOS 上轻则闪烁重绘异常重则直接崩给你看这种玄学问题排查起来非常折磨。SWTChart 就是冲着这个痛点来的。它是一个纯 SWT 实现的图表类库不依赖 AWT/Swing直接继承Canvas用 GC 绘制所以能无缝嵌进任何 SWT Composite 里跟你的 RCP 视图、对话框、编辑器融为一体。它支持折线图、散点图、柱状图、面积图、饼图、气泡图这些常见类型坐标轴、图例、网格线、标注、缩放、导出图片都有对应 API。适合谁正在做 Eclipse 插件、桌面监控工具、工业上位机、测试数据可视化这类 SWT 技术栈的开发者。如果你用的是 JavaFX 或者 Web 前端那这篇可以直接划走了。2. 把 SWTChart 跑起来依赖、坐标轴与数据系列2.1 依赖引入与最小可运行骨架SWTChart 的坐标是org.eclipse.swtchartMaven Central 上有发布。我一般直接在pom.xml里引版本按你项目实际用的 SWT 版本对齐别乱跳大版本。dependency groupIdorg.eclipse.swtchart/groupId artifactIdorg.eclipse.swtchart/artifactId version0.14.0/version /dependency如果你不用 Maven那就去项目发布页下 jar 包手动加到 classpath。注意它依赖 SWT而 SWT 是跟平台绑定的Windows、Linux、macOS 的 jar 不一样别拿错。最小骨架长这样import org.eclipse.swt.SWT; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.swtchart.Chart; import org.eclipse.swtchart.ILineSeries; import org.eclipse.swtchart.LineStyle; public class MinimalChart { public static void main(String[] args) { Display display new Display(); Shell shell new Shell(display); shell.setText(SWTChart Demo); shell.setSize(600, 400); shell.setLayout(new FillLayout()); // 创建图表风格用 FLAT避免 3D 效果干扰读数 Chart chart new Chart(shell, SWT.NONE); // 设置 X/Y 轴标题 chart.getAxisSet().getXAxis(0).getTitle().setText(采样点); chart.getAxisSet().getYAxis(0).getTitle().setText(电压 (mV)); // 创建一条折线系列 ILineSeries series (ILineSeries) chart.getSeriesSet() .createSeries(ILineSeries.class); series.setYSeries(new double[]{12, 35, 28, 47, 52, 41, 60}); series.setLineStyle(LineStyle.SOLID); series.setLineWidth(2); // 自动调整坐标轴范围 chart.getAxisSet().adjustRange(); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose(); } }逻辑说明Chart构造时传入父容器和样式它本身是个Canvas子类所以FillLayout能直接管它。createSeries用接口类型做参数返回对应实现这是 SWTChart 的一个设计特点——你声明什么接口它就给你什么类型的系列。adjustRange()会根据数据自动算坐标轴上下限省得手动设。参数说明setLineWidth(2)单位是像素太细在高分屏上会糊。LineStyle.SOLID还有DASH、DOT、DASHDOT可选。setYSeries传的是double[]X 轴默认按索引 0、1、2… 排如果你要自定义 X 值得用setXSeries。2.2 多系列、坐标轴与图例配置实际项目里很少只有一条线。多系列叠加时图例和颜色区分就很重要。// 第二条系列用虚线区分 ILineSeries series2 (ILineSeries) chart.getSeriesSet() .createSeries(ILineSeries.class); series2.setYSeries(new double[]{8, 22, 30, 38, 44, 50, 55}); series2.setLineStyle(LineStyle.DASH); series2.setLineWidth(2); series2.setDescription(参考通道); // 图例文字 // 第一条也补上图例文字 series.setDescription(实测通道); // 图例位置右下角 chart.getLegend().setPosition(SWT.BOTTOM); // 网格线 chart.getAxisSet().getXAxis(0).getGrid().setForeground( display.getSystemColor(SWT.COLOR_GRAY)); chart.getAxisSet().getYAxis(0).getGrid().setVisible(true);逻辑说明setDescription是图例显示的文字不设的话图例里就是空白。setPosition接受 SWT 的方位常量SWT.BOTTOM、SWT.TOP、SWT.LEFT、SWT.RIGHT都行。网格线默认是开的但颜色可能跟背景撞手动设一下更稳。参数说明getAxisSet().getXAxis(0)里的 0 是轴索引多轴场景下会用到 1、2。SWTChart 支持多 Y 轴比如左边一个量纲、右边一个量纲做法是getYAxis(1)然后给系列setYAxisId(1)。这个功能在双通道对比时很实用但要注意两个轴的范围得分别adjustRange不然会互相干扰。2.3 数据动态更新与重绘监控类场景数据是实时来的不能每次重建 Chart。正确做法是持有 series 引用更新数据后调update()。// 假设在某个定时器或事件回调里 double[] newData fetchLatestSamples(); // 你的取数逻辑 series.setYSeries(newData); chart.getAxisSet().adjustRange(); // 数据范围变了才需要 chart.redraw(); // 触发重绘逻辑说明setYSeries会替换整个数组不是追加。如果你要做滚动窗口得自己维护一个固定长度的数组每次移一位再塞新值。redraw()是必须的SWT 不会自动感知数据变化。参数说明频繁调adjustRange()会导致坐标轴跳动视觉上很难受。我一般只在数据首次加载或范围明显越界时才调平时固定范围。如果数据量很大比如上万点setYSeries每次全量替换会有性能压力常见做法是降采样或者只画窗口内的点。3. 避坑与排查SWTChart 实际项目里的五个翻车点3.1 现象图表一片空白什么都不显示原因最常见的是Chart创建后没有触发adjustRange()坐标轴范围是 0 到 0数据全在可视区外。其次是父容器布局没设Chart尺寸为 0。解决先确认shell.setLayout(new FillLayout())或者 GridLayout 给了 Chart 合理的GridData。然后检查是否调了adjustRange()。如果还不行在shell.open()之后手动chart.redraw()一次。3.2 现象Linux 下字体发虚、中文显示成方块原因SWTChart 默认用系统字体Linux 某些发行版缺中文字体或者 GC 的字体渲染跟 Windows 不一致。解决手动给轴标题和图例设字体。Font font new Font(display, Noto Sans CJK SC, 10, SWT.NORMAL); chart.getAxisSet().getXAxis(0).getTitle().setFont(font); chart.getLegend().setFont(font);注意Font用完要dispose()否则会泄漏 GDI 资源。我一般把字体对象挂在 Shell 的dispose监听里统一释放。3.3 现象数据点超过几千个后界面卡顿原因SWTChart 默认每个点都画GC 绘制开销随点数线性增长加上redraw()全量重绘卡是必然的。解决两条路。一是降采样比如每 10 个点取一个二是用ISeries的setVisible(false)把不需要的系列关掉。如果必须全画考虑用ScatterSeries替代LineSeries散点绘制比连线略快。另外别在 UI 线程里做大数据量的setYSeries放到后台线程算好再display.asyncExec回 UI 更新。3.4 现象导出图片是黑的或者尺寸不对原因SWTChart 导出用chart.saveAsBitmap或自己拿 GC 画到Image如果没指定背景色透明区域在某些查看器里显示为黑。解决chart.setBackground(display.getSystemColor(SWT.COLOR_WHITE)); chart.saveAsBitmap(/path/to/output.png, SWT.IMAGE_PNG, 800, 600);宽高参数是像素不传的话用当前控件尺寸。导出前确保chart.redraw()过否则可能拿到旧画面。3.5 现象多 Y 轴时数据画到了错误的轴上原因创建系列后忘了setYAxisId默认全挂在 0 号轴上。解决先chart.getAxisSet().createYAxis()拿到新轴再给对应系列series.setYAxisId(newAxis.getId())。顺序不能反轴 ID 是创建时分配的。这个坑我在一个双通道采集项目里踩过两条曲线叠在一起排查了半天才发现是轴 ID 没设。4. 进阶技巧自定义绘制与交互联动4.1 用 PaintListener 叠加自定义标注SWTChart 本身提供了series.setLabel做数据点标注但样式有限。如果要画阈值线、区域高亮、十字准星这类东西直接给 Chart 加PaintListener更灵活。chart.addPaintListener(e - { // 在 Y50 处画一条红色阈值线 Point origin chart.getPlotArea().getBounds().x 0 ? new Point(chart.getPlotArea().getBounds().x, 0) : new Point(0, 0); Rectangle plot chart.getPlotArea().getBounds(); int y plot.y plot.height - (int) ((50 - chart.getAxisSet().getYAxis(0).getRange().lower) / (chart.getAxisSet().getYAxis(0).getRange().upper - chart.getAxisSet().getYAxis(0).getRange().lower) * plot.height); e.gc.setForeground(display.getSystemColor(SWT.COLOR_RED)); e.gc.setLineStyle(SWT.LINE_DASH); e.gc.drawLine(plot.x, y, plot.x plot.width, y); });逻辑说明getPlotArea().getBounds()拿到绘图区矩形然后把数据值 50 按当前 Y 轴范围映射成像素坐标。PaintListener在 Chart 自身绘制完成后触发所以你的线会叠在图表上面。参数说明getRange().lower和upper是当前轴范围如果调了adjustRange它们会变所以这段映射逻辑得放在监听器里实时算不能缓存。阈值线的位置随缩放变化是符合预期的。4.2 鼠标交互获取点击位置对应的数据值做数据回放或者点选查询时需要把鼠标坐标反算成数据值。chart.addMouseListener(new MouseAdapter() { Override public void mouseDown(MouseEvent e) { Rectangle plot chart.getPlotArea().getBounds(); if (!plot.contains(e.x, e.y)) return; double xRatio (double) (e.x - plot.x) / plot.width; double yRatio (double) (plot.y plot.height - e.y) / plot.height; double xVal chart.getAxisSet().getXAxis(0).getRange().lower xRatio * (chart.getAxisSet().getXAxis(0).getRange().upper - chart.getAxisSet().getXAxis(0).getRange().lower); double yVal chart.getAxisSet().getYAxis(0).getRange().lower yRatio * (chart.getAxisSet().getYAxis(0).getRange().upper - chart.getAxisSet().getYAxis(0).getRange().lower); System.out.printf(点击数据坐标: (%.2f, %.2f)%n, xVal, yVal); } });逻辑说明X 方向是线性的直接按比例映射。Y 方向要注意屏幕坐标向下增长而数据坐标向上增长所以用plot.y plot.height - e.y翻转一下。参数说明plot.contains判断点击是否落在绘图区内避免点到轴标签也触发。这个反算假设轴是线性的如果用了对数轴得换成对数映射SWTChart 的LogAxis有对应的转换方法。4.3 一个我常用的验证习惯每次改完图表配置我不会只看界面而是先跑一遍导出把 PNG 存下来用图片查看器放大看细节。因为屏幕上有些问题比如线宽 1 像素的锯齿、图例文字被截断、网格线跟数据线颜色太近在运行时窗口里不明显导出成固定尺寸的图之后一眼就能看出来。这个习惯帮我提前发现过好几次图例遮挡数据、轴标签重叠的问题。从那以后我每次调完 SWTChart 的样式参数都强制走一遍「导出 800x600 PNG → 放大检查 → 再调」的流程比在窗口里反复拖拽靠谱得多。希望帮到你。本文还有配套的精品资源点击获取