Search code examples
javaswingpaintcomponentmousehover

Hover Effects with Java Swing


In my main window I have two panels. They are leftPanel and rightPanel. In the leftPanel I have two buttons: matchButton and simulatorButton. In my rightPanel I have an image drawn on it. I tried to add a hover effect to both buttons. When hovering the mouse over the matchButton the image contained in the rightPanel would change to a new image. When removing the mouse from the matchButton the image on the rightPanel would revert to the default image. It would be the same with simulatorButton. For that I created a separate class and added the following code:

public class ImgPanelStart extends JPanel {
    private Image backgroundImage;
    private BufferedImage imgBg;

    public ImgPanelStart() {
        try {
            backgroundImage = ImageIO.read(new File("./apsProject/assets/img0.jpg"));
        } catch (IOException ex) {
            System.out.println("Falha ao carregar imagem de fundo");
        }
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (backgroundImage != null) {
            g.drawImage(imgBg, 0, 0, null);
        }
        Dimension dim = this.getSize();
        int dWidth = (int) dim.getWidth();
        int dHeight = (int) dim.getHeight();
        imgBg = new BufferedImage(dWidth, dHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = imgBg.createGraphics();
        g2.drawImage(backgroundImage, 0, 0, dWidth, dHeight, null);
        g2.dispose();
        g.drawImage(imgBg, 0, 0, null);
    }

    private void setImgBackground(Image img) {
        backgroundImage = img;
        if (imgBg == null) {
            imgBg = new BufferedImage(850, 600, BufferedImage.TYPE_INT_RGB);
        }
        Graphics2D g2 = imgBg.createGraphics();
        g2.drawImage(backgroundImage, 0, 0, getWidth(), getHeight(), null);
        g2.dispose();
        repaint();
    }

    public void addHoverEffect(JButton button, JButton button2) {
        button.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                try {
                    setImgBackground(ImageIO.read(new File("./apsProject/assets/wall.jpg")));
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }

            @Override
            public void mouseExited(MouseEvent e) {
                try {
                    setImgBackground(ImageIO.read(new File("./apsProject/assets/img0.jpg")));
                } catch (IOException e1) {
                    e1.printStackTrace();
                };
            }
        });

        button2.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                try {
                    setImgBackground(ImageIO.read(new File("./apsProject/assets/img2.jpg")));
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }

            @Override
            public void mouseExited(MouseEvent e) {
                try {
                    setImgBackground(ImageIO.read(new File("./apsProject/assets/img0.jpg")));
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        });
    }
}

I call my method in the main class like this:

ImgPanelStart effects = new ImgPanelStart();
effects.addHoverEffect(matchButton, simulationButton);

However, the drawing made on the panel is not updated when hovering the mouse over it.

It would be something like, I hovered the mouse over the button button it would change the image in my rightPanel to wall.jpg. I removed the mouse and it would return to the image img0.jpg.

I hovered the mouse over the button2 button, it would change the image in my rightPanel to img2.jpg. When I removed the mouse it would return to the image img0.jpg.

Does anyone know what could be wrong, or give me a tip on what I can do to fix this problem?


Solution

  • Since your code was not a complete runnable example, I went ahead and created the following GUI.

    Example

    Here's the same GUI when you hover over the simulation button.

    Example

    Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section.

    I read the images I wanted to use before I constructed the GUI. That way, I only read the images one time.

    Here's the complete runnable code. I made the additional classes inner classes so I could post the code as one block.

    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.GridLayout;
    import java.awt.Image;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.io.IOException;
    import java.net.URL;
    
    import javax.imageio.ImageIO;
    import javax.swing.BorderFactory;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    
    public class HoverEffects implements Runnable {
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new HoverEffects());
        }
    
        private final DrawingPanel drawingPanel;
    
        private final LoadImages loadImages;
    
        public HoverEffects() {
            this.loadImages = new LoadImages();
            this.drawingPanel = new DrawingPanel(loadImages.getWallpaper());
        }
    
        @Override
        public void run() {
            JFrame frame = new JFrame("Hover Effects");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            frame.add(createButtonPanel(), BorderLayout.WEST);
            frame.add(drawingPanel, BorderLayout.CENTER);
    
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        }
    
        private JPanel createButtonPanel() {
            JPanel outerPanel = new JPanel();
    
            JPanel panel = new JPanel(new GridLayout(0, 1, 5, 5));
            panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    
            JButton matchButton = new JButton("Match");
            matchButton.addMouseListener(
                    new HoverListener(this, loadImages, matchButton));
            panel.add(matchButton);
    
            JButton simulatorButton = new JButton("Simulation");
            simulatorButton.addMouseListener(
                    new HoverListener(this, loadImages, simulatorButton));
            panel.add(simulatorButton);
    
            outerPanel.add(panel);
    
            return outerPanel;
        }
    
        public void setImage(Image image) {
            drawingPanel.setImage(image);
            drawingPanel.repaint();
        }
    
        public class DrawingPanel extends JPanel {
    
            private static final long serialVersionUID = 1L;
    
            private Image image;
    
            public DrawingPanel(Image image) {
                setImage(image);
                this.setPreferredSize(new Dimension(800, 600));
            }
    
            public void setImage(Image image) {
                this.image = image;
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.drawImage(image, 0, 0, this);
            }
    
        }
    
        public class HoverListener extends MouseAdapter {
    
            private final HoverEffects view;
    
            private final LoadImages model;
    
            private final JButton button;
    
            public HoverListener(HoverEffects view, LoadImages model,
                    JButton button) {
                this.view = view;
                this.model = model;
                this.button = button;
            }
    
            @Override
            public void mouseEntered(MouseEvent event) {
                String text = button.getText();
                if (text.equals("Match")) {
                    view.setImage(model.getNature1());
                } else {
                    view.setImage(model.getNature2());
                }
            }
    
            @Override
            public void mouseExited(MouseEvent event) {
                view.setImage(model.getWallpaper());
            }
    
        }
    
        public class LoadImages {
    
            private Image nature1, nature2, wallpaper;
    
            public LoadImages() {
                try {
                    URL url = new URL(
                            "http://www.thewowstyle.com/wp-content/uploads/"
                                    + "2015/01/nature-wallpaper-27.jpg");
                    Image image = ImageIO.read(url);
                    wallpaper = image.getScaledInstance(800, 600,
                            Image.SCALE_SMOOTH);
                    url = new URL("http://www.thewowstyle.com/wp-content/uploads/"
                            + "2015/01/nature-images..jpg");
                    image = ImageIO.read(url);
                    nature1 = image.getScaledInstance(800, 600, Image.SCALE_SMOOTH);
                    url = new URL("http://www.thewowstyle.com/wp-content/uploads/"
                            + "2015/01/nature-images.jpg");
                    image = ImageIO.read(url);
                    nature2 = image.getScaledInstance(800, 600, Image.SCALE_SMOOTH);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
            public Image getNature1() {
                return nature1;
            }
    
            public Image getNature2() {
                return nature2;
            }
    
            public Image getWallpaper() {
                return wallpaper;
            }
    
        }
    
    }