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

三角函数绘图程序运行异常及空指针错误排查求助

三角函数绘图程序空白窗口与空指针异常修复

问题说明

使用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)
    ...(后续栈信息省略)

修复要点

  1. 空指针异常修复:在GraphPanel构造函数中添加函数名非空校验,避免null值传入后触发字符串比较异常。
  2. 输入参数校验:为振幅和相位偏移添加数字格式校验,防止非法输入导致程序崩溃。
  3. 空白窗口解决:添加坐标轴绘制,让窗口不再空白;优化绘图方式为折线绘制,提升视觉效果。
  4. 函数定义域处理:针对tan、ctan的无穷大值,arcsin、arccos的输入范围限制进行过滤,避免绘图异常。
  5. 除零问题规避:当振幅为0时自动设置为1,防止yScale计算时出现除零错误。

内容的提问来源于stack exchange,提问作者Piotr Wykowski wyku

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 10:27:00