2

I'm having trouble getting my JMenuBar to appear alongside my paint() method.

package Main;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;

public class Main extends JFrame{

int x, y; // axis position for oval

//JMenuBar Variables
JMenuBar menuBar;
JMenu file;
JMenuItem newGame;
JMenuItem checkScore;
JMenuItem exitGame;

// DOUBLE BUFFERING
private Image dbImage;
private Graphics dbGraphics;

Font font = new Font("Arial", Font.ITALIC, 30);

// KeyListener Class
public class KeyListener extends KeyAdapter {
    public void keyPressed(KeyEvent e){
        int keyCode = e.getKeyCode();
        if(keyCode == e.VK_LEFT){
            if(x <=0){ // FRAME COLLISION DETECTION 
                x=0;
            }else
            x += -5; //decrement position to the left 
        }
        if(keyCode == e.VK_RIGHT){
            if(x >= 380){
                x = 380;
            }else
            x += +5; //incrementing position to the right
        }
        if(keyCode == e.VK_UP){
            if (y <= 25){
                y = 25;
            }else
            y += -5; //decrementing position up
        }
        if(keyCode == e.VK_DOWN){
            if(y >= 380){
                y = 380;
            }else
            y += +5; //incrementing position down
        }
    }
}


// CONSTRUCTOR
public Main(){
// Window Properties
    addKeyListener(new KeyListener()); // creates instance of KeyListener class
    setTitle("Tower Defence");
    setSize(400, 400);
    setResizable(false);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    //setBackground(Color.CYAN);


// JMenuBar
    menuBar = new JMenuBar();
    file = new JMenu("File");
    newGame = new JMenuItem("New Game");
    checkScore = new JMenuItem("Check High Scores");
    exitGame = new JMenuItem("Close Game");

    menuBar.add(file);
    file.add(newGame);
    file.add(checkScore);
    file.addSeparator();
    file.add(exitGame);
    setJMenuBar(menuBar);

// Display frame after all components added
    setVisible(true);

// default position for oval
    x = 150;
    y = 150;

}


public void paint(Graphics g){
    dbImage = createImage(getWidth(), getHeight()); // creates image of screen
    dbGraphics = dbImage.getGraphics(); // gets graphics to be drawn in off screen image
    paintComponent(dbGraphics); // paints graphics
    g.drawImage(dbImage, 0, 0, this);  // draw image to the visible screen
}

    // PAINT GRAPHICS TO SCREEN
public void paintComponent(Graphics g){

    g.setFont(font);
    g.drawString("Hello World", 100, 200);

    g.setColor(Color.red);
    g.drawOval(x, y, 15, 15);
    g.fillOval(x, y, 15, 15);
    repaint();
}


// MAIN METHOD
public static void main(String[] args) {
    new Main();
}

}

I saw a different question where the solution was to override the paint method and add super.paint(g); when i tried this the JMenuBar appears but the frame keeps flickering constantly.

mKorbel
  • 109,525
  • 20
  • 134
  • 319
