You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何对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轴
    }
}

关键修改说明:

  1. 直接传入完整数据集,统一处理缩放逻辑,避免预先绘制未缩放的线条
  2. 计算数据的极值和范围,确定Y轴的缩放比例
  3. 根据数据点数量和组件可用宽度,计算X轴的缩放比例
  4. 反转Y轴方向,适配Swing的坐标体系与常规图表的视觉习惯
  5. 添加固定边距,避免折线紧贴组件边缘
  6. 可选绘制坐标轴,让图表结构更清晰

内容的提问来源于stack exchange,提问作者Bhupesh Patil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 23:50:28