Home > Blockchain >  Swing/AWT/JavaFX GUI Freezing/NullPointerException
Swing/AWT/JavaFX GUI Freezing/NullPointerException

Time:09-22

I have a class that extends Application:

public class IO extends Application {
    private static JFrame frame = new JFrame("Shapes");;
    private final JPanel content = new JPanel();
    private final JPanel drawingArea = new JPanel();

my main/start method:

public static void main(String[] args) {
    Application.launch(args);
}

public void start(Stage primaryStage) throws Exception {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            new JFXPanel(); // initializes JavaFX environment
            createGUI();
        }
    });
}

I've done this to hopefully resolve any troubles between the swing/JavaFX components per this question. However, when I click a button that adds either a JPanel or a JFXPanel to another JPanel, if it was the JFXPanel, it will perform once just fine, but it will fail anytime thereafter that I try to generate a JFXPanel again, giving an "Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException" (but it actually takes 3 times total for this error to appear - the second time it will freeze, and if it doesn't, it does nothing). Here's the relevant code for the button:

JButton go = new JButton("Go");
go.addActionListener(new ActionListener() {
    // irrelevant code
        System.out.println("Shape set parameters: "   selectedShape.setParameters(shapeParams));
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new JFXPanel(); // initializes JavaFX environment
                Component shapePanel = (Component) new PaintedShape(selectedShape).getPanel();
                drawingArea.add(shapePanel);
                // drawingArea.add(new JLabel("Test"));
                // drawingArea.repaint();
                shapePanel.repaint();
                shapePanel.validate();
                drawingArea.repaint();
                drawingArea.validate();
                frame.pack();
                frame.setSize(new Dimension((int) (frame.getSize().getWidth()   PaintedShape.size.getWidth()),
                        (int) (frame.getSize().getHeight()   PaintedShape.size.getHeight())));
                frame.setLocationRelativeTo(null);
            }
        });
    }
});
params.add(go);
content.validate();

I call validate() a bunch of times because it was failing to add shapes sometimes, and one of those sets of calls initially fixed that error. Bonus points if you explain which panel is more relevant to call it on for me. If you feel you need the rest of the code, I created a github repo here.

Edit: full stacktrace -

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at com.sun.javafx.tk.quantum.QuantumToolkit.isSupported(QuantumToolkit.java:1153)
    at com.sun.javafx.application.PlatformImpl.isSupportedImpl(PlatformImpl.java:809)
    at com.sun.javafx.application.PlatformImpl.isSupported(PlatformImpl.java:482)
    at javafx.application.Platform.isSupported(Platform.java:168)
    at javafx.scene.shape.Shape3D.<init>(Shape3D.java:74)
    at javafx.scene.shape.Cylinder.<init>(Cylinder.java:89)
    at shapes.PaintedShape.painted3DShapePanel(PaintedShape.java:96)
    at shapes.PaintedShape.<init>(PaintedShape.java:51)
    at shapes.IO$1$1$1.run(IO.java:215)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
    at java.awt.EventQueue.access$500(EventQueue.java:97)
    at java.awt.EventQueue$3.run(EventQueue.java:709)
    at java.awt.EventQueue$3.run(EventQueue.java:703)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

Edit: Debugging further lead me to discover that it was not possible to instantiate any new three dimensional javafx shape in PaintedShape.java (see line 6 of the stack trace - at javafx.scene.shape.Shape3D.<init>(Shape3D.java:74)), possibly due to thread safety. Some of my fixes are included in my answer below, but I didn't mention that, despite my code being wrapped in Runnable()s "invoked later", I redundantly nested the specific JFXPanel generating code in the same runnable structure as well. This may have helped, though I'm not exactly sure how.

Platform.runLater(() -> {
    try {
        SwingUtilities.invokeLater(() -> {
            drawingPanel.add(shapePanel);
            frame.pack();
        });

    } catch (Exception e) {
        e.printStackTrace();
    }

});

CodePudding user response:

Fixed it. I believe the error may have been that, after removing all elements from the JPanel drawingArea, it was not immediately validate()d, and therefore didn't support adding elements to it. I also ensured that the JFXPanel was typed as such rather than being cast to a Component. I also ensured that the JPanel it was added to was created each time the button was pressed via JPanel drawing in case it being in the scope of the method previously mattered for some reason. See:

go.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
    final JPanel drawing = new JPanel();
        // irrelevant
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new JFXPanel(); // initializes JavaFX environment
                if (selectedShape.getClass().getSuperclass().getSimpleName()
                        .equals("TwoDimensionalShape")) {
                    Component shapePanel = (Component) new PaintedShape(selectedShape).getPanel();
                    drawing.add(shapePanel);
                } else {
                    JFXPanel shapePanel = (JFXPanel) new PaintedShape(selectedShape).getPanel();
                    Platform.runLater(() -> {
                        try {
                            SwingUtilities.invokeLater(() -> {
                                drawing.add(shapePanel);
                                frame.pack();
                            });

                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                    });
                }
                drawingArea.removeAll();
                drawingArea.validate();
                drawingArea.add(drawing);
                drawingArea.repaint();
                frame.pack();
                frame.setSize(new Dimension((int) (frame.getSize().getWidth()),
                        (int) (frame.getSize().getHeight()   PaintedShape.size.getHeight())));
                frame.setLocationRelativeTo(null);
            }
        });
    }
});

Full code with changes pushed to git repo as well for any more curious.

  • Related