Question

I have just started working with Swing and am trying to draw a button with a custom shape, a triangle in this example. I called the JButton subclass 'ShiftingButton' in the following code because of its unusual behavior. When the mouse enters its region, it is repainted with an offset from its original position. Furthermore the shifted, offset version is drawn in addition to the original position so that both the original and shifted versions appear together. That is, when I run this code, the button is shown as a triangle along the left edge of the window. Then when I run the mouse over the button, a new triangle is drawn (in addition to the old one), shifted down and to the right by about 10 pixels. Resizing the window changes the offset of the phantom button from the original.

Experimenting with mouse clicks shows that only the original, correctly-positioned button is active. The region of the offset phantom button is not active.

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.event.*;
import java.awt.Polygon;

public class ShiftingButton extends JButton implements ActionListener {
    private Polygon shape;
    public ShiftingButton () {
        initialize();
        addActionListener(this);
    }
    protected void initialize() {
        shape = new Polygon();
        setSize(120, 120);
        shape.addPoint(0, 0);
        shape.addPoint(0, 60); 
        shape.addPoint(90, 0);
        setMinimumSize(getSize());
        setMaximumSize(getSize());
        setPreferredSize(getSize());
    }
    // Hit detection
    public boolean contains(int x, int y) {
        return shape.contains(x, y);
    }
    @Override
    public void paintComponent (Graphics g) {
        System.err.println("paintComponent()");
        g.fillPolygon(shape);
    }
    protected void paintBorder(Graphics g) {
    }
    @Override
    public void actionPerformed (ActionEvent ev) {
        System.out.println("ShiftingButton ActionEvent!");
    }
    public static void main (String[] args) {
        JFrame frame = new JFrame();
        JPanel panel = new JPanel();
        ShiftingButton button = new ShiftingButton();
        panel.add(button);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(panel);
        frame.pack();
        frame.setVisible(true);
    }
}
Was it helpful?

Solution

You failed to call super.paintComponent(g) inside the overridden paintComponent(...) method. Moreover, while overriding a method of the Base class, always try to keep the access specifier of the methods, the same, as much as possible. In this case it's protected and not public :-) Now function should be like this :

@Override
protected void paintComponent (Graphics g) {
    System.err.println("paintComponent()");
    super.paintComponent(g);
    g.fillPolygon(shape);
}

EDIT 1 :

Moreover, since you are using a custom shape to be drawn, hence you again failed to specify the ContentAreaFilled property for this JButton in question, hence inside your constructor, you should write setContentAreaFilled(false), for it to work nicely. Though if this doesn't works (for reasons specified in the Docs), then you have to use the plain old Opaque property and set it to false for this JButton using setOpaque(false) :-)

Here is your code with modified changes :

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.event.*;
import java.awt.Polygon;

public class ShiftingButton extends JButton implements ActionListener {

    private Polygon shape;

    public ShiftingButton () {
        setContentAreaFilled(false);
        initialize();
        addActionListener(this);
    }

    protected void initialize() {
        shape = new Polygon();
        setSize(120, 120);
        shape.addPoint(0, 0);
        shape.addPoint(0, 60); 
        shape.addPoint(90, 0);
    }

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

    // Hit detection
    public boolean contains(int x, int y) {
        return shape.contains(x, y);
    }

    @Override
    protected void paintComponent(Graphics g) {
        System.err.println("paintComponent()");
        super.paintComponent(g);
        g.fillPolygon(shape);       
    }

    protected void paintBorder(Graphics g) {
    }

    @Override
    public void actionPerformed (ActionEvent ev) {
        System.out.println("ShiftingButton ActionEvent!");
    }

    public static void main (String[] args) {
        JFrame frame = new JFrame();
        JPanel panel = new JPanel();
        ShiftingButton button = new ShiftingButton();
        panel.add(button);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(panel);
        frame.pack();
        frame.setVisible(true);
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top