Application.getContext() is of type NullContext after a call to Application.createCanvas()

hi,

i am new here so let me immediatly say that i would be very thankfull for any help that you can give me!

for the last weeks i am trying to find my way into jme. the latest problem i have stumbled upon involves jme usage within swing.

of course i have read the appropriate tutorial:

https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:swing_canvas

and i have tried to follow it as close as possible.

nethertheless i have to admit that the example is quite advanced for me, and i also tried to follow the much simpler version i found here:

欧美Av色爱综合网欧美Av,亚洲 欧洲 日韩 av综合,亚洲 自拍色综合图区

more specifically the TestSafeCanvas version.

Let me present my code: It contains 2 classes: JMonkeyCanvas and QuaternionsAndAngleMatrices. JMonkeyCanvas is being used from within QuaternionsAndAngleMatrices

Code:
public class JMonkeyCanvas extends SimpleApplication {
public Canvas canvas;
private int x, y;

public JMonkeyCanvas(int x, int y) {
	super();

	this.x = x;
	this.y = y;
}

public void initCanvas() {
	AppSettings s = new AppSettings(false);
	s.setWidth(this.x);
	s.setHeight(this.y);
	this.setSettings(s);
	this.setPauseOnLostFocus(false);

	this.createCanvas();
	this.startCanvas(true);

	Dimension d = new Dimension(this.x, this.y);
	this.canvas = ((JmeCanvasContext) this.getContext()).getCanvas();
	this.canvas.setSize(d);
	this.canvas.setPreferredSize(d);

	System.out.println("JMonkeyCanvas initialized");
}

public void simpleInitApp() {
}

public void simpleUpdate() {
}

}

public class QuaternionsAndAngleMatrices extends JPanel {

public static JMonkeyCanvas jmec = new JMonkeyCanvas(500, 500);
private JPanel jmecanvas;

public void createCanvasSpace() {
	this.jmecanvas = new JPanel();
	this.jmecanvas.setLayout(new FlowLayout());
	this.jmecanvas.add(jmec.canvas);
}


public static void main(String[] args) {
	jmec.initCanvas();

	try {
		Thread.sleep(3000);
	} catch (InterruptedException ex) {}

	SwingUtilities.invokeLater(new Runnable() {
		public void run() {
			QuaternionsAndAngleMatrices qa = new QuaternionsAndAngleMatrices();
			qa.createCanvasSpace();

			qa.setLayout(new GridLayout(1, 1, 10, 10));

			qa.add(qa.jmecanvas);

			JFrame f = new JFrame();
			f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			f.addWindowListener(new WindowAdapter() {
				@Override public void windowClosed(WindowEvent e) {
					jmec.stop();
				}
			});
			f.getContentPane().add(qa);
			f.pack();
			f.setVisible(true);
		}
	});
}

}


however, the above code fails in the method initCanvas in line
Code:
this.canvas = ((JmeCanvasContext) this.getContext()).getCanvas();
with the error
Code:
com.jme3.system.NullContext cannot be cast to com.jme3.system.JmeCanvasContext
what am i doing wrong?
thank you very much!

The canvas simply isn’t an JmeCanvasContext instance. Check what is the object instance the the getCanvas() returns by printing its class name:



System.out.println(context.getCanvas().getClass().getName());

actually the exception originates from the call to the method getContext() , as the return value of the method cannot be cast to com.jme3.system.JmeCanvasContext.

if i try to follow your suggestion and use (i hope that is consistent with your intention):

Code:
System.out.println("context: " + this.getContext().getClass().getName());
the result is, as expected from the exception: context: com.jme3.system.NullContext
thus the error message originates from com.jme3.system.NullContext and com.jme3.system.JmeCanvasContext being unrelated: JmeCanvasContext is a subinterface of JmeContext, and NullContext only implements JmeContext...
so the real question is: Why is the context of type context:com.jme3.system.NullContext and not of type com.jme3.system.JmeCanvasContext ?
all the javadoc documentation of Application.createCanvas() seems to say, is that after the call to it, the context returned by the method getContext is supposed to be of type JmeCanvasContext .
the tutorial is not that clear to me (otherwise the problem would most propably not exist)
https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:swing_canvas
on the one hand it says, i quote:
Here in the run() method, we start the jME application, create its canvas, create a Swing frame, and add everything together.

