Apple's JAVA: JMenu's submenu is not being updated - java

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).

Related

JMenuBar visibility confusion

I'm learning about GUI in Java.
I'm slightly confused here. When I place window.setVisible(true); like this, I only see JMenuBar if I resize it (it doesn't show without some sort of interaction).
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
public class Main {
public static void main(String[] args) {
JFrame window = new JFrame("My App");
window.setSize(500, 500);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
JMenuBar bar = new JMenuBar();
window.setJMenuBar(bar);
JMenu menu = new JMenu("File");
bar.add(menu);
}
}
But when I place it at the very bottom, it shows as expected. Why is this?
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
public class Main {
public static void main(String[] args) {
JFrame window = new JFrame("My App");
window.setSize(500, 500);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JMenuBar bar = new JMenuBar();
window.setJMenuBar(bar);
JMenu menu = new JMenu("File");
bar.add(menu);
window.setVisible(true);
}
}
Here it is explained that it must be called at the end, but what is the reasoning behind this?
java JMenuBar not visible?Why?
After adding a component you would have to repaint the container.
So if you add menubar after window is visible, it will popup after next repaint, in your example, after resize. If menubar is added prior setting window to be visible, it will be drawn at first drawing.
This is common behaviour for Swing components.
See Component javadoc
If you add or remove component:
If the container has already been displayed, the hierarchy must be
validated thereafter in order to display the added component.

JWrapper OS-X App prevents Menu Bar at top of screen

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

javaw.exe incorrect redraw to gui

Hi there.
I have a problem to one my PC. Source code is correct. My problem is in graphic render. This bug only on one laptop.
Example screens in 1 PC:
(screen in http://)
JLabel - i.gyazo.com/deafe8b111007562e47d93ab4f9728a3.png
JMenu - i.gyazo.com/1d5c5babd243d958073d2635f64b0e8a.png
JMenuItem - http://i.gyazo.com/aca39fd386d7d186c1f22bb2d629148e.png
JMenuItem - i.gyazo.com/d78f33834913e4548edf93f8bd996002.png
On other PC's there is no problems.: http://i.gyazo.com/51e9c928627d7091bbb302b5eb78b6a2.png
I thought that problem was in java JRE (I use v1.7) and I reinstalled it. But the problem remains. Also, I switched off Desktop Composition - but there is no luck either. What should I do now? Maybe the problem is in video driver or hardware acceleration?
Tell me how to solve the problem?
[message edited]
Example "bug code":
public class Example extends JFrame {
private static final long serialVersionUID = 1L;
public Example(){
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
JMenu mnNewMenu = new JMenu("\u041C\u0435\u043D\u044E");
menuBar.add(mnNewMenu);
JMenuItem mntmNewMenuItem = new JMenuItem("\u0424\u0430\u0439\u043B");
mnNewMenu.add(mntmNewMenuItem);
JMenuItem mntmNewMenuItem_1 = new JMenuItem("\u0412\u044B\u0445\u043E\u0434");
mnNewMenu.add(mntmNewMenuItem_1);
}
public static void main(String[] args){
Example form = new Example();
form.setSize(640,480);
form.setLocationRelativeTo(null);
form.setVisible(true);
}
}
screen bug: i.gyazo.com/9fcf258e62c498f8468d47b7f73759e1.png
screen normal: i.gyazo.com/ec27e655a0209e4613c3a19863fa0e18.png
Ok, this problem solved!
From my PC, i added lines:
System.setProperty("sun.java2d.d3d", "false");
System.setProperty("sun.java2d.ddoffscreen","false");
System.setProperty("sun.java2d.noddraw", "true");
This video driver error.

JMenu consumes focuslost event in Windows7 LAF Java7

If a popup menu is still open when another component is clicked, then the component does not get the event, because it's probably consumed by the popup. This happens for all JPopupmenus in general.
This happens only in Java 7 with windows LAF (Windows7). Is there a workaround? Is it a known bug?
import javax.swing.*;
import java.awt.event.*;
public class Test
{
public static void main(String[] s)
throws Exception
{
String lookAnfFeelClassName = UIManager.getSystemLookAndFeelClassName();
UIManager.setLookAndFeel(lookAnfFeelClassName);
JMenu menu = new JMenu("TEST Menu");
JMenuItem menuItem = new JMenuItem("Menu Item 1");
JMenuBar menuBar = new JMenuBar();
menu.add(menuItem);
menuBar.add(menu);
final JButton b = new JButton("Test");
b.setBounds(5, 50, 60, 20);
b.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//If the Menu is open when I press the button, the putton is not pressed
//so I have to press it again.
JOptionPane.showMessageDialog(b, "Button Pressed");
}
}
);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(150, 150);
frame.setJMenuBar(menuBar);
frame.getContentPane().setLayout(null);
frame.getContentPane().add(b);
frame.setVisible(true);
}
}
Here is the magic line that fixes the problem:
UIManager.put("PopupMenu.consumeEventOnClose", Boolean.FALSE);
I found this after looking into the source code for the BasicPopupMenuUI class. Apparently this behaviour is a deliberate design choice according to the following comments in the code, but it sure feels like a bug to me.
// Ask UIManager about should we consume event that closes
// popup. This made to match native apps behaviour.
By the way, it happens in Java 5 and 6 too.

