I am having problem with the swing JMenu component on the JFrame with JME canvas embedded in it.
I found the example “JME3 Canvas in a Swing GUI” extremely helpful and got it working fine. The JME app displays in the app window fine:
Personally, I use AwtPanels instead because I understood canvas support to be a little dodgy… but it may be that things aren’t properly sized yet when pack() is done. You could try doing a swingutilities invoke from simpleInitApp() that calls pack() again maybe.
This didn’t solve the issue, but it did remove the margin space around the canvas. It also kept the space at the bottom which I guess is the height of the JMenuBar:
Can I display the JME Canvas in AWT panel and still be able to use swing components for menu bars, popups, internal frames on the top of the AWT panel?
I have a swing application that uses JME’s AwtPanels class instead of canvas. It works fine and I’m able to lay out my app fine. I don’t know why canvas is not working for you and it could just be something simple that I don’t know… since I’ve never used it before I can’t really say.
For my app, I manage this in an app state:
public class AwtPanelState extends BaseAppState {
// Other than initial setup these fields are _only_ accessed
// from the swing thread except Viewport attachment
private final Container container;
private final Object constraints;
private volatile AwtPanel panel;
private List<Runnable> enabledCommands = new CopyOnWriteArrayList<>();
public AwtPanelState( Container container, Object constraints ) {
this.container = container;
this.constraints = constraints;
}
public void addEnabledCommand( Runnable cmd ) {
enabledCommands.add(cmd);
}
protected void initialize( Application app ) {
try {
SwingUtilities.invokeAndWait(new InitializeCommand());
} catch( InterruptedException | InvocationTargetException e ) {
throw new RuntimeException("Error creating panel on swing thread", e);
}
// Can't unattach them so we might as well do it on init
panel.attachTo(true, app.getViewPort(), app.getGuiViewPort());
}
protected void onEnable() {
SwingUtilities.invokeLater(new AttachPanelCommand());
}
protected void onDisable() {
SwingUtilities.invokeLater(new DetachPanelCommand());
}
protected void cleanup( Application app ) {
}
private class InitializeCommand implements Runnable {
public void run() {
AwtPanelsContext ctx = (AwtPanelsContext)getApplication().getContext();
panel = ctx.createPanel(PaintMode.Accelerated);
panel.setPreferredSize(new Dimension(1280, 720));
panel.setMinimumSize(new Dimension(400, 300));
panel.setBackground(Color.black);
ctx.setInputSource(panel);
}
}
private class AttachPanelCommand implements Runnable {
public void run() {
// Add it to the container provided
container.add(panel, constraints);
for( Runnable r : enabledCommands ) {
r.run();
}
}
}
private class DetachPanelCommand implements Runnable {
public void run() {
container.remove(panel);
}
}
}
Then in my application, I initialize it like:
public class TestApp extends SimpleApplication {
private volatile JFrame mainFrame;
public static void main(String[] args) throws Exception {
JFrame.setDefaultLookAndFeelDecorated(true);
JPopupMenu.setDefaultLightWeightPopupEnabled(false);
UIManager.setLookAndFeel(new SubstanceGraphiteGlassLookAndFeel());
final TestApp app = new TestApp();
app.setShowSettings(false);
AppSettings settings = new AppSettings(true);
settings.setCustomRenderer(AwtPanelsContext.class);
settings.setFrameRate(60);
app.setSettings(settings);
app.start();
}
public TestApp() throws Exception {
super(new StatsAppState(), new DebugKeysAppState(), new BasicProfilerState(false),
new FlyCamAppState());
// Have to create the frame on the AWT EDT.
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
mainFrame = new JFrame("Test App");
mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
mainFrame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent e) {
stop();
}
});
mainFrame.setJMenuBar(createMainMenu());
stateManager.attach(new AwtPanelState(rmainFrame, BorderLayout.CENTER));
}
});
stateManager.getState(AwtPanelState.class).addEnabledCommand(new Runnable() {
public void run() {
if( !mainFrame.isVisible() ) {
// By now we should have the panel inside
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
}
});
}
...
@Override
public void simpleInitApp() {
flyCam.setDragToRotate(true);
...
…something like that. I removed a bunch of my own stuff but I think the important bits are still there.
Content pane should already have border layout and the setMenuBar() should already be putting the menu bar in the right place with respect to the internal JRootPane.
Something is funky that this isn’t working as written.
He shouldn’t have had to add the menu bar to the north of the content pane… because the menu bar shouldn’t even be in the content pane.