Why won't my JMenuBar show up? - java

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.

Related

Java Swing: Easy task, but I fail

I am not new to Java and OOP but I'm new to swing.
I want to write a software for building pedigrees. That means: right click into the middle of the drawing area and choose "New -> Man". A rectangle appears where I have right-clicked. Then I click on the rectangle and choose "New -> Sibling -> Woman" and the pedigree expands dynamically with a circle that is connected to the rectangle. You get the idea.
Additionally I need to save information for each node of the pedigree. Such as "mutation in gene x: positive".
I thought this must be perfect for OOP. I need every node of my pedigree to be an instance which draws itself into the drawing area. So ... a Jpanel? I extend JPanel, I give that class some attributes (such as "int mutationX = 1") and a method to add itself to the JFrame. At the moment I am only trying to add a rectangle into the middle of the screen via the menu. Easy step for a swing beginner. But the desired rectangle doesn't show up. So basically my questions are:
Am I even following the right approach of solving what I'm trying to achieve?
Why doesn't the rectangle show up?
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class HelloWorld
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Hello World");
JPanel mainpanel = new JPanel();
JScrollPane scroll = new JScrollPane(mainpanel);
frame.add(scroll);
JMenuBar menubar = new JMenuBar();
frame.setJMenuBar(menubar);
JMenu file = new JMenu("File");
menubar.add(file);
JMenuItem exit = new JMenuItem("Exit");
exit.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent ae){
System.exit(0);
}
}
);
file.add(exit);
JMenuItem newMember = new JMenuItem("Add");
newMember.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent ae){
FamilyMember fm = new FamilyMember();
mainpanel.add(fm);
mainpanel.revalidate();
}
}
);
file.add(newMember);
frame.setLocation(400, 100);
frame.setPreferredSize(new Dimension(500,500));
frame.pack();
frame.setVisible(true);
}
}
public class FamilyMember extends JPanel {
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.drawRect(230,80,10,10);
g.setColor(Color.RED);
g.fillRect(230,80,10,10);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(50, 50);
}
}
For the second point (why, a minima, it does not work/show any rectangle), you could take a look at Oracle docs (from more precise to broader concern) :
FlowLayout
Layout managers
Swing panels
In short,
your JPanel instance mainpanel has a FlowLayout as layout manager (which is the default for a new instance)
a flow layout will use each child preferred size
and you force the preferred size of your FamilyMember to 50x50
but you want to draw only south-east of 230,80 which is not in the 50x50 area.
=> it won't show.
For the first point, I'd say first : separate the model from the view.

How to add action to a button?

I am trying to enter an event for JButon I create:
JButton botton1=new JButton("welcom to my show db! lets start");
botton1.setFont(new Font ("Eras Medium ITC",Font.BOLD,20));
this.add(botton1);
JPanel Basic_panel=new JPanel();
Basic_panel.setName("SHOW DB ");
Basic_panel.setBounds(x,y,width,hight);
botton1.addActionListener(this) ;
}
public void actionPerformed(ActionEvent e) {
if (e.getSource()==botton1){
Now I want to enter another JFrame I made, and make the first disappear. How?
For your original question:
How to add action to a button?
you might want to check How to write an Action Listener.
For your second question:
Now I want to enter another JFrame I made, and make the first disappear. How?
please check both approaches :)
Option 1 (Recommended)
If you want to do it the right way, you should use a CardLayout as recommended by #AndrewThompson in his comment above.
I also saw you were using a Null Layout (because of setBounds() method), you might also want to get rid of it, see Why is it frowned upon to use a null layout in Swing? and Null Layout is Evil to know why, insted you should be using a Layout Manager or combinations of them as shown in the following code based on #AndrewThompson's answer (The same that was linked in his comment above) but a bit modified to work with a JFrame instead of a JOptionPane, so give him credit by upvoting his Original Answer too!
This produces the following outputs:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class CardLayoutDemo {
JButton button1, button2;
CardLayoutDemo() {
JFrame gui = new JFrame("CardLayoutDemo");
button1 = new JButton("Go to pane 2");
button2 = new JButton("Go to pane 1");
JPanel pane1 = new JPanel();
pane1.setLayout(new BoxLayout(pane1, BoxLayout.PAGE_AXIS));
JPanel pane2 = new JPanel();
pane2.setLayout(new BoxLayout(pane2, BoxLayout.PAGE_AXIS));
final CardLayout cl = new CardLayout();
final JPanel cards = new JPanel(cl);
pane1.add(new JLabel("This is my pane 1"));
pane1.add(button1);
pane2.add(new JLabel("This is my pane 2"));
pane2.add(button2);
gui.add(cards);
cards.add(pane1, "frame1");
cards.add(pane2, "frame2");
ActionListener al = new ActionListener(){
public void actionPerformed(ActionEvent ae) {
if (ae.getSource() == button1) {
cl.show(cards, "frame2");
} else if (ae.getSource() == button2) {
cl.show(cards, "frame1");
}
}
};
button1.addActionListener(al);
button2.addActionListener(al);
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.pack();
gui.setVisible(true);
}
public static void main(String[] args) {
new CardLayoutDemo();
}
}
With this option you only have 1 JFrame but you can change through different views, and you don't annoy user with multiple windows on the task bar.
One more tip here is: If you're going to open this second JFrame to prevent user from doing something on the 1st one, you should consider using a JOptionPane or this second JFrame will contain just a bit information which you don't want to have there for the whole time (Something like a pop up).
Option 2 (Not recommended)
But if you really really really want to use multiple JFrames (which is not recommended) you can dispose() it. At the time you're calling your new JFrame to be created. For example, the following code produces this output:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class TwoJFrames {
JFrame frame;
JButton button;
TwoJFrames() {
frame = new JFrame("1st frame");
button = new JButton("Click me!");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
new AnotherFrame();
frame.dispose();
}
});
frame.add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String args[]) {
new TwoJFrames();
}
class AnotherFrame {
JFrame frame2;
JLabel label;
AnotherFrame() {
frame2 = new JFrame("Second Frame");
label = new JLabel("This is my second frame");
frame2.add(label);
frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame2.pack();
frame2.setVisible(true);
}
}
}
In this case you might want to consider setVisible() instead if you want to go back to previous state or reopen this one when closing the second JFrame
Both of my above codes are called a Minimal, Complete, and Verifiable example (MCVE) or Runnable Example or Short, Self Contained, Correct Example (SSCCE) which are code you can copy-paste and see the same output as me, when you have an error in your code, these examples are very handy because we can see where your errors are or be able to find them easier and/or faster.
You should consider reading all the links I provided (included these ones) and for your future questions to make something like I've done above, that way you'll prevent confusion and you'll get more, faster and better responses.

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

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

