0

I am currently doing GUI development in JavaSwing. I am trying to create a button like the HTML code described below using JButton, which was added to getContentPane(), but I don't know how to do it and am at a loss.


Current Code:

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

public class Main {
  public static void main(String[] args) {

    JFrame frame = new JFrame();
    frame.setTitle("TITLE");
    frame.setVisible(true);
    frame.setLocationRelativeTo(null);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(1000, 800);
    frame.getContentPane().setLayout(new FlowLayout());

    JButton button = new JButton("Click Here");
    frame.getContentPane().add(button);
    button.setBackground(Color.RED);
    button.setForeground(Color.WHITE);
    button.setOpaque(true);
    button.setPreferredSize(new Dimension(150, 50));

    }

  }

The entity I am trying to create is a little hard to explain by mouth, so I have tried to reproduce what I am trying to create using HTML. It is as follows:


HTML CODE:

<div class="btn">Click Here</div>

<style>
.btn {
  background-color: red;
  display: inline-block;
  height: 70px;
  width: 150px;
  text-align: center;
  color: white;
  padding-top: 35px;
  font-size: 25px;
  border-radius: 50px;
  box-shadow: 0px 5px #b70d0b;
  opacity: 0.7;
  cursor: pointer;
}
  .btn:hover {
    opacity: 1;
  }
  .btn:active{
    position: relative;
    top: 5px;
    box-shadow: none;
  }
</style>

This is what it looks like when executed: The following image is my ideal in JavaSwing. Button

The question this time is:

  • Setting opacity to JButton in JavaSwing

  • To set border-radius to button

  • To set opacity to 1 only when the mouse hovers over the button and MouseEvent detects it.

  • Set box-shadow to 5px, and use ActionListener to detect the interval of active, and make it look like a button is being pressed.

  • To reproduce the cursor:pointer code while the mouse is hovering over the button.

I am not sure if this is too much to ask or not. I am fully aware that there are too many questions, so I would appreciate it if you could answer only the ones that I can answer.

In the meantime, I have done my own Google research on the question, but none of it fits my ideal, so I am asking it here.


As for what I did, here's what I did:

I looked here, but when I enter a decimal point, like setOpacity(0.5), I get an error that setOpacity(double) is undefined.

I referred to the border-radius here, but nothing happened when I ran it. Perhaps there is a problem with my writing style or version. I think there is a problem with the way I wrote it or the version, but I could not find out the cause.

I tried copying the MouseEvent for the hover here, but the version may be different, or an error occurred.

So, what code should I write to achieve what I am asking? I would appreciate it if you could help me.

Thank you.

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
Qwj_38
  • 103
  • 7
  • Honestly, make an image – MadProgrammer Jun 04 '22 at 03:43
  • @MadProgrammer Hm... I think that is great idea!, but how do I add ```ActionListener``` with Image? – Qwj_38 Jun 04 '22 at 03:45
  • Well, since `JLabel` doesn't support `ActionListener`, then you'd have to use a `JButton` – MadProgrammer Jun 04 '22 at 03:47
  • Oh, I didn't know that, thank you. So I think I supposed to edit the question about ```How to add decoration with JButton``` – Qwj_38 Jun 04 '22 at 03:48
  • There's no "simple" way to do it. You're going to have to create your own button class to do (or create your own look and feel delegate) – MadProgrammer Jun 04 '22 at 04:14
  • @MadProgrammer I see, thank you very much for telling me that. I will try to create my own button class as you have taught me. – Qwj_38 Jun 04 '22 at 04:18
  • I have had success in small experiments like this to use subclass of JLabel with custom paintComponent with addMouseListener/MouseAdapter, roughly like https://stackoverflow.com/questions/14297448/jlabel-after-overriding-paintcomponent-how-to-make-settext-render-the-text does – Dmytro Jun 04 '22 at 04:20
  • !! this is just what I wanted to know, thank you for sharing – Qwj_38 Jun 04 '22 at 04:28

1 Answers1

1

There's no "simple" way to do this, you're either going to have to create your own custom button (extending from JButton) or your own UI delegate class (which might be the preferred direction, but it's complicated)

Why not use a Border

Because a Border can't be filled ... and if you do, it will paint over the text of the button

You should start by looking at Painting in AWT and Swing, Performing Custom Painting and 2D Graphics to get a better understanding of how the solution works.

enter image description here

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

public class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {
        public TestPane() {
            setBorder(new EmptyBorder(32, 32, 32, 32));
            setLayout(new GridBagLayout());
            FancyButton btn = new FancyButton();
            btn.setText("Click me");
            add(btn);
        }
    }

    public class FancyButton extends JButton {

        private int cornerRadius = 32;
        private BufferedImage backgroundImage;

        private float alpha = 0.25f;

        public FancyButton() {
            setBackground(Color.RED);
            setForeground(Color.WHITE);
            // This is important
            setBorderPainted(false);
            // This is important
            setContentAreaFilled(false);
            // This is important
            int padding = cornerRadius / 2;
            setBorder(new EmptyBorder(padding, padding, padding, padding));
            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseEntered(MouseEvent e) {
                    alpha = 1;
                    repaint();
                }

                @Override
                public void mouseExited(MouseEvent e) {
                    alpha = 0.25f;
                    repaint();
                }
            });
            addComponentListener(new ComponentAdapter() {
                @Override
                public void componentResized(ComponentEvent e) {
                    backgroundImage = null;
                }
            });
        }

        @Override
        public boolean isOpaque() {
            return false;
        }

        @Override
        public Insets getInsets() {
            Insets insets = super.getInsets(); 
            insets.bottom += 5;
            return insets;
        }

        @Override
        public Insets getInsets(Insets insets) {
            super.getInsets(insets);
            insets.bottom += 5;
            return insets;
        }

        @Override
        protected void paintComponent(Graphics g) {
            if (backgroundImage == null) {
                backgroundImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
                Graphics2D g2d = backgroundImage.createGraphics();
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.setColor(getBackground().darker());
                g2d.fillRoundRect(0, 5, getWidth(), getHeight() - 5, cornerRadius, cornerRadius);
                g2d.setColor(getBackground());
                g2d.fillRoundRect(0, 0, getWidth(), getHeight() - 5, cornerRadius, cornerRadius);
                g2d.dispose();
            }

            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setComposite(AlphaComposite.SrcOver.derive(alpha));
            g2d.drawImage(backgroundImage, 0, 0, this);
            super.paintComponent(g2d);
            g2d.dispose();
        }
    }
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366