2015-08-25 20 views
0

我使用Swing製作了一個GUI,它有一些特性:使用Graphics2D,JInternalFrame,JDesktopFrame,AffineTransform的自定義圖形。我想我已經接近讓一切正常工作,但我得到空指針異常。我在這裏做錯了什麼?Swing GUI中的空指針異常

這裏是我的自包含例如:

import javax.swing.*; 
import java.awt.event.*; 
import java.awt.*; 
import java.awt.geom.AffineTransform; 
import java.awt.geom.Ellipse2D; 
import java.util.*; 

public class MainPanel extends JFrame implements ActionListener{ 

    private static final double version = 1.0; 
    private JDesktopPane desktop; 
    public static RFInternalFrame frame; 

    private java.util.List<Point> POINT_LIST = Arrays.asList(
      //Top Row 
      new Point(50, 30), 
      new Point(70, 30), 
      new Point(90, 30), 
      new Point(110, 30), 
      new Point(130, 30), 
      new Point(150, 30), 
      new Point(170, 30), 
      new Point(190, 30), 
      new Point(210, 30), 
      new Point(230, 30), 

      //Circle of Radios 
      new Point(140, 60), 
      new Point(120, 80), 
      new Point(100, 100), 
      new Point(100, 120), 
      new Point(120, 140), 
      new Point(140, 160), 
      new Point(160, 140), 
      new Point(180, 120), 
      new Point(180, 100), 
      new Point(160, 80)); 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       createAndShowGui(); 
      } 
     }); 
    } 

    private static void createAndShowGui() { 
     JFrame frame = new MainPanel(); 
     frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
     frame.setLocationByPlatform(false); 
     frame.setVisible(true); 
    } 

    public MainPanel() { 
     super("MainPanel " + version); 

     //Make the big window be indented 50 pixels from each edge 
     //of the screen. 
     int inset = 50; 
     Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 
     setBounds(inset, inset, 
       screenSize.width - inset * 7, 
       screenSize.height - inset * 4); 

     //Set up the GUI. 
     desktop = new JDesktopPane(); //a specialized layered pane 
     desktop.setBackground(Color.DARK_GRAY); 

     createRFFrame(); //create first RFFrame 
     createScenarioFrame(); //create ScenarioFrame 

     setContentPane(desktop); 
     setJMenuBar(createMenuBar()); 

     //Make dragging a little faster but perhaps uglier. 
     desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE); 
    } 

    protected JMenuBar createMenuBar() { 
     JMenuBar menuBar = new JMenuBar(); 

     //Set up the lone menu. 
     JMenu menu = new JMenu("File"); 
     menu.setMnemonic(KeyEvent.VK_D); 
     menuBar.add(menu); 

     //Set up the first menu item. 
     JMenuItem menuItem = new JMenuItem("Add Panel"); 
     menuItem.setMnemonic(KeyEvent.VK_N); 
     menuItem.setAccelerator(KeyStroke.getKeyStroke(
       KeyEvent.VK_N, ActionEvent.ALT_MASK)); 
     menuItem.setActionCommand("new"); 
     menuItem.addActionListener(this); 
     menu.add(menuItem); 

     //Set up the second menu item. 
     menuItem = new JMenuItem("Quit"); 
     menuItem.setMnemonic(KeyEvent.VK_Q); 
     menuItem.setAccelerator(KeyStroke.getKeyStroke(
       KeyEvent.VK_Q, ActionEvent.ALT_MASK)); 
     menuItem.setActionCommand("quit"); 
     menuItem.addActionListener(this); 
     menu.add(menuItem); 

     return menuBar; 
    } 

    //React to menu selections. 
    public void actionPerformed(ActionEvent e) { 
     if ("new".equals(e.getActionCommand())) { //new 
      createRFFrame(); 
     } else { 
      //quit 
      quit(); 
     } 
    } 

    /* 
    * ActivateAllAction activates all radios on the panel, essentially changes the color 
    * of each ellipse from INACTIVE to ACTIVE 
    */ 
    private class ActivateAllAction extends AbstractAction { 
     public ActivateAllAction(String name) { 
      super(name); 
      int mnemonic = (int) name.charAt(1); 
      putValue(MNEMONIC_KEY, mnemonic); 
     } 

     /* 
     * This will find the selected tab and extract the DrawEllipses instance from it 
     * Then for the actionPerformed it will call activateAll() from DrawEllipses 
     */ 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      Component comp = desktop.getSelectedFrame(); 
      if (comp instanceof DrawEllipses){ 
       DrawEllipses desktop = (DrawEllipses) comp; 
       desktop.activateAll(); 
      } 
     } 
    } 

    /* 
    * DeactivateAllAction deactivates all radios on the panel, essentially changes the color 
    * of each ellipse from ACTIVE to INACTIVE 
    */ 
    private class DeactivateAllAction extends AbstractAction { 
     public DeactivateAllAction(String name) { 
      super(name); 
      int mnemonic = (int) name.charAt(0); 
      putValue(MNEMONIC_KEY, mnemonic); 
     } 

     /* 
     * This will find the selected tab and extract the DrawPanel2 instance from it 
     * Then for the actionPerformed it will call activateAll() from DrawEllipses 
     */ 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      Component comp = desktop.getSelectedFrame(); 
      if (comp instanceof DrawEllipses){ 
       DrawEllipses desktop = (DrawEllipses) comp; 
       desktop.deactivateAll(); 
      } 
     } 
    } 

    /* 
    * Define a JPanel that will hold the activate and deactivate all JButtons 
    */ 
    protected JPanel btnPanel() { 
     JPanel btnPanel = new JPanel(); 

     btnPanel.setBorder(BorderFactory.createLoweredSoftBevelBorder()); 

     //Set the layout of the frame to a grid bag layout 
     btnPanel.setLayout(new GridBagLayout()); 

     //Creates constraints variable to hold values to be applied to each aspect of the layout 
     GridBagConstraints c = new GridBagConstraints(); 

     //Column 1 
     c.gridx = 0; 
     btnPanel.add(new JButton(new ActivateAllAction("Activate All"))); 

     //Column 2 
     c.gridx = 1; 
     btnPanel.add(new JButton(new DeactivateAllAction("Deactivate All"))); 
     return btnPanel; 
    } 

    //not used currently 
    protected JPanel drawPanel() { 
     JPanel drawPanel = new JPanel(); 
     drawPanel.setBorder(BorderFactory.createLoweredSoftBevelBorder()); 
     DrawEllipses drawEllipses = new DrawEllipses(POINT_LIST); 
     drawPanel.add(drawEllipses); 

     return drawPanel; 

    } 

    //Create a new internal frame. 
    protected void createRFFrame() { 
     frame.setLayout(new BorderLayout()); 

     DrawEllipses drawEllipses = new DrawEllipses(POINT_LIST); 
     frame.add(drawEllipses); 
     frame.add(btnPanel(), BorderLayout.SOUTH); 

     frame.setVisible(true); 
     desktop.add(frame); 

     try { 
      frame.setSelected(true); 
     } catch (java.beans.PropertyVetoException e) {} 
    } 

    protected void createScenarioFrame() { 
     ScenarioInternalFrame frame = new ScenarioInternalFrame(); 
     frame.setLayout(new BorderLayout()); 

     frame.setVisible(true); 
     desktop.add(frame); 

     try { 
      frame.setSelected(true); 
     } catch (java.beans.PropertyVetoException e) {} 
    } 

    //Quit the application. 
    protected void quit() { 
     System.exit(0); 
    } 

} 

