java JFrame给了我java.lang.NullPointerException,我无法弄清楚原因

时间:2014-10-19 17:49:30

标签: java swing nullpointerexception

在你将这篇文章标记为重复和referance What is a NullPointerException, and how do I fix it?之前,我已经阅读过了(我还是java的新手并且可能无法理解这一点)似乎无法看到它是如何连接到我的错误。

我正在尝试处理一个java swing JFrame并在其中加载另一个并使其工作。尽管它正是我想要的,它仍然给我java.lang.NullPointerException错误。据我所知,错误所连接的代码正在按照我的意愿运行。

这是我的相关代码。如果您需要我包含我认为没有必要的任何其他代码,请告诉我,我将进行编辑。

修改

我删除了以前的所有代码,并为您添加了mcve代码。

package test;

public final class Test {

    private static GUI1 gui1;
    private static GUI2 gui2;

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

    public static void startGUI1() {
        gui1 = new GUI1();
    }

    public static GUI1 getGUI1() {
        return gui1;
    }

    public static void startGUI2() {
        gui2 = new GUI2();
    }

    public static GUI2 getGUI2() {
        return gui2;
    }
}

包裹测试;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class GUI1 {

    JFrame frame;

    public GUI1() {
        frame = new JFrame();

        frame.setVisible(true);
        frame.setSize(500, 500);
        frame.setLocationRelativeTo(null);
        frame.add(new Pane());
    }

    public class Pane extends JComponent {

        public Pane() {
            try {
                Scanner read = new Scanner(new File("user.txt"));

                if (read.nextInt() != 0) {
                    test.Test.startGUI2();
                    test.Test.getGUI1().frame.dispose();
                }
            } catch (FileNotFoundException ex) {
                Logger.getLogger(GUI1.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}

包裹测试;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class GUI2 {

    JFrame frame;

    public GUI2() {
        frame = new JFrame();

        frame.setVisible(true);
        frame.setSize(500, 500);
        frame.setLocationRelativeTo(null);
        frame.add(new Pane());
    }

    public class Pane extends JComponent {

        JLabel label = new JLabel("GUI2");
        JButton button = new JButton("Start Gui1");

        public Pane() {
        }

        @Override
        protected void paintComponent(Graphics g) {
            Graphics2D g2d = (Graphics2D) g;

            g2d.setColor(new Color(5, 5, 5));
            g2d.fillRect(0, 0, getWidth(), getHeight());

            g2d.setStroke(new BasicStroke(5.0F));
        }
    }
}

这会产生相同的错误

1 个答案:

答案 0 :(得分:3)

不,您的问题不是JFrame为null,而是您的Test.gui1变量为null。我在你的代码中添加了一行来测试它:

  public Pane() {
     try {
        Scanner read = new Scanner(new File("user.txt"));

        if (read.nextInt() != 0) {
           Test.startGUI2();

           // ********** two lines below added ******
           System.out.println("gui1 null? " + (Test.getGUI1() == null));
           System.out.println("frame null? " + (frame == null));

           Test.getGUI1().frame.dispose();
        }
     } catch (FileNotFoundException ex) {
        Logger.getLogger(GUI1.class.getName()).log(Level.SEVERE, null, ex);
     }

这将返回:

gui1 null? true
frame null? false

你试图在构造函数完成之前调用gui1 GUI1对象上的方法,这是一件危险的事情。

但同样,最终解决方案可能会有所不同,并取决于您要实现的目标。如果您的目标是交换视图,那么我与Andrew Thompson一起 - 您应该使用CardLayout切换JPanel视图。


测试我是对的另一种方法是看看如果我们在GUI1构造函数中调用你的帧交换代码会发生什么,而不是通过使用SwingUtilities.invokeLater(Runnable)在Swing事件线程上对它进行排队来延迟它。在下面的代码中,尝试使用CREATE_ERROR布尔值的不同值运行它。

换句话说,用

运行一次
public static final boolean CREATE_ERROR = true; 

然后再次使用

运行它
public static final boolean CREATE_ERROR = false; 

看看会发生什么

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class TestA {
   private static GUI1A gui1;
   private static GUI2A gui2;

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

   public static void startGUI1() {
      gui1 = new GUI1A();
   }

   public static GUI1A getGUI1() {
      return gui1;
   }

   public static void startGUI2() {
      gui2 = new GUI2A();
   }

   public static GUI2A getGUI2() {
      return gui2;
   }
}

class GUI1A {
   public static final boolean CREATE_ERROR = true; 
   private JFrame frame1 = new JFrame("Frame 1");

   public GUI1A() {
      frame1.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame1.add(new JLabel("This is Frame 1"));
      frame1.pack();
      frame1.setLocationByPlatform(true);
      frame1.setVisible(true);

      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            if (!CREATE_ERROR) {
               swapFrames();
            }
         }
      });
      if (CREATE_ERROR) {
         swapFrames();
      }
   }

   private void swapFrames() {
      TestA.startGUI2();

      System.out.println("GUI1 is null: " + (TestA.getGUI1() == null));
      System.out.println("frame1 is null: " + (frame1 == null));

      TestA.getGUI1().getFrame().dispose();
   }

   public JFrame getFrame() {
      return frame1;
   }
}

class GUI2A {
   private JFrame frame2 = new JFrame("Frame 2");

   public GUI2A() {
      frame2.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame2.add(new JLabel("This is Frame 2"));
      frame2.pack();
      frame2.setLocationByPlatform(true);
      frame2.setVisible(true);
   }
}

作为旁注,我很少如果曾经那样交换JFrame(不要以为我曾经想过它),尽管我已经显示了单独的对话框窗口。另外,我会小心翼翼地读取EDT的所有文件。例如,为了获取代码,我将使用SwingWorker:

private class ButtonAction extends AbstractAction {
  public ButtonAction(String name) {
     super(name);
  }

  @Override
  public void actionPerformed(ActionEvent e) {
     final MyWorker myWorker = new MyWorker();
     myWorker.addPropertyChangeListener(new PropertyChangeListener() {

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
           if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
              try {
                 int result = myWorker.get().intValue();
                 if (result != 0) {
                    TestB.startGUI2();
                    System.out.println("gui1 null? " + (TestB.getGUI1() == null));
                    System.out.println("frame null? " + (frame == null));

                    TestB.getGUI1().frame.dispose();
                 }                     
              } catch (InterruptedException | ExecutionException e) {
                 e.printStackTrace();
              }
           }
        }
     });
     myWorker.execute();
  }
}

private class MyWorker extends SwingWorker<Integer, Void> {
  @Override
  protected Integer doInBackground() throws Exception {
     int result = 0;
     Scanner read = null;
     try {
        read = new Scanner(new File(USER_FILE_PATH));
        result = read.nextInt();
     } catch (FileNotFoundException ex) {
        Logger.getLogger(GUI1B.class.getName()).log(Level.SEVERE, null, ex);
     } finally {
        if (read != null) {
           read.close();
        }
     }
     return result;
  }
}

gui1在关键时刻为空的具体原因是因为在GUI1构造函数完成之前,对象gui1 = new GUI1();的赋值不会发生。