JWrapper bundled OS-X no longer allows OS-X apps to display the menu bar at the top of the screen in true Apple style. Even when Apple look and feel for menu bar is specified with:
System.setProperty("apple.laf.useScreenMenuBar", "true");
or if jwrapper.xml file contains:
<JvmOptions>
<JvmOption>-Xmx1024m</JvmOption>
<JvmOption>-Dapple.laf.useScreenMenuBar=true</JvmOption>
</JvmOptions>
My test files is
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
public class Main {
static {
System.setProperty("apple.laf.useScreenMenuBar", "true");
}
public static void main(String[] args) {
JFrame frame = new JFrame("Menu Bar Demo");
JMenuBar bar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
JMenu editMenu = new JMenu("Edit");
JMenu helpMenu = new JMenu("Help");
bar.add(fileMenu);
bar.add(editMenu);
bar.add(helpMenu);
frame.setSize(300, 150);
frame.setJMenuBar(bar);
frame.setVisible(true);
}
}
My jwrapper command line (and jwrapper version) are:
java -jar jwrapper-00034804310.jar jwrapper.xml
I am running on OS-X 10.9.5 and using Java 1.8.0_40 to build and run the app and also that is the version bundled with Jwrappered app
Related
In Eclipse, when I run the code, this works:
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame("test viewing images");
frame.setSize(600,300);
frame.setLocationRelativeTo(null); // centered on monitor
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
/**
* Menu Bar stuff
*/
JMenuBar menuBar;
JMenu menu;
JMenuItem menuItem;
// MENU BAR
menuBar = new JMenuBar();
frame.setJMenuBar(menuBar);
menuBar.setVisible(true);
// MENU 1
menu = new JMenu("File");
menuBar.add(menu);
// MENU 1 ITEM
ImageIcon icon = new ImageIcon("src/Action-exit-icon.png");
menuItem = new JMenuItem("Exit Program", icon);
menu.add(menuItem);
frame.setVisible(true);
}
}
And here's the File Structure from my Package Explorer:
ShowImage (project)
> src / Main.java
> src / Action-exit-icon.png
Also, this workspace is located in Z:\eclipse_projects
I can see the ImageIcon icon = new ImageIcon("src/Action-exit-icon.png"); is working nicely, and the menuBar does it's job.
Now let's Export this project, and I'll email the JAR to a friend of mine.
Right-click project > Select Export
Select Java > Runnable JAR File
I choose the Main File in Launch configuration
Export destination: my desktop
Library handling: Extract required libraries into generated JAR
go to my desktop, double-click the ShowImage.jar
The JFrame shows up, but the Action-exit-icon.png isn't appearing at all.
When I open the ShowImage.jar, to view it's contents, I see the Main.class, Action-exit-icon.png, META-INF.
Ok, I'm seriously confused about how to reference an image, or any resource now.
What am I doing wrong?
new ImageIcon("src/Action-exit-icon.png");
The String constructor for an ImageIcon presumes the string to represent a File path.
This image is obviously an application resource, and will become an embedded resource by the time of deployment (in a Jar). Therefore it must be accessed by URL from the run-time class-path of the app., like so:
new ImageIcon(getClass().getResource("/src/Action-exit-icon.png"));
Overhauling the code, I get this:
import java.awt.Color;
import javax.swing.*;
public class JavaGui148 {
public JComponent getGUI() {
JPanel p = new JPanel();
p.setBackground(Color.GREEN);
return p;
}
public JMenuBar getMenuBar() {
/**
* Menu Bar stuff
*/
JMenuBar menuBar;
JMenu menu;
JMenuItem menuItem;
// MENU BAR
menuBar = new JMenuBar();
menuBar.setVisible(true);
// MENU 1
menu = new JMenu("File");
menuBar.add(menu);
// MENU 1 ITEM
ImageIcon icon = new ImageIcon(getClass().getResource(
"/src/Action-exit-icon.png"));
menuItem = new JMenuItem("Exit Program", icon);
menu.add(menuItem);
return menuBar;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
JavaGui148 gui = new JavaGui148();
JFrame f = new JFrame("Demo");
f.setJMenuBar(gui.getMenuBar());
f.add(gui.getGUI());
// Ensures JVM closes after frame(s) closed and
// all non-daemon threads are finished
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// See http://stackoverflow.com/a/7143398/418556 for demo.
f.setLocationByPlatform(true);
// ensures the frame is the minimum size it needs to be
// in order display the components within it
f.pack();
// should be done last, to avoid flickering, moving,
// resizing artifacts.
f.setVisible(true);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(r);
}
}
How to use the screen menu bar with a mnemonic key combination (e.g. Ctrl + Alt + F) instead of windows menu bar on MacOS?
Expected outcome (menu in the screen menu bar):
Actual outcome (menu in the window menu bar):
Code:
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
class GUI extends JFrame {
public static void main(String[] args) {
new GUI();
}
public GUI() {
// Use the screen menu bar instead of the window menu bar.
System.setProperty("apple.laf.useScreenMenuBar", "true");
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("File");
JMenuItem menuItem1 = new JMenuItem("New");
JMenuItem menuItem2 = new JMenuItem("Open");
JMenuItem menuItem3 = new JMenuItem("Close");
// Make the menu listens to <Ctrl> + <Alt> + <F> mnemonic key events.
menu.setMnemonic('F');
menu.add(menuItem1);
menu.add(menuItem2);
menu.add(menuItem3);
menuBar.add(menu);
setJMenuBar(menuBar);
setSize(854, 480);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
}
It looks like this is impossible, there are no mnemonics to access the menu bar on macOS.
See a similar question on Super User: How to select File menu in Mac, just like Alt + F in Windows?. Although the question is not Swing-specific, the answers highlight that this is impossible on macOS. Swing does its best to display the menu invoked by a mnemonic.
In Eclipse, when I run the code, this works:
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame("test viewing images");
frame.setSize(600,300);
frame.setLocationRelativeTo(null); // centered on monitor
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
/**
* Menu Bar stuff
*/
JMenuBar menuBar;
JMenu menu;
JMenuItem menuItem;
// MENU BAR
menuBar = new JMenuBar();
frame.setJMenuBar(menuBar);
menuBar.setVisible(true);
// MENU 1
menu = new JMenu("File");
menuBar.add(menu);
// MENU 1 ITEM
ImageIcon icon = new ImageIcon("src/Action-exit-icon.png");
menuItem = new JMenuItem("Exit Program", icon);
menu.add(menuItem);
frame.setVisible(true);
}
}
And here's the File Structure from my Package Explorer:
ShowImage (project)
> src / Main.java
> src / Action-exit-icon.png
Also, this workspace is located in Z:\eclipse_projects
I can see the ImageIcon icon = new ImageIcon("src/Action-exit-icon.png"); is working nicely, and the menuBar does it's job.
Now let's Export this project, and I'll email the JAR to a friend of mine.
Right-click project > Select Export
Select Java > Runnable JAR File
I choose the Main File in Launch configuration
Export destination: my desktop
Library handling: Extract required libraries into generated JAR
go to my desktop, double-click the ShowImage.jar
The JFrame shows up, but the Action-exit-icon.png isn't appearing at all.
When I open the ShowImage.jar, to view it's contents, I see the Main.class, Action-exit-icon.png, META-INF.
Ok, I'm seriously confused about how to reference an image, or any resource now.
What am I doing wrong?
new ImageIcon("src/Action-exit-icon.png");
The String constructor for an ImageIcon presumes the string to represent a File path.
This image is obviously an application resource, and will become an embedded resource by the time of deployment (in a Jar). Therefore it must be accessed by URL from the run-time class-path of the app., like so:
new ImageIcon(getClass().getResource("/src/Action-exit-icon.png"));
Overhauling the code, I get this:
import java.awt.Color;
import javax.swing.*;
public class JavaGui148 {
public JComponent getGUI() {
JPanel p = new JPanel();
p.setBackground(Color.GREEN);
return p;
}
public JMenuBar getMenuBar() {
/**
* Menu Bar stuff
*/
JMenuBar menuBar;
JMenu menu;
JMenuItem menuItem;
// MENU BAR
menuBar = new JMenuBar();
menuBar.setVisible(true);
// MENU 1
menu = new JMenu("File");
menuBar.add(menu);
// MENU 1 ITEM
ImageIcon icon = new ImageIcon(getClass().getResource(
"/src/Action-exit-icon.png"));
menuItem = new JMenuItem("Exit Program", icon);
menu.add(menuItem);
return menuBar;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
JavaGui148 gui = new JavaGui148();
JFrame f = new JFrame("Demo");
f.setJMenuBar(gui.getMenuBar());
f.add(gui.getGUI());
// Ensures JVM closes after frame(s) closed and
// all non-daemon threads are finished
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// See http://stackoverflow.com/a/7143398/418556 for demo.
f.setLocationByPlatform(true);
// ensures the frame is the minimum size it needs to be
// in order display the components within it
f.pack();
// should be done last, to avoid flickering, moving,
// resizing artifacts.
f.setVisible(true);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(r);
}
}
I've run into some bugs in Apple's JVM's as i mentioned in my previous question.And i can live with first bug. But second is really annoying. If i create a JMenu with submenu in it and i have to modify submenu contents in runtime, i just can't do it. Debugging shows that items are added to Jmenu (submenu). But nothing's happening in screen menubar. This looks like a problem of synchronization of real JMenu object and it's representation in Mac OS X menubar.
Here's sample code:
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.SwingUtilities;
public class TestMenu extends JFrame{
public TestMenu() {
System.setProperty("apple.laf.useScreenMenuBar", "true");
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
JMenuBar mb = new JMenuBar();
mb.setName("menubar");
JMenu menu = new JMenu("menu");
JMenu submenu = new JMenu("submenu");
JMenuItem item = new JMenuItem("test item");
JMenuItem item2 = new JMenuItem("test item2");
JMenuItem subitem1 = new JMenuItem("sub item1");
JMenuItem subitem2 = new JMenuItem("sub item2");
menu.add(item);
mb.add(menu);
menu.add(submenu);
setJMenuBar(mb);
menu.add(item2);
setBounds(100, 100, 100, 100);
setVisible(true);
submenu.add(subitem1);
submenu.add(subitem2);
}
public static void main(String[] args) {
new TestMenu();
}
}
Note: I'm speaking of version 1.6.0_15 of Apple's JVM. I have to keep obsolete versions in mind to make sure my software will not expose any data because of bugs in some JVM on user's computer which was not updated since he or she bought that MAC. Current version of Java for Windows and Mac OS X works fine.
The question itself: maybe someone knows a way to manually synchronize JMenu and it's representation? Or maybe you can propose another workaround?
I've found the solution, and it wasn't so hard...
.................................
menu.add(item2);
setBounds(100, 100, 100, 100);
setVisible(true);
submenu.add(subitem1);
submenu.add(subitem2);
SwingUtilities.updateComponentTreeUI(mb); //This line updates menu representation
}
................................
Maybe I understood you wrong, but it's only a problem to display the changes? If so, try repaint() after submenu.add(subitem1) and submenu.add(subitem2).
I have a Java desktop application (document editor) for where I recently added a menubar, with menus which in turn have menu items. The problem is that - in my GNOME desktop environment (Ubuntu) the menu item separators are not visible at all. They are visible if I switch the application L&F to default Java (metal) LaF or to switch the desktop environment KDE environment on Ubuntu, but the menu item separators are never visible under GNOME environment. Also I am setting the application L&F to "GTK". If I force the L&F to "motif" the file separators can be clearly seen.
Has anyone else ever faced this kind of a problem before on Ubuntu GNOME environment? I am attaching the code below - which is straight forward and don't think there is any problem here.
import java.awt.EventQueue;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
static JFrame frame = null;
static JMenuBar menubar = null;
static JMenu filemenu = null;
public static void main (String[] args) throws InterruptedException,
InvocationTargetException {
EventQueue.invokeAndWait(new Runnable () {
#Override
public void run() {
createAndShowGUI ();
}
});
}
private static void createAndShowGUI () {
/* Set LAF to GTK LAF */
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
/* Create frame */
frame = new JFrame ();
frame.setLocation(50, 50);
frame.setSize(400, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
/* Add menu bar */
addMenuBar ();
}
private static void addMenuBar () {
/* Create menu bar and then file menu*/
menubar = new JMenuBar ();
filemenu = new JMenu ("File");
/* Add three menu items to the file menu */
JMenuItem newItem = new JMenuItem ("New ");
JMenuItem openItem = new JMenuItem ("Open ");
JMenuItem exitItem = new JMenuItem ("Exit ");
/* Add the menu items to the file menu. Also separate the last item
* from the first two using a menu item separator */
filemenu.add(newItem);
filemenu.add(openItem);
filemenu.addSeparator();
filemenu.add(exitItem);
/* Add the file menu to the menu bar */
menubar.add(filemenu);
/* Add menu bar to frame */
frame.setJMenuBar(menubar);
}
}
So the question is - do I need to add some more customization when using "GTK" L&F in GNOME environment so that the menu item separators are visible again?
[Edit: the post has now been edited to reflect an sscce. If you want to see the effect of Java LAF then please comment out the lines inside the createAndShowGUI () where the LAF is hardcoded to GTK LAF. The problem goes away with Java LAF but remains when using GTK LAF]