Sawyer05
  • 1,604
  • 2
  • 22
  • 37
  • 2
    I suggest that you go through one of the graphics tutorials because it appears that you're guessing at some of this and are doing quite a few things wrong, including drawing directly on the JFrame, not calling the super method calling repaint() from within a paint method. Don't guess -- check out the tut's as they'll show you the proper way to do this. Please start here: [Lesson: Performing Custom Painting](http://docs.oracle.com/javase/tutorial/uiswing/painting/index.html) and then check this link here: [Painting in AWT and Swing](http://www.oracle.com/technetwork/java/painting-140037.html) – Hovercraft Full Of Eels Dec 12 '12 at 18:08
  • I've been following tutorials on youtube, probably not the best idea.. – Sawyer05 Dec 12 '12 at 18:11
  • 1
    Please check my links. Also you don't want to do background/buffer painting in paint or paintComponent as it defeats the purpose of background painting. You should be drawing in a component that derives ultimately from JComponent such as a JPanel or JComponent itself, you should override paintComponent, not paint, you should call the super method,... – Hovercraft Full Of Eels Dec 12 '12 at 18:11
  • 1
    Your flicker comes from your poor attempt at double buffering and that you're calling repaint from paint or paintComponent. Why not use a Swing Timer for the game loop and use Swing graphics of a JComponent's paintComponent method that has automatic double buffering? – Hovercraft Full Of Eels Dec 12 '12 at 18:16
  • 1
    I was following TheJavaHub's beginners game development tutorials on youtube, im comfortable writing applications, with just buttons and text, etc but i don't know anything about Graphics, i will check out your links..Thanks for the info – Sawyer05 Dec 12 '12 at 18:23
  • again SO isn't code generator, did your read tutorials, tried code examples from tutorial, – mKorbel Dec 12 '12 at 18:25
  • @mKorbel, at no point did i ask for a "code generator", I asked about a specific problem, which i researched beforehand and could not find the answer. perhaps you should go read the two first sections here http://stackoverflow.com/faq and tell me how my question does not fit the rules. – Sawyer05 Dec 13 '12 at 15:39

2 Answers2

4
  • Dont extend JFrame unnecessarily

  • Dont overide any paint method of JFrame unnecessarily rathe add Jpanel and override paintComponent

  • Dont call repaint(...) in paintComponent(...) as this will cause a loop i.e repaint will re-call paintComponent and the cycle will carry on

  • Create and manipulate Swing components on Event Dispatch Thread

  • Dont call setSize(..) on JFrame rather override getPreferredSize and return an appropriate size which fits all drawings and than call JFrame#pack() before setting JFrame visible

  • Dont use KeyListener/KeyAdapter for Swing components rather use KeyBindings

Here is your code fixed:

enter image description here

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

public class Main extends JPanel {

    int x, y; // axis position for oval
    //JMenuBar Variables
    JMenuBar menuBar;
    JMenu file;
    JMenuItem newGame;
    JMenuItem checkScore;
    JMenuItem exitGame;
    Font font = new Font("Arial", Font.ITALIC, 30);

    // KeyBindings Class
    public class KeyBindings {

        public KeyBindings(final JComponent jc) {
            jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "Right");
            jc.getActionMap().put("Right", new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent ae) {
                    if (x >= 380) {
                        x = 380;
                    } else {
                        x += +5; //incrementing position to the right
                    }
                    jc.repaint();

                }
            });

            jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "Left");
            jc.getActionMap().put("Left", new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent ae) {
                    if (x <= 0) { // FRAME COLLISION DETECTION 
                        x = 0;
                    } else {
                        x += -5; //decrement position to the left 
                    }
                    jc.repaint();

                }
            });
            jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "Up");
            jc.getActionMap().put("Up", new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent ae) {
                    if (y <= 25) {
                        y = 25;
                    } else {
                        y += -5; //decrementing position up
                    }
                    jc.repaint();

                }
            });
            jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "Down");
            jc.getActionMap().put("Down", new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent ae) {
                    if (y >= 380) {
                        y = 380;
                    } else {
                        y += +5; //incrementing position down
                    }
                    jc.repaint();

                }
            });
        }
    }

    // CONSTRUCTOR
    public Main() {
        // Window Properties
        JFrame frame = new JFrame();
        frame.setTitle("Tower Defence");
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //setBackground(Color.CYAN);


        // JMenuBar
        menuBar = new JMenuBar();
        file = new JMenu("File");
        newGame = new JMenuItem("New Game");
        checkScore = new JMenuItem("Check High Scores");
        exitGame = new JMenuItem("Close Game");

        menuBar.add(file);
        file.add(newGame);
        file.add(checkScore);
        file.addSeparator();
        file.add(exitGame);

        JPanel panel = new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2 = (Graphics2D) g;
                g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

                g.setFont(font);
                g.drawString("Hello World", 100, 200);

                g.setColor(Color.red);
                g.drawOval(x, y, 15, 15);
                g.fillOval(x, y, 15, 15);
            }

            @Override
            public Dimension getPreferredSize() {
                return new Dimension(400, 400);
            }
        };
        //add keybindings
        new KeyBindings(panel);

        frame.add(panel);

        frame.setJMenuBar(menuBar);

        frame.pack();
        // Display frame after all components added
        frame.setVisible(true);

        // default position for oval
        x = 150;
        y = 150;

    }

    // MAIN METHOD
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Main();
            }
        });
    }
}
David Kroukamp
  • 36,155
  • 13
  • 81
  • 138
4

