JonDoeMaths
JonDoeMaths

Reputation: 23

Draw Rectangle on pressing JButton

I am currently working on a little game but I just encountered a problem:

I have three classes, the first one is the JFrame:

public class Game 
{

    public static void main(String[] args)
    {
        new Game().gui();
    }


    public void gui()
    {
        DrawPanel panel = new DrawPanel();
        JFrame frame = new JFrame("Test");
        //frame.add(panel); 
        frame.add(new MainMenu());
        frame.setSize(800, 700);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
    }
}

Now I have two other classes, one is the mainMenu, currently consisting of just one JButton. I decided to make the menu its own class because later, I want to call the menu by pressing escape, but the problem is that (for testing reasons) I want to draw an rectangle when "start" is pressed. I tried different approaches but nothing happens.

public class MainMenu extends JPanel implements ActionListener
{

     GamePanel panel = new GamePanel();

     public MainMenu()
     {

         setLayout(new GridBagLayout());
         GridBagConstraints c = new GridBagConstraints();

         JButton b1 = new JButton("Start");
         c.fill = GridBagConstraints.HORIZONTAL;
         c.ipadx = 200;

         b1.addActionListener(new ActionListener()
         {
            @Override
            public void actionPerformed(ActionEvent e) {
                setVisible(false);
            }
         });
         add(b1, c);

     }

}


public class DrawPanel extends JPanel
{

     public void paint(Graphics g) 
          {
            g.drawRect (10, 10, 200, 200);  
          }

}

Upvotes: 0

Views: 1312

Answers (1)

Frakcool
Frakcool

Reputation: 11163

There are several errors I found in your code:

  1. You're not adding your DrawPanel to anything because this line

    frame.add(panel); 
    

    is commented, so, that leads us to the next problem:

  2. You're overriding paint() method instead of paintComponent() and also don't forget to call

    super.paintComponent();
    

    at the very beginning of the method. Without it, you're preventing your code to keep painting the rest of the components. See Custom painting in Swing

  3. That still doesn't makes anything appear because you haven't declared a location for your DrawPanel and thus it's taking JFrame's default Layout Manager which is BorderLayout and it's default location when not specified is CENTER, and as you're adding new MainMenu() to it on the same position it replaces the DrawPanel panel, since only one component can exist on the same position.

    Instead try and place the DrawPanel to the CENTER and the MainMenu to the SOUTH. It now should look like this:

    enter image description here

  4. Don't forget to place your program on the Event Dispatch Thread (EDT) by writing your main method as follows:

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                //Your constructor here
            }
        });
    }
    
  5. You're implementing ActionListener on MainMenu but not implementing it's methods, remove it or implement the actionPerformed method and move the code inside the b1 action listener to it. However I highly recommend you to take at Should your class implement ActionListener or use an object of an anonymous ActionListener class too

  6. You're playing with MainMenu's JPanel visibility, instead you should try using a CardLayout or consider using JDialogs.

    For example I would make a JDialog and place the JButton there, so it will open the JFrame with the Rectangle drawn in it.

Now, the code that made the above output and follows all recommendations (but #6) is:

import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Game {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Game().gui();
            }
        });
    }

    public void gui() {
        DrawPanel panel = new DrawPanel();
        JFrame frame = new JFrame("Test");
        frame.add(panel, BorderLayout.CENTER);
        frame.add(new MainMenu(), BorderLayout.SOUTH);
        frame.setSize(400, 300);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
    }
}

class MainMenu extends JPanel  {

//  GamePanel panel = new GamePanel();

    public MainMenu() {

        setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();

        JButton b1 = new JButton("Start");
        c.fill = GridBagConstraints.HORIZONTAL;
        c.ipadx = 200;

        b1.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                setVisible(false);
            }
        });
        add(b1, c);
    }
}

class DrawPanel extends JPanel {

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawRect(10, 10, 200, 200);
    }
}

As suggested in the comments by @MadProgrammer, you can also override the getPreferredSize() method of your DrawPanel and then call frame.pack():

Your DrawPanel class should now look like this:

class DrawPanel extends JPanel {

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawRect(10, 10, 200, 200);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(400, 300);
    }
}

Upvotes: 1

Related Questions