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

Java Swing正弦曲线缩放异常及坐标轴不居中问题求助

Java Swing正弦曲线程序问题修复

存在的问题

  • 鼠标滚轮缩小(zoom out)时,正弦曲线无法延续显示;但拉长窗口时左侧曲线能正常延伸
  • 坐标轴未随缩放保持居中

原问题代码

SineWave JPanel代码

package SineWave;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.Line2D;

import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class SineWave extends JPanel implements MouseWheelListener {
    private double scale = 1.0;

    public SineWave() {
        addMouseWheelListener(this);
        
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setColor(Color.BLACK);
        double xScale = getWidth() / 2 * scale;
        double yScale = getHeight() / 2 * scale;
        g2.draw(new Line2D.Double(0, getHeight() / 2 * scale, getWidth(), getHeight() / 2 * scale));
        g2.draw(new Line2D.Double(getWidth() / 2 * scale, 0, getWidth() / 2 * scale, getHeight()));
        g2.setColor(Color.BLUE);
        double x, y, oldx = 0, oldy = getHeight() / 2;
        for (x = 0; x <= getWidth(); x += 0.1) {
            y = getHeight() / 2 - Math.sin((x - getWidth() / 2) / 100) * 100;
            g2.draw(new Line2D.Double(oldx * scale, oldy * scale, x * scale, y * scale));
            oldx = x;
            oldy = y;
        }
    }

    public void mouseWheelMoved(MouseWheelEvent e) {
        if (e.getWheelRotation() < 0) {
            scale *= 1.1;
        } else {
            scale /= 1.1;
        }
        repaint();
    }
}

MyFrame JFrame代码

package SineWave;

import javax.swing.JFrame;

public class MyFrame extends JFrame{
    MyFrame(){
        this.setSize(500, 500);
        SineWave wave = new SineWave();
        this.add(wave);
        this.setVisible(true);
    }

}

问题根源

  1. 坐标轴绘制错误:原代码将坐标轴位置与缩放因子scale绑定,导致缩放时坐标轴偏离窗口中心。
  2. 曲线绘制范围不足:仅绘制了屏幕可见宽度内的x值,缩小(scale<1)时,无法覆盖超出原屏幕宽度的曲线部分,导致曲线不延续。
  3. 坐标转换逻辑混乱:直接对屏幕坐标乘以缩放因子,而非基于数学坐标系进行转换,导致缩放时曲线位置和范围异常。

修复后的代码

修正后的SineWave类

package SineWave;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.Line2D;

import javax.swing.JPanel;

public class SineWave extends JPanel implements MouseWheelListener {
    private double scale = 1.0;
    // 控制曲线疏密,值越大曲线越稀疏
    private final double PIXELS_PER_UNIT = 100.0;

    public SineWave() {
        addMouseWheelListener(this);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        int centerX = getWidth() / 2;
        int centerY = getHeight() / 2;

        // 绘制居中坐标轴
        g2.setColor(Color.BLACK);
        g2.draw(new Line2D.Double(0, centerY, getWidth(), centerY)); // X轴
        g2.draw(new Line2D.Double(centerX, 0, centerX, getHeight())); // Y轴

        g2.setColor(Color.BLUE);
        // 计算需要绘制的数学x范围:覆盖窗口左右外侧,确保缩放时显示完整曲线
        double startX = -centerX / (PIXELS_PER_UNIT * scale);
        double endX = (getWidth() - centerX) / (PIXELS_PER_UNIT * scale);
        double step = 0.01; // 步长越小曲线越平滑

        // 初始化起始点屏幕坐标
        double oldScreenX = centerX + startX * PIXELS_PER_UNIT * scale;
        double oldScreenY = centerY - Math.sin(startX) * PIXELS_PER_UNIT * scale;

        // 遍历数学x值,转换为屏幕坐标绘制曲线
        for (double x = startX + step; x <= endX; x += step) {
            double screenX = centerX + x * PIXELS_PER_UNIT * scale;
            double screenY = centerY - Math.sin(x) * PIXELS_PER_UNIT * scale;
            g2.draw(new Line2D.Double(oldScreenX, oldScreenY, screenX, screenY));
            oldScreenX = screenX;
            oldScreenY = screenY;
        }
    }

    @Override
    public void mouseWheelMoved(MouseWheelEvent e) {
        if (e.getWheelRotation() < 0) {
            scale *= 1.1;
        } else {
            scale /= 1.1;
        }
        repaint();
    }
}

优化后的MyFrame类

package SineWave;

import javax.swing.JFrame;

public class MyFrame extends JFrame{
    MyFrame(){
        this.setSize(500, 500);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 关闭窗口时退出程序
        SineWave wave = new SineWave();
        this.add(wave);
        this.setVisible(true);
    }

    public static void main(String[] args) {
        new MyFrame();
    }
}

修复说明

  • 坐标轴居中:直接使用窗口中心坐标绘制坐标轴,与缩放因子无关,确保始终居中显示。
  • 曲线范围扩展:计算数学坐标系下的x范围,覆盖窗口左右外侧区域,缩小(scale<1)时能显示更多曲线周期,解决曲线不延续问题。
  • 规范坐标转换:基于数学坐标系计算曲线点,再转换为屏幕坐标,缩放逻辑更清晰,曲线显示更准确。
  • 平滑度调整:使用更小的步长0.01提升曲线平滑度,可根据需求调整PIXELS_PER_UNIT改变曲线疏密。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 22:54:52