三角函数绘图程序运行异常及空指针错误排查求助
三角函数绘图程序空白窗口与空指针异常修复
问题说明
使用Apache NetBeans开发的三角函数绘图程序,编译通过但启动后显示空白窗口,交互操作触发空指针异常。程序目标是实现8种三角函数(sin、cos、tan、ctan、arcsin、arccos、arctan、arcctan)的绘图,支持调整振幅与X轴相位偏移,点击按钮生成对应图形。
程序代码
package test; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; public class javaP extends JFrame { public static void main(String[] args) { SwingUtilities.invokeLater(() -> createAndShowGUI()); } private static void createAndShowGUI() { JFrame frame = new JFrame("TrigGraphsApp"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 函数选择面板 JPanel functionPanel = new JPanel(); JLabel functionLabel = new JLabel("函数:"); String[] functions = { "sin", "cos", "tg", "ctg", "arcsin", "arccos", "arctg", "arcctg" }; JComboBox<String> functionComboBox = new JComboBox<>(functions); functionPanel.add(functionLabel); functionPanel.add(functionComboBox); // 参数设置面板 JPanel parameterPanel = new JPanel(); JLabel amplitudeLabel = new JLabel("振幅:"); JTextField amplitudeTextField = new JTextField("1", 10); // 默认值1 JLabel phaseShiftLabel = new JLabel("相位偏移:"); JTextField phaseShiftTextField = new JTextField("0", 10); // 默认值0 parameterPanel.add(amplitudeLabel); parameterPanel.add(amplitudeTextField); parameterPanel.add(phaseShiftLabel); parameterPanel.add(phaseShiftTextField); // 绘图按钮 JButton drawButton = new JButton("绘图"); drawButton.addActionListener(e -> { String selectedFunction = (String) functionComboBox.getSelectedItem(); double amplitude; double phaseShift; // 参数输入校验 try { amplitude = Double.parseDouble(amplitudeTextField.getText()); phaseShift = Double.parseDouble(phaseShiftTextField.getText()); } catch (NumberFormatException ex) { JOptionPane.showMessageDialog(frame, "请输入有效的数字参数", "输入错误", JOptionPane.ERROR_MESSAGE); return; } // 创建绘图面板 GraphPanel graphPanel = new GraphPanel(selectedFunction, amplitude, phaseShift); graphPanel.setPreferredSize(new Dimension(600, 400)); // 显示绘图窗口 JFrame graphFrame = new JFrame(selectedFunction + " 曲线图"); graphFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); graphFrame.getContentPane().add(graphPanel); graphFrame.pack(); graphFrame.setLocationRelativeTo(null); graphFrame.setVisible(true); }); // 主面板布局 JPanel mainPanel = new JPanel(new BorderLayout()); mainPanel.add(functionPanel, BorderLayout.NORTH); mainPanel.add(parameterPanel, BorderLayout.CENTER); mainPanel.add(drawButton, BorderLayout.SOUTH); frame.getContentPane().add(mainPanel); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } } class GraphPanel extends JPanel { private String function; private double amplitude; private double phaseShift; public GraphPanel(String function, double amplitude, double phaseShift) { // 确保函数名不为null this.function = function != null ? function : "sin"; this.amplitude = amplitude == 0 ? 1 : amplitude; // 避免振幅为0 this.phaseShift = phaseShift; } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); int width = getWidth(); int height = getHeight(); // 绘制坐标轴 g2d.setColor(Color.LIGHT_GRAY); g2d.setStroke(new BasicStroke(1)); // X轴 g2d.drawLine(0, height/2, width, height/2); // Y轴 g2d.drawLine(width/2, 0, width/2, height); // 绘制函数曲线 g2d.setColor(Color.BLUE); g2d.setStroke(new BasicStroke(2)); double xScale = width / (4 * Math.PI); // 扩展X轴范围,显示更多周期 double yScale = height / (2 * amplitude); double xOffset = width / 2; double yOffset = height / 2; double step = 0.01; List<Point> points = new ArrayList<>(); for (double x = -2 * Math.PI; x < 2 * Math.PI; x += step) { double y = 0; boolean validPoint = true; try { switch (function) { case "sin": y = amplitude * Math.sin(x - phaseShift); break; case "cos": y = amplitude * Math.cos(x - phaseShift); break; case "tg": double tanVal = Math.tan(x - phaseShift); // 过滤tan的无穷大值(接近π/2奇数倍时) if (Math.abs(tanVal) > 1000) validPoint = false; else y = amplitude * tanVal; break; case "ctg": double tanCtgVal = Math.tan(x - phaseShift); // 过滤ctg的无穷大值(接近π整数倍时) if (Math.abs(tanCtgVal) < 0.001 || Math.abs(tanCtgVal) > 1000) validPoint = false; else y = amplitude / tanCtgVal; break; case "arcsin": double asinX = x - phaseShift; if (asinX < -1 || asinX > 1) validPoint = false; else y = amplitude * Math.asin(asinX); break; case "arccos": double acosX = x - phaseShift; if (acosX < -1 || acosX > 1) validPoint = false; else y = amplitude * Math.acos(acosX); break; case "arctg": y = amplitude * Math.atan(x - phaseShift); break; case "arcctg": y = amplitude * (Math.PI / 2 - Math.atan(x - phaseShift)); break; } } catch (Exception ex) { validPoint = false; } if (validPoint) { int xPixel = (int) (x * xScale + xOffset); int yPixel = (int) (-y * yScale + yOffset); // 确保点在面板范围内 if (xPixel >=0 && xPixel < width && yPixel >=0 && yPixel < height) { points.add(new Point(xPixel, yPixel)); } } } // 绘制折线 for (int i = 1; i < points.size(); i++) { Point p1 = points.get(i-1); Point p2 = points.get(i); g2d.drawLine(p1.x, p1.y, p2.x, p2.y); } } }
错误栈信息
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException: Cannot invoke "String.equals(Object)" because "this.wybranaFunkcja" is null at dawca.App.drawFunkcjaPlot(App.java:122) at dawca.App$5.paintComponent(App.java:78) at java.desktop/javax.swing.JComponent.paint(JComponent.java:1074) ...(后续栈信息省略)
修复要点
- 空指针异常修复:在
GraphPanel构造函数中添加函数名非空校验,避免null值传入后触发字符串比较异常。 - 输入参数校验:为振幅和相位偏移添加数字格式校验,防止非法输入导致程序崩溃。
- 空白窗口解决:添加坐标轴绘制,让窗口不再空白;优化绘图方式为折线绘制,提升视觉效果。
- 函数定义域处理:针对tan、ctan的无穷大值,arcsin、arccos的输入范围限制进行过滤,避免绘图异常。
- 除零问题规避:当振幅为0时自动设置为1,防止
yScale计算时出现除零错误。
内容的提问来源于stack exchange,提问作者Piotr Wykowski wyku
相关产品推荐
相关产品推荐

