如何对Swing Graphics绘制的折线图进行缩放以正常显示?
如何为Java Swing折线图实现缩放适配
我用以下代码尝试创建折线图:
import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.geom.Line2D; import javax.swing.JOptionPane; import javax.swing.JComponent; import javax.swing.SwingUtilities; import java.util.ArrayList; import java.util.List; import java.util.Random; class NewG { public static void main(String[] args) { Runnable r = new Runnable() { public void run() { LineComponent lineComponent = new LineComponent(300,300); List<Integer> values = new ArrayList<>(); values.add(100); values.add(200); values.add(300); values.add(400); values.add(100); values.add(900); for (int i=0; i<values.size()-1; i++) { lineComponent.addLine(i+1, values.get(i), i+2, values.get(i+1)); } JOptionPane.showMessageDialog(null, lineComponent); } }; SwingUtilities.invokeLater(r); } } class LineComponent extends JComponent { ArrayList<Line2D.Double> lines; Random random; LineComponent(int width, int height) { super(); setPreferredSize(new Dimension(width,height)); lines = new ArrayList<Line2D.Double>(); random = new Random(); } public void addLine(int x1, int y1, int x2, int y2) { Line2D.Double line = new Line2D.Double(x1, y1, x2, y2); lines.add(line); repaint(); } public void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.white); g.fillRect(0, 0, getWidth(), getHeight()); Dimension d = getPreferredSize(); g.setColor(Color.black); for (Line2D.Double line : lines) { g.drawLine( (int)line.getX1(), (int)line.getY1(), (int)line.getX2(), (int)line.getY2() ); } } }
当前生成的图表没有做缩放处理,导致数据无法正常显示。我需要呈现的数据点是:
(1, 100); (2, 200); (3, 300); (4, 400); (5, 100); (6, 900);
现在我是直接连接相邻点绘制线条,但不知道怎么对图表做缩放适配,让数据能在组件范围内正常显示。
解决方案
核心思路是计算数据的范围,将原始数据坐标映射到组件的绘制区域坐标,同时处理Y轴方向反转(Swing中Y轴向下为正,图表通常Y轴向上为正),并添加边距避免折线贴边。
修改后的代码如下:
import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.util.ArrayList; import java.util.List; import java.util.OptionalInt; import javax.swing.JOptionPane; import javax.swing.JComponent; import javax.swing.SwingUtilities; class NewG { public static void main(String[] args) { Runnable r = () -> { List<Integer> values = new ArrayList<>(); values.add(100); values.add(200); values.add(300); values.add(400); values.add(100); values.add(900); // 传入数据集和组件尺寸 LineComponent lineComponent = new LineComponent(values, 300, 300); JOptionPane.showMessageDialog(null, lineComponent); }; SwingUtilities.invokeLater(r); } } class LineComponent extends JComponent { private List<Integer> data; private final int margin = 20; // 边距,提升视觉效果 LineComponent(List<Integer> data, int width, int height) { super(); this.data = data; setPreferredSize(new Dimension(width, height)); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); // 绘制白色背景 g.setColor(Color.WHITE); g.fillRect(0, 0, getWidth(), getHeight()); if (data == null || data.size() < 2) { return; } // 计算数据的最大值、最小值和范围 OptionalInt maxOpt = data.stream().mapToInt(Integer::intValue).max(); OptionalInt minOpt = data.stream().mapToInt(Integer::intValue).min(); if (!maxOpt.isPresent() || !minOpt.isPresent()) { return; } int dataMax = maxOpt.getAsInt(); int dataMin = minOpt.getAsInt(); int dataRange = dataMax - dataMin; int pointCount = data.size(); // 计算绘制区域的可用尺寸 int drawWidth = getWidth() - 2 * margin; int drawHeight = getHeight() - 2 * margin; // 计算缩放比例 double xScale = (double) drawWidth / (pointCount - 1); double yScale = dataRange == 0 ? 1 : (double) drawHeight / dataRange; // 绘制折线 g.setColor(Color.BLACK); for (int i = 0; i < pointCount - 1; i++) { // 映射X坐标:数据索引 -> 绘制区域X int x1 = margin + (int) (i * xScale); int x2 = margin + (int) ((i + 1) * xScale); // 映射Y坐标:数据值 -> 绘制区域Y,反转Y轴方向 int y1 = margin + drawHeight - (int) ((data.get(i) - dataMin) * yScale); int y2 = margin + drawHeight - (int) ((data.get(i + 1) - dataMin) * yScale); g.drawLine(x1, y1, x2, y2); } // 可选:绘制坐标轴 g.setColor(Color.GRAY); g.drawLine(margin, getHeight() - margin, getWidth() - margin, getHeight() - margin); // X轴 g.drawLine(margin, margin, margin, getHeight() - margin); // Y轴 } }
关键修改说明:
- 直接传入完整数据集,统一处理缩放逻辑,避免预先绘制未缩放的线条
- 计算数据的极值和范围,确定Y轴的缩放比例
- 根据数据点数量和组件可用宽度,计算X轴的缩放比例
- 反转Y轴方向,适配Swing的坐标体系与常规图表的视觉习惯
- 添加固定边距,避免折线紧贴组件边缘
- 可选绘制坐标轴,让图表结构更清晰
内容的提问来源于stack exchange,提问作者Bhupesh Patil
相关产品推荐
相关产品推荐

