views:

157

answers:

3
+1  Q: 

Fickle JMenuBar

I ran the following code 10 times. Of the 10 runs, 3 showed both the menu bar and the rectangle, 3 showed only the rectangle, and 4 showed nothing at all. What am I doing wrong?

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import static java.awt.Color.*;
import java.awt.image.*;


public class GUI extends JFrame implements KeyListener, ActionListener
{
    int x, y;
    public static void main(String[] args)
    {
        new GUI();
    }
    public GUI()
    {
        try
        {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e)
        {
            e.printStackTrace();
        }       
        frameInit();
        setSize(1024,768);
        setDefaultCloseOperation(EXIT_ON_CLOSE);;
        setVisible(true);
        setJMenuBar(createMenuBar());
        addKeyListener(this);
        createBufferStrategy(2);
        x = 0;
        y = 49;
    }
    public void paint(Graphics gm)
    {
        BufferStrategy bs = getBufferStrategy();
        try
        {
            Graphics g = bs.getDrawGraphics(); 
            super.paint(g);
            g.setColor(WHITE);
            g.drawRect(0,0,1024,768);
            g.setColor(BLACK);
            g.fillRect(x,y,100,100);
            bs.show();
        }catch(Exception e)
        {

        }
    }
    public JMenuBar createMenuBar()
    {
        JMenuBar menuBar = new JMenuBar();
        JMenu fileMenu = new JMenu("File");
        fileMenu.setMnemonic(KeyEvent.VK_F);
        JMenuItem save = new JMenuItem("Save");
        save.setMnemonic(KeyEvent.VK_S);
        save.addActionListener(this);
        JMenuItem load = new JMenuItem("Load");
        load.setMnemonic(KeyEvent.VK_L);
        load.addActionListener(this);
        JMenuItem quit = new JMenuItem("Quit");
        quit.setMnemonic(KeyEvent.VK_Q);
        quit.addActionListener(this);
        fileMenu.add(save);
        fileMenu.add(load);
        fileMenu.addSeparator();
        fileMenu.add(quit);
        JMenu editMenu = new JMenu("Edit");
        editMenu.setMnemonic(KeyEvent.VK_E);
        JMenuItem undo = new JMenuItem("Undo");
        undo.setMnemonic(KeyEvent.VK_U);
        undo.addActionListener(this);
        JMenuItem redo = new JMenuItem("Redo");
        redo.setMnemonic(KeyEvent.VK_R);
        redo.addActionListener(this);
        editMenu.add(undo);
        editMenu.add(redo);
        JMenu helpMenu = new JMenu("Help");
        helpMenu.setMnemonic(KeyEvent.VK_H);
        JMenuItem controls = new JMenuItem("Controls");
        controls.setMnemonic(KeyEvent.VK_C);
        controls.addActionListener(this);
        JMenuItem about = new JMenuItem("About");
        about.setMnemonic(KeyEvent.VK_A);
        about.addActionListener(this);
        helpMenu.add(controls);
        helpMenu.addSeparator();
        helpMenu.add(about);
        menuBar.add(fileMenu);
        menuBar.add(editMenu);
        menuBar.add(helpMenu);
        menuBar.setLocation(0,23);
        return menuBar;
    }
    public void actionPerformed(ActionEvent e)
    {
        System.out.println(e.getActionCommand());
        repaint();
    }
    public void keyPressed(KeyEvent e)
    {
        if(e.getKeyCode()==KeyEvent.VK_UP)
        {
            y-=10;
        }
        if(e.getKeyCode()==KeyEvent.VK_DOWN)
        {
            y+=10;
        }
        if(e.getKeyCode()==KeyEvent.VK_LEFT)
        {
            x-=10;
        }
        if(e.getKeyCode()==KeyEvent.VK_RIGHT)
        {
            x+=10;
        }
        repaint();
    }
    public void keyReleased(KeyEvent e)
    {
    }
    public void keyTyped(KeyEvent e)
    {       
    }

}
A: 

First of all you're using bad brace style. But well that's not the problem here.

On line 48 you're ignoring the exception:

try {

} catch(Exception e) {

}

If you add this:

e.printStackTrace();

It will tell you what the problem is, when I ran it it said:

java.lang.NullPointerException
at GUI.paint(GUI.java:41)
at sun.awt.RepaintArea.paintComponent(RepaintArea.java:276)
at sun.awt.RepaintArea.paint(RepaintArea.java:241)
at apple.awt.ComponentModel.handleEvent(ComponentModel.java:263)

GUI.java at line 41 is:

BufferStrategy bs = getBufferStrategy();
try {
    Graphics g = bs.getDrawGraphics(); // <--- this line

Here your bs variable is null, the method getBufferStrategy returned null instead of a valid object reference. Why? I don't know, you answer me. What's that getBufferStrategy all about?

But at least from there what I see is that your're getting a NullPointerException try adding that printStackTrace to see what's printing for you. don't just ignore them

OscarRyz
BufferStrategy is class that allows for multi-buffering in JFramegetBufferStrategy is the JFrame method to allow you to get the BufferStrategy (assuming you created one) of a particular JFrame, and then getDrawGraphics allows you to get the Graphics object associated with that BufferStrategy (or at least, thats my primitive understanding of it)the NullPointerException occurs b/c of something about painting in dirty regionsany idea on how i could fix that problem
resotpvl
A: 

There are a bunch of errors in your code. Numero uno is that you shouldn't be overriding the JFrame's paint() method. You should, instead, create some JComponent, implement its paintComponent method, then add() that component to your JFrame's contentPane.

Edit: Oscar's comments are all good, too!

Jonathan Feinberg
Indeed, actually you should not subclass JFrame in first place! Your code is not really a JFrame subclass, you're just using it.
OscarRyz
+1  A: 

Since you're overriding the way the JFrame is painted you are simply ignoring the JMenu bar painting completely.

Don't subclass JFrame, use a custom component, here's a quick edit of your code, without thinking too much about it, I've just move some pieces.

It works 100% of the times for me:

it works fine like this

//I ran the following code 10 times. Of the 10 runs, 3 showed both the menu bar and the rectangle, 3 showed only the rectangle, and 4 showed nothing at all. What am I doing wrong?

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import static java.awt.Color.*;
import java.awt.image.*;


public class GUI extends JComponent implements KeyListener, ActionListener {
    private int x, y;
    public static void main(String[] args) {
        setLnF();
        // Don't subclass it just use it.
        JFrame frame = new JFrame();
        //frameInit();
        frame.setSize(1024,768);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //frame.setVisible(true);

        GUI gui = new GUI();

        frame.setJMenuBar(gui.createMenuBar());
        frame.addKeyListener( gui );    
        frame.add( gui ) ;
        frame.setVisible(true); // should be the last thing to call


    }
    private static void setLnF() {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch( InstantiationException ie ) {
            ie.printStackTrace();
        } catch( IllegalAccessException iae ) {
            iae.printStackTrace();
        } catch( UnsupportedLookAndFeelException u ) {
            u.printStackTrace();
        }
    }
    public GUI() {
        //createBufferStrategy(2);
        x = 0;
        y = 49;
    }
    public void paint(Graphics gm) {
        //BufferStrategy bs = getBufferStrategy();
        try {
            Graphics g = gm; // bs.getDrawGraphics(); 
            super.paint(g);
            g.setColor(WHITE);
            g.drawRect(0,0,1024,768);
            g.setColor(BLACK);
            g.fillRect(x,y,100,100);
            //bs.show();
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
    public JMenuBar createMenuBar() {
        JMenuBar menuBar = new JMenuBar();
        JMenu fileMenu = new JMenu("File");
        fileMenu.setMnemonic(KeyEvent.VK_F);
        JMenuItem save = new JMenuItem("Save");
        save.setMnemonic(KeyEvent.VK_S);
        save.addActionListener(this);
        JMenuItem load = new JMenuItem("Load");
        load.setMnemonic(KeyEvent.VK_L);
        load.addActionListener(this);
        JMenuItem quit = new JMenuItem("Quit");
        quit.setMnemonic(KeyEvent.VK_Q);
        quit.addActionListener(this);
        fileMenu.add(save);
        fileMenu.add(load);
        fileMenu.addSeparator();
        fileMenu.add(quit);
        JMenu editMenu = new JMenu("Edit");
        editMenu.setMnemonic(KeyEvent.VK_E);
        JMenuItem undo = new JMenuItem("Undo");
        undo.setMnemonic(KeyEvent.VK_U);
        undo.addActionListener(this);
        JMenuItem redo = new JMenuItem("Redo");
        redo.setMnemonic(KeyEvent.VK_R);
        redo.addActionListener(this);
        editMenu.add(undo);
        editMenu.add(redo);
        JMenu helpMenu = new JMenu("Help");
        helpMenu.setMnemonic(KeyEvent.VK_H);
        JMenuItem controls = new JMenuItem("Controls");
        controls.setMnemonic(KeyEvent.VK_C);
        controls.addActionListener(this);
        JMenuItem about = new JMenuItem("About");
        about.setMnemonic(KeyEvent.VK_A);
        about.addActionListener(this);
        helpMenu.add(controls);
        helpMenu.addSeparator();
        helpMenu.add(about);
        menuBar.add(fileMenu);
        menuBar.add(editMenu);
        menuBar.add(helpMenu);
        menuBar.setLocation(0,23);
        return menuBar;
    }
    public void actionPerformed(ActionEvent e) {
        System.out.println(e.getActionCommand());
        repaint();
    }
    public void keyPressed(KeyEvent e) {
        if(e.getKeyCode()==KeyEvent.VK_UP) {
            y-=10;
        }
        if(e.getKeyCode()==KeyEvent.VK_DOWN) {
            y+=10;
        }
        if(e.getKeyCode()==KeyEvent.VK_LEFT) {
            x-=10;
        }
        if(e.getKeyCode()==KeyEvent.VK_RIGHT) {
            x+=10;
        }
        repaint();
    }
    public void keyReleased(KeyEvent e) {
    }
    public void keyTyped(KeyEvent e) {      
    }

}

EDIT

Your problem is here:

    frameInit();
    setSize(1024,768);
    setDefaultCloseOperation(EXIT_ON_CLOSE);;
    setVisible(true); //<-- exaaaactly here!!
    setJMenuBar(createMenuBar());
    addKeyListener(this);
    createBufferStrategy(2);

Just move that line to the end and it should work fine.

    frameInit();
    setSize(1024,768);
    setDefaultCloseOperation(EXIT_ON_CLOSE);;
    ///setVisible(true); //<-- exaaaactly here!!
    setJMenuBar(createMenuBar());
    addKeyListener(this);
    createBufferStrategy(2);
    setVisible( true );

What I said about subclassing JFrame is still valid.

OscarRyz
just out of curiosity, what's so bad about sub-classing JFrame
resotpvl
Because by inheriting you're tying your class very deeply to the JFrame and in this case that's now necessary. You should inherit ( subclass ) when you're redefining the behavior of a class, when the functionality changes, not only when the data changes. In this example, you're just using the JFrame and there is no reason to inherit it. Also inheritance makes more difficult to perform unit testing ( because to test your code you have to create a JFrame always ) while using composition you may test separately your functionality. Inheritance has it's place in OOP but should not be abused.
OscarRyz