@SuppressWarnings("serial") 
class DrawEllipses extends JPanel { 
    private double translateX; // 
    private double translateY; // 
    protected double scale; // 
    private static final int OVAL_WIDTH = 15; 
    private static final Color INACTIVE_COLOR = Color.RED; 
    private static final Color ACTIVE_COLOR = Color.green; 
    private java.util.List<Point> points; // 
    private java.util.List<Ellipse2D> ellipses = new ArrayList<>(); 
    private Map<Ellipse2D, Color> ellipseColorMap = new HashMap<>(); 

    public DrawEllipses(java.util.List<Point> points) { 
     this.points = points; // 
     translateX = 0; // 
     translateY = 0; // 
     scale = 1; // 
     setOpaque(true); // 
     setDoubleBuffered(true); // 


     for (Point p : points) { 
      int x = p.x - OVAL_WIDTH/2; 
      int y = p.y - OVAL_WIDTH/2; 
      int w = OVAL_WIDTH; 
      int h = OVAL_WIDTH; 
      Ellipse2D ellipse = new Ellipse2D.Double(x, y, w, h); 
      ellipses.add(ellipse); 
      ellipseColorMap.put(ellipse, INACTIVE_COLOR); 
     } 

     MyMouseAdapter mListener = new MyMouseAdapter(); 
     addMouseListener(mListener); 
     addMouseMotionListener(mListener); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     AffineTransform tx = new AffineTransform(); // 
     tx.translate(translateX, translateY); // 
     tx.scale(scale, scale); // 

     Graphics2D g2 = (Graphics2D) g; 
     g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
       RenderingHints.VALUE_ANTIALIAS_ON); 
     for (Ellipse2D ellipse : ellipses) { 
      g2.setColor(ellipseColorMap.get(ellipse)); 
      g2.fill(ellipse); 
     } 
    } 

    private class MyMouseAdapter extends MouseAdapter { 
     @Override 
     public void mousePressed(MouseEvent e) { 
      for (Ellipse2D ellipse : ellipses) { 
       if (ellipse.contains(e.getPoint())) { 
        Color c = ellipseColorMap.get(ellipse); 
        c = (c == INACTIVE_COLOR) ? ACTIVE_COLOR : INACTIVE_COLOR; 
        ellipseColorMap.put(ellipse, c); 
       } 
      } 
      repaint(); 
     } 
    } 

    //Used for button click action to change all ellipses to ACTIVE_COLOR 
    public void activateAll(){ 
     for (Ellipse2D ellipse : ellipses){ 
      ellipseColorMap.put(ellipse, ACTIVE_COLOR); 
     } 
     repaint(); 
    } 

    //Used for button click action to change all ellipses to INACTIVE_COLOR 
    public void deactivateAll(){ 
     for (Ellipse2D ellipse : ellipses){ 
      ellipseColorMap.put(ellipse, INACTIVE_COLOR); 
     } 
     repaint(); 
    } 
} 