Heck, I'll throw my code in the ring. Recs as per my comments. Also, don't use KeyListeners but rather Key Bindings.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.RenderingHints;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.*;

@SuppressWarnings("serial")
public class Main2 extends JPanel {
   private static final int PREF_W = 400;
   private static final int PREF_H = PREF_W;
   private static final int OVAL_W = 15;
   private int x = 150;
   private int y = 150;
   private JMenuBar menuBar;
   private JMenu file;
   private JMenuItem newGame;
   private JMenuItem checkScore;
   private JMenuItem exitGame;
   private Font font = new Font("Arial", Font.ITALIC, 30);

   public Main2() {      
      menuBar = new JMenuBar();
      file = new JMenu("File");
      newGame = new JMenuItem("New Game");
      checkScore = new JMenuItem("Check High Scores");
      exitGame = new JMenuItem("Close Game");

      menuBar.add(file);
      file.add(newGame);
      file.add(checkScore);
      file.addSeparator();
      file.add(exitGame);

      addKeyBinding();
   }

   public JMenuBar getMenuBar() {
      return menuBar;
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2 = (Graphics2D) g;
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
            RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, 
            RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
      g.setFont(font);
      g.drawString("Hello World", 100, 200);

      g.setColor(Color.red);
      g.drawOval(x, y, OVAL_W, OVAL_W);
      g.fillOval(x, y, OVAL_W, OVAL_W);
   }

   private void addKeyBinding() {
      int condition = WHEN_IN_FOCUSED_WINDOW;
      InputMap inputMap = getInputMap(condition);
      ActionMap actionMap = getActionMap();

      for (final MyDirection dir : MyDirection.values()) {
         KeyStroke keyStroke = KeyStroke.getKeyStroke(dir.getKeyCode(), 0);
         inputMap.put(keyStroke, dir.toString());
         actionMap.put(dir.toString(), new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent evt) {
               int newX = x + dir.getxTrans();
               int newY = y + dir.getyTrans();

               newX = Math.min(newX, PREF_W - 2 * OVAL_W);
               newX = Math.max(newX, OVAL_W);
               newY = Math.min(newY, PREF_H - 2 * OVAL_W);
               newY = Math.max(newY, OVAL_W);

               x = newX;
               y = newY;
               repaint();
            }
         });
      }
   }

   enum MyDirection {
      UP(KeyEvent.VK_UP, 0, -5), DOWN(KeyEvent.VK_DOWN, 0, 5), 
      LEFT(KeyEvent.VK_LEFT, -5, 0), RIGHT(KeyEvent.VK_RIGHT, 5, 0);

      private int keyCode;
      private int xTrans;
      private int yTrans;

      private MyDirection(int keyCode, int xTrans, int yTrans) {
         this.keyCode = keyCode;
         this.xTrans = xTrans;
         this.yTrans = yTrans;
      }

      public int getKeyCode() {
         return keyCode;
      }

      public int getxTrans() {
         return xTrans;
      }

      public int getyTrans() {
         return yTrans;
      }


   }

   private static void createAndShowGui() {
      Main2 main = new Main2();

      JFrame frame = new JFrame("Main2");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(main);
      frame.setJMenuBar(main.getMenuBar());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • +1 I saw OP never even used KeyListener yet so left that out. +1 for the extra mile – David Kroukamp Dec 12 '12 at 18:44
  • Thanks Hovercraft, there's quite a bit of stuff thats completely new to me in there, just tested it and its working great for me, i'll have a look over it, thanks again for the help! – Sawyer05 Dec 12 '12 at 18:45
  • Using the KeyListener or the Key Bindings as the game loop isn't elegant. Better to use a Swing Timer and then change direction based on the key binding action. – Hovercraft Full Of Eels Dec 12 '12 at 18:46
  • Is there a disadvantage to using KeyListener rather than Key Bindings? – Sawyer05 Dec 12 '12 at 18:48
  • @Sawyer05 `KeyListener` has know focus issues with Swing, thus you may not have focus when expected and thus no Key events are recieved – David Kroukamp Dec 12 '12 at 18:50
  • Thanks for the info guys, im following the lessons on the oracle website and im slowly beginning to understand what all your code means! – Sawyer05 Dec 12 '12 at 18:55
  • 1
    Key binding are also easier to remap in preferences. – trashgod Dec 12 '12 at 22:21