Search code examples
javaswingjbuttonpolygoncurve

How do I design a JButton with round corners?


I am trying to design a JButton.

I want the JButton to look like this:

enter image description here

I tried to achieve this using Polygon but I couldn't make the corners be round as seen above.

The one I designed looks like this:

enter image description here

The code that generated this button is below:

public class arcButton extends JButton{

public arcButton() {
    Dimension size = getPreferredSize();
    size.width = size.height = Math.max(size.width, size.height);
    setPreferredSize(size);
    setContentAreaFilled(false);
}
protected void paintComponent(Graphics g) {
    
    
    if (getModel().isArmed()) {
        g.setColor(Color.CYAN.darker().darker());
    } else {
        g.setColor(Color.CYAN.darker());
    }
    int xPoints[] = {getWidth(), getWidth()/3, getWidth()/3, getWidth()*3/4, getWidth()*3/4, getWidth(), getWidth()*3/4, getWidth()*3/4, 0, 0, getWidth()};
    int yPoints[] = {getHeight()*7/9, getHeight()*7/9, getHeight()*3/9, getHeight()*3/9, getHeight()*4/9, getHeight()*2/9, 0, getHeight()/9, getHeight()/9, getHeight(), getHeight()};      
    g.fillPolygon(xPoints, yPoints, xPoints.length);
    super.paintComponent(g);
}

protected void paintBorder(Graphics g) {
    g.setColor(Color.cyan);
    int xPoints[] = {getWidth(), getWidth()/3, getWidth()/3, getWidth()*3/4, getWidth()*3/4, getWidth(), getWidth()*3/4, getWidth()*3/4, 0, 0, getWidth()};
    int yPoints[] = {getHeight()*7/9, getHeight()*7/9, getHeight()*3/9, getHeight()*3/9, getHeight()*4/9, getHeight()*2/9, 0, getHeight()/9, getHeight()/9, getHeight(), getHeight()};      
    g.drawPolygon(xPoints, yPoints, xPoints.length);
}
Polygon polygon;

public boolean contains(int x, int y) {
    if (polygon == null ||
            !polygon.getBounds().equals(getBounds())) {
        int xPoints[] = {getWidth(), getWidth()/3, getWidth()/3, getWidth()*3/4, getWidth()*3/4, getWidth(), getWidth()*3/4, getWidth()*3/4, 0, 0, getWidth()};
        int yPoints[] = {getHeight()*7/9, getHeight()*7/9, getHeight()*3/9, getHeight()*3/9, getHeight()*4/9, getHeight()*2/9, 0, getHeight()/9, getHeight()/9, getHeight(), getHeight()};          
        polygon = new Polygon(xPoints,yPoints,xPoints.length);
    }
    return polygon.contains(x, y);
}
}

I tried to draw with arcs but when I use ((Graphics2D)g).draw(arc) in the paintComponent. It kept giving a lot of errors when mouse was on the GUI.

How should I approach this?


Solution

  • I created the following GUI.

    Custom JButton

    Instead of extending a JButton, I created a class to hold two BufferedImages. One for the arrow, and one to signify a pressed button.

    I created a test GUI so I could draw the arrow one small piece at a time. I wound up creating two Polygons, one for the semi-circle and one for the arrowhead.

    Here's the complete runnable code.

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.FlowLayout;
    import java.awt.Graphics2D;
    import java.awt.Point;
    import java.awt.Polygon;
    import java.awt.RenderingHints;
    import java.awt.image.BufferedImage;
    
    import javax.swing.BorderFactory;
    import javax.swing.ImageIcon;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    
    public class CustonButtonGUI implements Runnable {
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new CustonButtonGUI());
        }
        
        private ButtonImages buttonImages;
        
        public CustonButtonGUI() {
            this.buttonImages = new ButtonImages();
        }
    
        @Override
        public void run() {
            JFrame frame = new JFrame("Custom JButton");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            
            frame.add(createMainPanel(), BorderLayout.CENTER);
            
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        }
        
        private JPanel createMainPanel() {
            JPanel panel = new JPanel(new FlowLayout());
            panel.setBorder(BorderFactory.createEmptyBorder(100, 100, 100, 100));
            
            BufferedImage image = buttonImages.getMainImage();
            
            JButton button = new JButton();
            button.setPreferredSize(new Dimension(image.getWidth(panel), 
                    image.getHeight(panel)));
            button.setIcon(new ImageIcon(image));
            button.setPressedIcon(new ImageIcon(buttonImages.getPressedImage()));
            panel.add(button);
            
            return panel;
        }
        
        private class ButtonImages {
            
            private final BufferedImage mainImage;
            private final BufferedImage pressedImage;
            
            public ButtonImages() {
                this.mainImage = createMainImage(120, 200);
                this.pressedImage = createPressedImage(120, 200);
            }
            
            private BufferedImage createMainImage(int width, int height) {
                BufferedImage image = new BufferedImage(width, height, 
                        BufferedImage.TYPE_INT_RGB);
                Graphics2D g2d = (Graphics2D) image.getGraphics();
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.setColor(Color.WHITE);
                g2d.fillRect(0, 0, width, height);
                
                g2d.setColor(Color.BLACK);
                g2d.fillPolygon(createArrowPolygon(width, height));
                g2d.fillPolygon(createCircularPolygon(width, height));
                
                g2d.dispose();
                return image;
            }
            
            private Polygon createArrowPolygon(int width, int height) {
                Polygon polygon = new Polygon();
                
                int margin = 10;
                int arrowWidth = 30;
                int x = width - margin;
                int y = height - margin;
                
                polygon.addPoint(x, y - arrowWidth);
                polygon.addPoint(x - arrowWidth, y - arrowWidth - arrowWidth);
                polygon.addPoint(x - arrowWidth, y);
                
                return polygon;
            }
            
            private Polygon createCircularPolygon(int width, int height) {
                Polygon polygon = new Polygon();
                
                int centerY = height / 2;
                int margin = 10;
                Point centerPoint = new Point(width - margin - 30, centerY);
                double radius = centerY - 55.0;
                
                for (int angle = 90; angle <= 270; angle++) {
                    double theta = Math.toRadians(angle);
                    int x = (int) Math.round(Math.cos(theta) * radius) + centerPoint.x;
                    int y = (int) Math.round(Math.sin(theta) * radius) + centerPoint.y;
                    polygon.addPoint(x, y);
                }
                
                radius += 25.0;
                for (int angle = 270; angle >= 90; angle--) {
                    double theta = Math.toRadians(angle);
                    int x = (int) Math.round(Math.cos(theta) * radius) + centerPoint.x;
                    int y = (int) Math.round(Math.sin(theta) * radius) + centerPoint.y;
                    polygon.addPoint(x, y);
                }
                
                return polygon;
            }
            
            private BufferedImage createPressedImage(int width, int height) {
                BufferedImage image = new BufferedImage(width, height, 
                        BufferedImage.TYPE_INT_RGB);
                return image;
            }
            
            public BufferedImage getMainImage() {
                return mainImage;
            }
            
            public BufferedImage getPressedImage() {
                return pressedImage;
            }
                
        }
    
    }