Search code examples
javapaintcomponentextending

Overriding paintComponent() Method within a custom JButton


So my ultimate goal is to change the design of a JButton from the basic looking blue button to whatever I want, like a circle. So I create a class called "Button" and made it extend JButton

public class Button extends JButton {

public Button(String text) {
    super(text);
    this.setContentAreaFilled(false);
}

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    System.out.println("hello");

    //Paint Stuff Will Happen Here
}

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

}

My first goal was just to make sure that the paintComponent method was being called, so I put in a debug message. That debug message has never shown. Basically the paintComponent() method is never called, even though I'm manually calling the "repaint" method for my JFrame. Despite the fact that the method is not being called, a regular button still shows up on my JFrame, which is really confusing to me.

Here is my JPanel code

public class Scene extends JPanel {

public Scene() {
    //Initialize Listeners
    Button button = new Button("Hello");
    button.setBounds(400, 400, 50, 25);

    this.setLayout(null);
    this.add(button);
}

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g;

    //Paint Stuff Below
    for (int xI = 0; xI < Sprite.allSprites.size(); xI++) {
        Sprite sprite = Sprite.allSprites.get(xI);

        if (sprite.isVisible) {
            g2.drawImage(sprite.image, sprite.rawLocation.x.intValue(), sprite.rawLocation.y.intValue(), null);
        }
    }

    g2.dispose();
}

}

Basically in my JPanel I override the paintComponent method as well so as to paint my various sprites onto the screen, which has worked just fine and is probably irrelevant to the issue.

And finally, this is my JFrame code

public class GameWindow extends JFrame {

private Scene currentScene;
public void initialize(Scene scene) {
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setSize(Settings.DEFAULT_WINDOW_SIZE);
    this.setResizable(false);
    this.setLocation(this.getLocationToCenterScreen());

    this.setScene(scene);
}

//Gets the center of the screen with the given window
public Point getLocationToCenterScreen() {
    return new Point(Settings.SCREEN_CENTER.x - (this.getSize().width / 2), Settings.SCREEN_CENTER.y - (this.getSize().height / 2));
}

public void setScene(Scene scene) {
    this.currentScene = scene;
    this.setContentPane(scene);
}

public Scene getCurrentScene() {
    return currentScene;
}

}

Nothing really fancy in this code as far as I can tell. I've set the content pane. I've made sure each paintComponent() method also includes super.paintComponent(g). I've set the LayoutManager to null for testing purposes. I've set the Button's bounds.

As I said, the button actually does show up on the screen. But the debug message never shows. Also, the button that shows up on the screen looks like the really old Windows buttons from 10 years ago. It's all grey with a black border. This old button only shows up if I'm using a class that extends JButton.

Anyways, thanks guys! I hope I can get over this weird problem.


Solution

  • First and foremost, as a few other people have said, don't name your class "Button"; that belongs to Swing's predecessor, AWT (Advanced Windowing Toolkit), and is likely to confuse the compiler at best, and get you the wrong "Button" at worst.

    That should solve the paintComponent() problem, but in addition, if all you're trying to do is change the feel of the button, then you're overprogramming this.

    There are two ways to accomplish this with a JButton.

    The first, and probably easiest (for an image), is AbstractButton.setIcon(Icon defaultIcon) An Icon is a type of image, loadable from a BufferedImage with ImageIcon(Image image) and manipulable in the same way. This is probably what you need.

    The other method which comes to mind, which is much more broad in scope, is change the Look and Feel of the application. Most of us have several available to our systems, inclusive of the default Java look and feel, and the platform look and feel. I recommend setting it as early as possible; since it's entirely done through static methods, for small projects you might even get away with slipping it into the main method, before anything is even initialized.

    Let me know if this doesn't solve your problem, and I wish you luck with the rest of your project!