Why won't my JMenuBar show up?

I'm trying to make a GUI in java, but JMenuBar has been giving me a hard time for two days. Can someone please tell me why it isn't showing up?
import java.awt.*;
import javax.swing.*;
import javax.swing.JPanel;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import java.util.Arrays;
import javax.imageio.ImageIO;
public class selectionFrame extends JFrame
{
Font name;
Font title;
public void setup() //can't use constructer because this isn't given a size until after it is constructed.
{
//getContentPane().add(menuBar);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new FlowLayout());
//getContentPane().add(j);
setJMenuBar(createMenuBar());
//getContentPane().add(createMenuBar());
}
public JMenuBar createMenuBar()
{
JMenuBar menuBar;
JMenu m_file;
JMenuItem mi_save;
JMenuItem mi_load;
JMenu m_edit;
JMenuItem mi_tileHeight;
JMenuItem mi_tileWidth;
menuBar = new JMenuBar();
m_file = new JMenu("File");
m_edit = new JMenu("Edit");
mi_save = new JMenuItem("Save file", KeyEvent.VK_S);
mi_load = new JMenuItem("Load file", KeyEvent.VK_L);
mi_tileHeight = new JMenuItem("Set tile height", KeyEvent.VK_H);
mi_tileWidth = new JMenuItem("Set tile width", KeyEvent.VK_W);
menuBar.add(m_file);
m_file.add(mi_save);
m_file.add(mi_load);
menuBar.add(m_edit);
m_edit.add(mi_tileHeight);
m_edit.add(mi_tileWidth);
return menuBar;
}
public static void main(String[] args) //run
{
selectionFrame sel = new selectionFrame();
sel.setLocationRelativeTo(null);
sel.setSize((int) 400 + (sel.getInsets().left + sel.getInsets().right),(int) 400 + (sel.getInsets().top + sel.getInsets().bottom));
sel.setVisible(true);
sel.setTitle("Tiles/Meta");
sel.setResizable(false);
sel.setFocusable(true);
sel.getContentPane().setSize(sel.getSize());
sel.setLocation((int) sel.getX() - (sel.getWidth()/2),(int) sel.getY() - (sel.getHeight()/2));
sel.setup();
sel.repaint();
}
}
You have an awful lot of extra code there.
public class SelectionFrame extends JFrame
{
Font name;
Font title;
public SelectionFrame()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setJMenuBar(createMenuBar());
}
public JMenuBar createMenuBar()
{
JMenuBar menuBar;
JMenu m_file;
JMenuItem mi_save;
JMenuItem mi_load;
JMenu m_edit;
JMenuItem mi_tileHeight;
JMenuItem mi_tileWidth;
menuBar = new JMenuBar();
m_file = new JMenu("File");
m_edit = new JMenu("Edit");
mi_save = new JMenuItem("Save file", KeyEvent.VK_S);
mi_load = new JMenuItem("Load file", KeyEvent.VK_L);
mi_tileHeight = new JMenuItem("Set tile height",
KeyEvent.VK_H);
mi_tileWidth = new JMenuItem("Set tile width",
KeyEvent.VK_W);
menuBar.add(m_file);
m_file.add(mi_save);
m_file.add(mi_load);
menuBar.add(m_edit);
m_edit.add(mi_tileHeight);
m_edit.add(mi_tileWidth);
return menuBar;
}
public void main( String args[] )
{
SelectionFrame sel = new SelectionFrame();
sel.setLocationRelativeTo(null);
sel.setSize(400 + (sel.getInsets().left + > sel.getInsets().right), 400
+ (sel.getInsets().top + sel.getInsets().bottom));
sel.setTitle("Tiles/Meta");
sel.setResizable(false);
sel.setFocusable(true);
sel.getContentPane().add( new JLabel( "Content", SwingConstants.CENTER),
BorderLayout.CENTER );
sel.setLocation(sel.getX() - (sel.getWidth() / 2), sel.getY() - > (sel.getHeight() / 2));
sel.setVisible(true);
}
}
That shows up with a menu bar and everything. if you add your content to the CENTER of the content pane (by default a border layout), the center automatically fills the whole content area, you don't have to resize anything.
This shows up as a window with a menu bar and everything works fine.
What platform are you doing this on? I'm on Vista, i get what i expect to see.
What Java version are you using? Your menu bar shows up fine in 1.6.0_10 on my system. Try wrapping the body of your main method in an invokeLater() call so that it runs on the correct thread, like so:
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
public void run() {
selectionFrame sel = new selectionFrame();
sel.setLocationRelativeTo(null);
sel.setSize((int) 400 + (sel.getInsets().left + sel.getInsets().right),
(int) 400 + (sel.getInsets().top + sel.getInsets().bottom));
sel.setTitle("Tiles/Meta");
sel.setResizable(false);
sel.setFocusable(true);
sel.getContentPane().setSize(sel.getSize());
sel.setLocation((int) sel.getX() - (sel.getWidth() / 2),
(int) sel.getY() - (sel.getHeight() / 2));
sel.setup();
sel.setVisible(true); // Follow Kendrick's advice too.
}
});
}
Turns out you HAVE to set the JMenuBar inside the JFrame's constructor. I figured this out while looking at the differences between my code, and the marked answers code.
Thank you for your wonderful answer, John Gardner. Without you I would have most likely been stuck for months.
In my case I have tracked down a missing menu bar to a bug where I set the RootPane layout, tsk tsk. The RootPane (see eg http://download.java.net/jdk7/archive/b123/docs/api/javax/swing/JRootPane.html ) controls the layout of the menu bar, so when I changed its layout manager it lost the bar.
Instead, one should use the ContentPane to layout and add components to, eg:
frame.getContentPane().setLayout(...);
frame.getContentPane().add(...);
For future reference... this has nothing to do with the component being visible (as the OP said, the frame is visible but the menu bar is not), I have working code that sets the JMenuBar outside the constructor, and while being swing-thread-safe is Good Practice, it is not the cause of the problem.
sel.setVisible(true);
Should be the last thing you call......
Also, just before the call to sel.setVisible(true); pls invoke sel.pack();
Pls note that instead of setSize it is better to use setPreferredSize, which is leveraged during frame packing.
Not directly relevant to your question, but still -- the use of a good layout manager is a huge time and frustration saviour when using Swing. MigLayout is simply an excellent one-stop layout manager.
When I compile and run it, it shows up with a menu bar with file and edit menu items. Were you expecting more?
Also, capitalize your class- SelectionFrame
EDIT:
One thing I forgot to look at, your code and every answer here is technically wrong. Often, it happens to work, but you are not allowed to do anything with Swing components unless you are in the AWT worker thread.
Normally you don't have to think about the worker thread much because every event that comes from your window will be on the worker thread anyway, but there is a tendency to forget about it when you construct your initial frame--and more often than not it just works anyway.
Sun used to recommend that you can work with components outside the AWT thread until the window has been realized (with either pack() or setVisible(true)) but this is no longer considered safe.
The easiest way to fix this might be for your main to create a swing worker thread before newing your SelectionFrame.
There is only a 50-50 chance this will fix your problem, but you should still take it into consideration whenever working on a GUI.

Categories

Resources