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); } }
问题根源
- 坐标轴绘制错误:原代码将坐标轴位置与缩放因子
scale绑定,导致缩放时坐标轴偏离窗口中心。 - 曲线绘制范围不足:仅绘制了屏幕可见宽度内的x值,缩小(scale<1)时,无法覆盖超出原屏幕宽度的曲线部分,导致曲线不延续。
- 坐标转换逻辑混乱:直接对屏幕坐标乘以缩放因子,而非基于数学坐标系进行转换,导致缩放时曲线位置和范围异常。
修复后的代码
修正后的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
相关产品推荐
相关产品推荐