on the other, in the associated source code the application seems to be started outside of the run method, by a call to createCanvas() from main . within createCanvas there is pretty much the same as in my method initCanvas . let me cite it here for convenience:
Code:
// Code excerpt from the tutorial swing canvas: TestCanvas public static void main(String[] args) { JmeFormatter formatter = new JmeFormatter();
	Handler consoleHandler = new ConsoleHandler();
	consoleHandler.setFormatter(formatter);

	Logger.getLogger("").removeHandler(Logger.getLogger("").getHandlers()[0]);
	Logger.getLogger("").addHandler(consoleHandler);

	createCanvas(appClass);

	try {
		Thread.sleep(500);
	} catch (InterruptedException ex) {
	}

	SwingUtilities.invokeLater(new Runnable() {

		public void run() {
			JPopupMenu.setDefaultLightWeightPopupEnabled(false);

			createFrame();

			currentPanel.add(canvas, BorderLayout.CENTER);
			frame.pack();
			startApp();
			frame.setLocationRelativeTo(null);
			frame.setVisible(true);
			System.out.println("running!");
		}
	});
}

public static void createCanvas(String appClass) {
	AppSettings settings = new AppSettings(true);
	settings.setWidth(640);
	settings.setHeight(480);

	try {
		Class<? extends Application> clazz = (Class<? extends Application>) Class.forName(appClass);
		app = clazz.newInstance();
	} catch (ClassNotFoundException ex) {
		ex.printStackTrace();
	} catch (InstantiationException ex) {
		ex.printStackTrace();
	} catch (IllegalAccessException ex) {
		ex.printStackTrace();
	}

	app.setPauseOnLostFocus(false);
	app.setSettings(settings);
	app.createCanvas();
	app.startCanvas();

	context = (JmeCanvasContext) app.getContext();
	canvas = context.getCanvas();
	canvas.setSize(settings.getWidth(), settings.getHeight());
}</div>

yet obviously the tutorial code is running, mine isn't, and i am just to blind to see the mistake.... any idea?

well,

i actually managed to solve the problem like this now…

though i am still not sure what caused the problem in the first place, so if someone has an idea i would still be happy if they could point me in the right direction.

nethertheless i believe this is a fairly elegent solution allowing the canvas to be displayed in any swing application, while any jmonkey application can be passed to it in its constructor.

if anyone has an opinion about the code i would be happy about feedback as well!

thanks!

Code:
public class JCanvas extends JPanel {
private Application app;
private int x, y;
JFrame frame;

public class JCanvasRunner implements Runnable {

	private JCanvas jc;

	public JCanvasRunner(JCanvas jc) {
		this.jc = jc;
	}

	public void run() {
		jc.add(((JmeCanvasContext) jc.app.getContext()).getCanvas(), BorderLayout.CENTER);
	}
}

public class JCanvasWindowListener extends WindowAdapter {
	
	private JCanvas jc;
	
	public JCanvasWindowListener (JCanvas jc) {
		this.jc = jc;
	}
	
	@Override public void windowClosed(WindowEvent e) {
		jc.stop();
	}
}

public JCanvas(Application app, int x, int y) {
	this.app = app;
	this.x = x;
	this.y = y;
}

public void createFrame() {
	this.setLayout(new BorderLayout());
}

public void initCanvas(JFrame frame) {
	frame.addWindowListener(new JCanvasWindowListener(this));
	AppSettings settings = new AppSettings(true);
	settings.setWidth(x);
	settings.setHeight(y);
	app.setSettings(settings);
	app.setPauseOnLostFocus(false);
	app.createCanvas();
	app.startCanvas();
	((JmeCanvasContext) app.getContext()).getCanvas().setSize(x, y);

	try {
		Thread.sleep(500);
	} 
	catch (InterruptedException ex) {}

	SwingUtilities.invokeLater(new JCanvasRunner(this));
}

public void stop() {
	app.stop();
}

public static void main(String[] args) {
	JFrame frame = new JFrame(&quot;Test&quot;);
	frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

	JCanvas jc = new JCanvas(new Main(), 500, 500);
	jc.initCanvas(frame);

	frame.getContentPane().add(jc);
	frame.pack();
	frame.setLocationRelativeTo(null);
	frame.setVisible(true);
}

}

It doesn’t consider threading between the update loop and awt thread, thats also why your sleep() apparently fixes the issue. You have to use app.enqueue for the scene like you have to use SwingUtilities.invokeLater for the awt thread:

http://hub.jmonkeyengine.org/groups/general-2/snippets/single/10/

thank you very much for your advice!

your recommendation has proven itself to be most helpfull!

is there any way i can mark this as solved?

You can edit the title but you don’t have to.