How to display a menu and a panel in the same window in Java Swing?

I've got a JMenu and I want to change the window's content according to what button from the menu is pressed. I managed to show the panel as a popup, but I want it to be displayed in the same window with the menu. This is my code so far :
public class GUImenu extends JFrame
{
private JMenuBar menuBar;
private JMenu menu;
private JMenu subMenu;
private JMenuItem item1;
private JMenuItem item2;
private JMenuItem item3;
private JMenuItem item4;
private JMenuItem item5;
private JMenuItem item6;
public GUImenu()
{
super("Example Menu System");// Call the JFrame constructor.
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Specify an action for the close button.
buildMenuBar();
// Pack and display the window.
pack();
setSize(1000, 250); // set frame size
setVisible(true);
}
private void buildMenuBar()
{
// Create the menu bar.
menuBar = new JMenuBar();
// Create the file and text menus.
menu = new JMenu("Menu"); menuBar.add(menu);
subMenu = new JMenu("Create Customer");
item1 = new JMenuItem("Ordinary Customer"); subMenu.add(item1);
item1.addActionListener(new showOrdinaryCust());
item6 = new JMenuItem("Privileged Customer"); subMenu.add(item6);
menu.add(subMenu);
item2 = new JMenuItem("View Customers Who Didn't Pay"); menu.add(item2);
item3 = new JMenuItem("Remove Client");menu.add(item3);
item4 = new JMenuItem("Create Order"); menu.add(item4);
item5 = new JMenuItem("Search..."); menu.add(item5);
setJMenuBar(menuBar);
}
public static void main(String[] args)
{
new GUImenu();
}
private class showOrdinaryCust implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
if(event.getSource()==item1)
GUIpanel.main(null);
}
}
}
I would try to fill the entire window with a CardLayout. CardLayout is meant to switch its contents between separate views. Simply set up multiple cards for each of the panels you want to show and have the menu switch between them.
If you use windows or dialogs you will latter have to deal with the focus, the closing, minimizing, maximizing, re-size, centering, visibility...
In your case i would recommend you to pick a good layout to suit your needs(Probably the easiest way to achieve your goal).
What do you think about tabbed panes?
See this link: http://docs.oracle.com/javase/tutorial/uiswing/components/tabbedpane.html
building guis is a little complex, but worth the time spent to understand what options are. This is a good place to start as it explains various java gui layouts, including using a layout manager. http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html.
For future posts, your example should be complete, including imports so we can copy and paste code, compile and look at.
It is simple enough. I have implemented this thing as follows :
First get content pane of your JFrame, say in container. Make this container object static.
private static Container container;
now get content pane.
container = this.getContentPane();
Now on click on menu call some method that will do some thing like this :
container.removeAll();
container.add(new JPanel()); //Add object of your panel you want to show.
container.revalidate();
This method is helpful in case you want to show multiple panels in same JFrame.

Why does Windows LookAndFeel make fonts too small?

The native Windows LookAndFeel in Java 6 seems to incorrectly size some fonts.
Test program:
import java.awt.*;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class Test {
public static void main(String[] arg) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (Exception e) {
e.printStackTrace();
}
final JMenuBar mb = new JMenuBar();
final JMenu file = new JMenu("File");
file.setMnemonic(KeyEvent.VK_F);
mb.add(file);
final JToolBar toolbar = new JToolBar();
final JButton button = new JButton("Button");
toolbar.add(button);
final JLabel label = new JLabel("Basic Colors");
final JPanel panel = new JPanel(new BorderLayout());
panel.add(toolbar, BorderLayout.PAGE_START);
panel.add(label, BorderLayout.CENTER);
final JFrame frame = new JFrame();
frame.setJMenuBar(mb);
frame.add(panel);
frame.setTitle("Test");
frame.setSize(400,200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
Output, compared with a native Windows app on Vista:
While the text in the test app menu bar is sized correctly, the rest of the text is smaller than in the native app next to it. Zoomed in, you can see that the text in the test app JLabel is 1px shorter than in the native app:
Is this a bug in the Windows LaF, or are we misusing it? If it's a bug, is there a known workaround?
Java 6 uses its own font renderer, including the implementation of subpixel antialiasing / hinting whatsit. While the output is meant to be similar to Windows' rendering, either the top of the B being at a pixel boundary, or it being rounded, or both, throws the Java renderer off. The Windows font renderer decides to place the top of the letter above the boundary, while the Java one places it below. The 'l' looks like it's at the same height in both samples, so it doesn't seem like the renderer gets the height of every letter wrong. Maybe try comparing with some letters where the top is a straight line, like a T or an E?

Categories

Resources