6

I'm making a tank game and to avoid redundancy I'm making classes to extend. My MenuPanel looks like this atm (I've only written the code that matters for the question) (knop = dutch for button)

public class MenuPanel extends JPanel implements ActionListener
{

    private JButton playKnop, highScoreKnop, quitKnop, HTPKnop;
    private ImageIcon play, HS, quit, HTP;
    private Tanks mainVenster;

    public MenuPanel(Tanks mainVenster) 
    {
        this.mainVenster = mainVenster;
        this.setLayout(null); 

        int x = 95; 
        int width = 200; 
        int height = 50;    


        play = new ImageIcon(PlayPanel.class.getResource(/buttons/PLAY.png));
        playKnop = new JButton(play);
        playKnop.setBounds(x, y, width, height);
        playKnop.addActionListener(this);

        HS = new ImageIcon(PlayPanel.class.getResource(/buttons/HS.png));
        highScoreKnop = new JButton(HS);
        highScoreKnop.setBounds(x, 460, width, height);
        highScoreKnop.addActionListener(this);

        HTP = new ImageIcon(PlayPanel.class.getResource(/buttons/HTP.png));
        HTPKnop = new JButton(HTP);
        HTPKnop.setBounds(x, 515, width, height);
        HTPKnop.addActionListener(this);

        quit = new ImageIcon(PlayPanel.class.getResource(/buttons/QUIT.png));
        quitKnop = new JButton(quit);
        quitKnop.setBounds(x, 570, width, height);
        quitKnop.addActionListener(this);

        this.add(playKnop);
        this.add(quitKnop);
        this.add(HTPKnop);
        this.add(highScoreKnop);

        validate();
    }
}

because the code to make the buttons is exactly the same (except for the backgroundPath and the y-coordinate) I made a class button:

package menu;

import java.awt.Image;
import java.awt.event.ActionListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;

public class button 
{


    public JButton button;
    public ImageIcon buttonImage;

    public int x = 95;
    public int width = 200;
    public int height = 50;

    public String backgroundPath;
    public int y;



    public button(String backgroundPath, int y)
    {
        this.backgroundPath = backgroundPath;
        this.y = y;

        buttonImage = new ImageIcon(PlayPanel.class.getResource(backgroundPath));
        button = new JButton();
        button.setBounds(x, y, width, height);;
        button.addActionListener(this); 
    }



}

that way, my menuPanel COULD look like this:

    package menu;

    @SuppressWarnings("serial")
    public class MenuPanel extends JPanel implements ActionListener
    {

    private button playKnop, highScoreKnop, quitKnop, HTPKnop;
    private JTextField naam;
    private Tanks mainVenster;



    public MenuPanel(Tanks mainVenster) 
    {
        this.mainVenster = mainVenster;
        this.setLayout(null);       

        playKnop = new button("/buttons/PLAY.png", 350);        
        highScoreKnop = new button("/buttons/HS.png", 460);
        quitKnop = new button("/buttons/QUIT.png", 515);
        HTPKnop = new button("/buttons/HTP.png", 570);


        this.add(playKnop);
        this.add(quitKnop);
        this.add(HTPKnop);
        this.add(highScoreKnop);


        validate();

    }


}

I don't know why, but when I do this the buttons won't appear, although the code from the button class is correct (bc when I use the code in the menuPanel itself it works)

I don't know how to fix this problem and I have multiple problems like this in my whole JavaProject, but if someone could explain me how to fix this I could get rid of all the redundancy in my project.

Thanks in advance, Lola

Thank you all so much! a combination of your answers helped me to let the buttons appear, but for some kind of reason the images don't load with them. my code now looks like:

public class MenuPanel extends JPanel implements ActionListener {

private Button playKnop, highScoreKnop, quitKnop, HTPKnop;

private Tanks mainVenster;

int x = 95, width = 200, height = 50;

public MenuPanel(Tanks mainVenster) 
{
    this.mainVenster = mainVenster;
    this.setLayout(null);

    playKnop = new Button("/buttons/PLAY.png", 350, this);      
    highScoreKnop = new Button("/buttons/HS.png", 460, this);
    quitKnop = new Button("/buttons/QUIT.png", 515, this);
    HTPKnop = new Button("/buttons/HTP.png", 570, this);

    this.add(playKnop);
    this.add(quitKnop);
    this.add(HTPKnop);
    this.add(highScoreKnop);

    validate();

}

public class Button extends JButton
{
    JButton button;
    ImageIcon buttonImage;

    String backgroundPath;
    int y;


    public Button(String backgroundPath, int y, MenuPanel menuPanel)
    {
        super();
        this.backgroundPath = backgroundPath;
        this.y = y;

        buttonImage = new ImageIcon(PlayPanel.class.getResource(backgroundPath));
        this.setBounds(x, y, width, height);;
        this.addActionListener(menuPanel); 
    }
}

}

(all the buttons do work!)

Lola
  • 179
  • 8

10 Answers10

2

Firstly, all class names should begin with a capital letter as a convention, this does not affect compilation but is good practice.

Now, for your actual problem, the first thing that stands out to me is that your Button Class does not extend anything. This to me seems to be the reason why it does not appear on the screen. I would suggest making Button extend JButton:

public class Button extends JButton {
// Implementation Code
}

This is similar to how your MenuPanel extends JPanel. The JPanel cannot render a custom Button that you wrote. By extending JButton it will be able to render it as it knows how to interact with a JButton

KernelKoder
  • 746
  • 5
  • 15
2

I think you can better let your Button class extend JButton. In that way you can just add your own button class to the menupanel.

public class Button extends JButton
{


    public JButton button;
    public ImageIcon buttonImage;

    public int x = 95;
    public int width = 200;
    public int height = 50;

    public String backgroundPath;
    public int y;



    public Button(String backgroundPath, int y, MenuPanel menuPanel)
    {
        super()
        this.backgroundPath = backgroundPath;
        this.y = y;

        buttonImage = new ImageIcon(PlayPanel.class.getResource(backgroundPath));
        this.setBounds(x, y, width, height);;
        this.addActionListener(menuPanel); 
    }



}
Rick Slot
  • 156
  • 1
  • 7
1

Can you observe the difference between the line:

playKnop.addActionListener(this);

and the one in later code:

playKnop = new button("/buttons/PLAY.png", 350);  

I believe you want to add MenuPanel as action listener but you are not passing the reference to it in later code. You should rather have: playKnop = new button("/buttons/PLAY.png", 350, this);

And then set this reference in your Button class like:

public button(String backgroundPath, int y, MenuPanel menuPanel)
    {
        this.backgroundPath = backgroundPath;
        this.y = y;

        buttonImage = new ImageIcon(PlayPanel.class.getResource(backgroundPath));
        button = new JButton();
        button.setBounds(x, y, width, height);;
        button.addActionListener(menuPanel); 
    }
akhil_mittal
  • 23,309
  • 7
  • 96
  • 95
  • When you pass `this` you actually pass a reference to the instance of that Class which is `MenuPanel` in your case. By the way did it solve your problem? – akhil_mittal May 07 '15 at 09:14
  • yes thank you very much, a combination of the answers i received helped me very much. everything works but i have one last question. i want to use this code is multiple panels so i need a parameter for `MenuPanel menuPanel` in the constructor. do you know which parameter i could use? i mean different panels like 'HighscorePanel' 'PlayPanel' 'HowToPlayPanel' 'QuitPanel' .... – Lola May 08 '15 at 08:46
1

The difference is that you are no longer adding JButtons to the JPanel.

For this code to work, your "button" class must extend JPanel.

Another way to extract the shared code would be to create a "Button creator method" instead of a class, something like:

public class MenuPanel extends JPanel implements ActionListener
{
    int y = 95, width = 200, height = 50;
    private JButton playKnop, highScoreKnop, quitKnop, HTPKnop;

    public MenuPanel()
    {
        this.setLayout(null);

        playKnop = createButton("/buttons/PLAY.png", 350);
        highScoreKnop = createButton("/buttons/HS.png", 460);
        quitKnop = createButton("/buttons/QUIT.png", 515);
        HTPKnop = createButton("/buttons/HTP.png", 570);

        this.add(playKnop);
        this.add(quitKnop);
        this.add(HTPKnop);
        this.add(highScoreKnop);

        validate();
    }

    private JButton createButton(String path, int x) {
        ImageIcon icon = new ImageIcon(MenuPanel.class.getResource(path));
        JButton button = new JButton(icon);
        button.setBounds(x, y, width, height);
        button.addActionListener(this);
        return button;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
    }
}
folkol
  • 4,752
  • 22
  • 25
0

In the existing MenuPanel, when you do

this.add(playKnop);

you are adding a JButton to your JPanel

In the new MenuPanel you are adding a button to your JPanel.

You need to add a JButton to a JPanel.

Also choose Button rather than button for class names.

The solution is to rewrite this code so that you are adding JButtons rather than buttons to your panel. There may be other issues with the code too.

Sachin Kainth
  • 45,256
  • 81
  • 201
  • 304
0

There is a difference in what you are adding. In the new code you are adding instances of your button class to the JPanel. In the old code you added JButtons. buttons can't be displayed as they're not swing classes, the old JButtons could.

Extending button from JButton should do the trick:

public class button extends JButton {

// public JButton button; // this line is depreceted now

public ImageIcon buttonImage;

...

Also, learn about code formatting and style in Java. This will help you write clearer code and prevent confusions as above. E.g. you have a class named button with a field named button and a method named button. Use different names as Button (classes are always upper case!), button and createButton.

LastFreeNickname
  • 1,445
  • 10
  • 17
0

Try adding a getButton in the class button to return the button for adding

public JButton getJButton(){
 retun this.button
}

then add use this on adding on the menu panel

this.add(playKnop.getJButton());
0

There is nothing wrong with your code. The only problem that I can see is that your Class button extend Object instead of JButton. So just do the following change and I feel it should work:

Instead of :

public class button 

write

public class button extends JButton
Blip
  • 3,061
  • 5
  • 22
  • 50
  • Right this is the first step. But don't forget to change the implemantation. you can remove the attribute "button" and then change all the function calls on the button from button.setBounds(x, y, width, height); to this.setBounds(x, y, width, height); – morgelo May 07 '15 at 09:16
  • dear downvoter could you comment on why or where my answer is incorrect? – Blip May 07 '15 at 09:33
0

Perhaps you want to make your button class inherit JButton instead of keeping a button field. That way, you could add the button to the panel.

Maurice Perry
  • 32,610
  • 9
  • 70
  • 97
0

I am not very familiar with the JButton class. You need to set the buttonImage as background. Maybe there is some function like:

this.setBackground(buttonImage);

If there is no function liek this, you can set the background in the Constructor. Similar to your examples above. You always created a new Button with:

JButton b = new JButton(buttonImage);

You can give the same parameters to the super()-methode in your own Constructor. The result will look liek this:

public class Button extends JButton
{
   String backgroundPath;
   int y;

   public Button(String backgroundPath, int y, MenuPanel menuPanel)
   {
       super(new ImageIcon(PlayPanel.class.getResource(backgroundPath)));
       this.backgroundPath = backgroundPath;
       this.y = y;

       this.setBounds(x, y, width, height);
       this.addActionListener(menuPanel); 
   }
}

This code is not tested.

morgelo
  • 136
  • 15