class RFInternalFrame extends JInternalFrame implements ComponentListener { 
    protected static double scale = 1; // 
    static int openFrameCount = 0; 
    static final int xOffset = 300, yOffset = 0; 

    public RFInternalFrame() { 
     super("RF Panel #" + (++openFrameCount), 
       true, //resizable 
       true, //closable 
       true, //maximizable 
       true);//iconifiable 

     setSize(300, 300); 
     setMinimumSize(new Dimension(300, 300)); 
     addComponentListener(this); 

     if (openFrameCount == 1) { 

      setLocation(0,0); 
     } 
     else if (openFrameCount <= 4) { 

      //Set the window's location. 
      setLocation(xOffset * (openFrameCount - 1), yOffset * (openFrameCount - 1)); 
     } 
     else if (openFrameCount == 5) { 

      setLocation(xOffset - 300, yOffset + 300); 
     } 
     else if (openFrameCount == 6) { 

      setLocation(xOffset + 600, yOffset + 300); 
     } 
    } 

    ////////////////////////////////////////////////// 
    @Override 
    public void componentResized(ComponentEvent e) { 
     String str = ""; 
     if (getWidth() < 300) { 
      str = "0." + getWidth(); 
     } else { 
      str = "1." + (getWidth() - 300); 
      System.out.println(getWidth() - 300); 
     } 
     double dou = Double.parseDouble(str); 
     MainPanel.frame.scale = dou; 
    } 

    @Override 
    public void componentMoved(ComponentEvent componentEvent) { 

    } 

    @Override 
    public void componentShown(ComponentEvent componentEvent) { 

    } 

    @Override 
    public void componentHidden(ComponentEvent componentEvent) { 

    } 
} 

class ScenarioInternalFrame extends JInternalFrame { 
    static int openFrameCount = 0; 
    static final int xOffset = 300, yOffset = 300; 

    public ScenarioInternalFrame() { 
     super("Test Scenario" + (++openFrameCount), 
       true, //resizable 
       true, //closable 
       true, //maximizable 
       true);//iconifiable 

     //...Create the GUI and put it in the window... 

     //...Then set the window size or call pack... 
     setSize(600, 300); 

     //Set the window's location. 
     setLocation(xOffset, yOffset); 
    } 
} 

這裏是堆棧跟蹤:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException 
    at MainPanel.createRFFrame(MainPanel.java:205) 
    at MainPanel.<init>(MainPanel.java:69) 
    at MainPanel.createAndShowGui(MainPanel.java:48) 
    at MainPanel.access$000(MainPanel.java:8) 
    at MainPanel$1.run(MainPanel.java:42) 
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251) 
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:733) 
    at java.awt.EventQueue.access$200(EventQueue.java:103) 
    at java.awt.EventQueue$3.run(EventQueue.java:694) 
    at java.awt.EventQueue$3.run(EventQueue.java:692) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76) 
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:703) 
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242) 
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161) 
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150) 
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146) 
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138) 
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:91) 

Process finished with exit code 0 

回答

2

你忘frame.setLayout(new BorderLayout());之前調用frame = new RFInternalFrame();。如果沒有這一行,你正嘗試設置尚未初始化的RFInternalFrame的佈局 - 所以程序打印出一個NPE。有關更多詳細信息,請參閱What is a Null Pointer Exception, and how do I fix it?

+0

謝謝,這確實讓我編譯。此外,既然你迴應了,你能否告訴我爲什麼我的轉換不起作用?它與你前一天展示給我的概念相同,但在嘗試使其適應該代碼時不會縮放。 – feltersnach

+1

@feltersnach在'Graphics2D g2 =(Graphics2D)g;'後面調用'g2.setTransform(tx);'並用'DrawEllipses.scale = dou;'替換'MainPanel.frame.scale = dou;'。在那之後再添加一個'repaint();'。現在它可以擴展,但不幸的是會出現一個新問題:有時點會「跳」到頂端(在測試之後,您會明白我的意思)。我現在太累了,無法完成所有代碼並找到問題。我保證稍後我會盡力幫助你。 –

+0

再次感謝,我今晚將繼續努力。 – feltersnach

3

你在這裏得到了NPE:

//Create a new internal frame. 
protected void createRFFrame() { 
    frame.setLayout(new BorderLayout()); 

簡單地說,NPE是正確的,框爲空,你根本就從來沒有初始化這個變量。嘗試將變量標記爲final,您將看到一個編譯器錯誤,它永遠不會被初始化。我認爲混亂可能是你有另一個變量稱爲框架,但它有一個不同的範圍,沒有關係:

private static void createAndShowGui() { 
    JFrame frame = new MainPanel(); 
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
    frame.setLocationByPlatform(false); 
    frame.setVisible(true); 
} 
+0

感謝您的回覆! – feltersnach