简体   繁体   中英

java setOpaque(false) makes hovering slow

I made a button by extending JPanel and adding 2 JLabels on top of each other using the OverlayLayout. one of the JLabels is the icon which is just a font-awesome icon. The other one is the hover text. I want the background of the JPanel to be transparent, so it doesn't have a white border. I did this using this AlphaContainer method:

https://www.programcreek.com/java-api-examples/index.php?source_dir=cismet-gui-commons-master/src/main/java/de/cismet/tools/gui/AlphaContainer.java

This is what I mean by slow hovering:

在此处输入图片说明

I now only added the setOpaque(false) property to the bottom half of the icons. This is what it looks like: 在此处输入图片说明

Here I added the 6 buttons:

setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));

        HoverButtonTest forum = new HoverButtonTest("\uf086", "Forum", Settings.iconSize);
        add(forum);

        HoverButtonTest hs = new HoverButtonTest("\uf080", "Highscores", Settings.iconSize);
        add(hs);

        HoverButtonTest shop = new HoverButtonTest("\uf07a", "Store", Settings.iconSize);
        add(shop);

        HoverButtonTest vote = new HoverButtonTest("\uf046", "Vote for Us", Settings.iconSize);
        vote.setOpaque(false);
        add(vote);

        HoverButtonTest discord = new HoverButtonTest("\uf392", "Discord", Settings.iconSize, HoverButtonTest.Type.BRAND);
        discord.setOpaque(false);
        add(discord);

        HoverButtonTest web = new HoverButtonTest("\uf0ac", "Web", Settings.iconSize, HoverButtonTest.Type.SOLID);
        web.setOpaque(false);
        add(web);

This is the button class I am using:

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

/**
 * @author Ruud.
 */
public class HoverButtonTest extends JPanel implements MouseListener {

    public enum Type {
        NORMAL("Font Awesome.ttf"),
        REGULAR("Font Awesome Regular.ttf"),
        SOLID("Font Awesome Solid.ttf"),
        BRAND("Font Awesome Brands.ttf");

        String font;

        Type(String font) {
            this.font = font;
        }

        String getFont() {
            return font;
        }

    }

    private JLabel icon;
    private JLabel text;

    public HoverButtonTest(String icon, String text, int size) {
        this(icon, text, size, Type.NORMAL);
    }

    public HoverButtonTest(String icon, String text, int size, Type type) {
        setLayout(new OverlayLayout(this));
        addMouseListener(this);
        setOpaque(false);

        this.text = new JLabel(text);
        this.text.setForeground(Color.WHITE);
        this.text.setAlignmentX(0.5f);
        this.text.setAlignmentY(0.5f);
        Utils.setFont(this.text, "OpenSans-Light.ttf", 13);
        this.text.setVisible(false);
        add(this.text);

        this.icon = new JLabel(icon);
        this.icon.setForeground(Settings.primaryColor);
        this.icon.setAlignmentX(0.5f);
        this.icon.setAlignmentY(0.5f);
        Utils.setFont(this.icon, type.getFont(), size);
        add(this.icon);
    }

    @Override
    public void paintComponent(Graphics g) {
        g.setColor(new Color(0, 0, 0, 0));
    }


    @Override
    public void mouseClicked(MouseEvent e) {

    }

    @Override
    public void mousePressed(MouseEvent e) {

    }

    @Override
    public void mouseReleased(MouseEvent e) {

    }

    @Override
    public void mouseEntered(MouseEvent e) {
        text.setVisible(true);
        icon.setForeground(Settings.primaryColor.darker().darker().darker().darker());
    }

    @Override
    public void mouseExited(MouseEvent e) {
        text.setVisible(false);
        icon.setForeground(Settings.primaryColor);
    }
}

I've edited the code from RadioDef to fit a bit more to my needs, the weird thing is that it doesn't occur in this code

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.LineBorder;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URL;

public class MouseoverPanels {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(MouseoverPanels::new);
    }

    public MouseoverPanels() {
        JFrame frame = new JFrame("Mouseover Panels");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        JPanel background = new Background();

        JPanel buttons = new Buttons();
        //JPanel buttons = new JPanel();
        buttons.setOpaque(false);

        buttons.add(new MouseoverPanel("Queen", QUEEN_IMG, QUEEN_IMG_H));
        buttons.add(new MouseoverPanel("King", KING_IMG, KING_IMG_H));
        buttons.add(new MouseoverPanel("Rook", ROOK_IMG, ROOK_IMG_H));
        buttons.add(new MouseoverPanel("Knight", KNIGHT_IMG, KNIGHT_IMG_H));
        buttons.add(new MouseoverPanel("Pawn", PAWN_IMG, PAWN_IMG_H));

        background.add(buttons);

        frame.setContentPane(background);

        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    class MouseoverPanel extends JPanel {
        JLabel button;
        JLabel hoverImage;
        JLabel icon;

        MouseoverPanel(String text, Image img, Image hImg) {
            setLayout(new OverlayLayout(this));
            setOpaque(false);

            button = new JLabel(text);
            button.setOpaque(false);
            button.setAlignmentX(0.5f);
            button.setAlignmentY(0.5f);
            button.setVisible(false);

            hoverImage = new JLabel(new ImageIcon(hImg));
            hoverImage.setOpaque(false);
            hoverImage.setAlignmentX(0.5f);
            hoverImage.setAlignmentY(0.5f);
            hoverImage.setVisible(false);

            icon = new JLabel(new ImageIcon(img));
            icon.setOpaque(false);
            icon.setAlignmentX(0.5f);
            icon.setAlignmentY(0.5f);

            add(button);
            add(hoverImage);
            add(icon);

            MouseoverListener ml = new MouseoverListener();

            addMouseListener(ml);
            button.addMouseListener(ml);
            icon.addMouseListener(ml);
        }

        class MouseoverListener extends MouseAdapter {
            @Override
            public void mouseEntered(MouseEvent e) {
                button.setVisible(true);
                hoverImage.setVisible(true);
            }

            @Override
            public void mouseExited(MouseEvent e) {
                button.setVisible(false);
                hoverImage.setVisible(false);
            }
        }
    }

    class Buttons extends JPanel {
        public Buttons() {
            setOpaque(false);
            setBorder(new LineBorder(Color.BLACK));
        }
        @Override
        protected void paintComponent(Graphics g) {
            g.setColor(new Color(0, 0, 0, 100));
            g.fillRect(0, 0, getWidth(), getHeight());
        }
    }

    class Background extends JPanel {
        private BufferedImage sprite = null;

        public Background() {
            try {
                sprite = ImageIO.read(new URL("https://i.stack.imgur.com/XZ4V5.jpg"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Image scaledImage = sprite.getScaledInstance(getWidth(), getHeight(), Image.SCALE_REPLICATE);
            g.drawImage(scaledImage, getWidth() / 2 - scaledImage.getWidth(this) / 2, getHeight() / 2 - scaledImage.getHeight(this) / 2, this);
        }
    }

    static final Image QUEEN_IMG,
            QUEEN_IMG_H,
            KING_IMG,
            KING_IMG_H,
            ROOK_IMG,
            ROOK_IMG_H,
            KNIGHT_IMG,
            KNIGHT_IMG_H,
            PAWN_IMG,
            PAWN_IMG_H;

    static {
        try {
            // source for sprite sheet: https://stackoverflow.com/a/19209651/2891664
            BufferedImage sprites = ImageIO.read(new URL("https://i.stack.imgur.com/memI0.png"));
            int n = 64;
            QUEEN_IMG = sprites.getSubimage(0 * n, 0, n, n);
            QUEEN_IMG_H = sprites.getSubimage(0 * n, 64, n, n);
            KING_IMG = sprites.getSubimage(1 * n, 0, n, n);
            KING_IMG_H = sprites.getSubimage(1 * n, 64, n, n);
            ROOK_IMG = sprites.getSubimage(2 * n, 0, n, n);
            ROOK_IMG_H = sprites.getSubimage(2 * n, 64, n, n);
            KNIGHT_IMG = sprites.getSubimage(3 * n, 0, n, n);
            KNIGHT_IMG_H = sprites.getSubimage(3 * n, 64, n, n);
            PAWN_IMG = sprites.getSubimage(4 * n, 0, n, n);
            PAWN_IMG_H = sprites.getSubimage(4 * n, 64, n, n);
        } catch (IOException x) {
            throw new UncheckedIOException(x);
        }
    }


}

The small project I made with hovering: https://www.dropbox.com/s/wq4ggufbxrfcvb8/HoverButton.zip?dl=0

The best way to do this is probably to use a CardLayout which is already set up for good behavior.

Here's an MCVE.

鼠标悬停面板MCVE截图

package mcve;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.imageio.*;
import java.net.*;
import java.io.*;

public class MouseoverPanels {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(MouseoverPanels::new);
    }

    MouseoverPanels() {
        JFrame frame = new JFrame("Mouseover Panels");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel buttons = new JPanel();
        buttons.setBackground(Color.WHITE);

        buttons.add(new MouseoverPanel("Queen",  QUEEN_IMG));
        buttons.add(new MouseoverPanel("King",   KING_IMG));
        buttons.add(new MouseoverPanel("Rook",   ROOK_IMG));
        buttons.add(new MouseoverPanel("Knight", KNIGHT_IMG));
        buttons.add(new MouseoverPanel("Pawn",   PAWN_IMG));

        frame.setContentPane(buttons);

        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    class MouseoverPanel extends JPanel {
        static final String BUTTON_KEY = "BUTTON";
        static final String ICON_KEY   = "ICON";

        final CardLayout layout = new CardLayout();

        MouseoverPanel(String text, Image img) {
            setLayout(layout);
            setOpaque(false);

            JButton button = new JButton(text);
            button.setBorderPainted(false);
            button.setOpaque(false);

            JLabel icon = new JLabel(new ImageIcon(img));
            icon.setOpaque(false);

            add(button, BUTTON_KEY);
            add(icon,   ICON_KEY);

            layout.show(this, ICON_KEY);

            MouseoverListener ml = new MouseoverListener();

            addMouseListener(ml);
            button.addMouseListener(ml);
            icon.addMouseListener(ml);
        }

        class MouseoverListener extends MouseAdapter {
            @Override
            public void mouseEntered(MouseEvent e) {
                recomputeView(e);
            }
            @Override
            public void mouseExited(MouseEvent e) {
                recomputeView(e);
            }
            void recomputeView(MouseEvent e) {
                Component comp = e.getComponent();
                Point     loc  = SwingUtilities.convertPoint(comp, e.getPoint(), MouseoverPanel.this);
                String    key  = contains(loc) ? BUTTON_KEY : ICON_KEY;
                layout.show(MouseoverPanel.this, key);
            }
        }
    }

    static final Image QUEEN_IMG,
                       KING_IMG,
                       ROOK_IMG,
                       KNIGHT_IMG,
                       PAWN_IMG;
    static {
        try {
            // source for sprite sheet: https://stackoverflow.com/a/19209651/2891664
            BufferedImage sprites = ImageIO.read(new URL("https://i.stack.imgur.com/memI0.png"));
            int n = 64;
            QUEEN_IMG  = sprites.getSubimage(0 * n, 0, n, n);
            KING_IMG   = sprites.getSubimage(1 * n, 0, n, n);
            ROOK_IMG   = sprites.getSubimage(2 * n, 0, n, n);
            KNIGHT_IMG = sprites.getSubimage(3 * n, 0, n, n);
            PAWN_IMG   = sprites.getSubimage(4 * n, 0, n, n);
        } catch (IOException x) {
            throw new UncheckedIOException(x);
        }
    }
}

I think the performance hit you're seeing is probably because calling setVisible may cause revalidate to be called , which invokes the layout manager, but it's hard to say for sure, especially without a proper MCVE ( see ).


Here's another example which does this via custom painting only. An approach like this should be easier to animate. This might not normally be feasible, except that the only "real" component we're dealing with here is the text itself.

仅定制绘画的示例

package mcve;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.imageio.*;
import java.net.*;
import java.io.*;
import java.util.*;

public class MouseoverPanels2 {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(MouseoverPanels2::new);
    }

    MouseoverPanels2() {
        JFrame frame = new JFrame("Mouseover Panels");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel buttons = new JPanel();
        buttons.setBackground(Color.WHITE);

        buttons.add(new MouseoverLabel("Queen",  QUEEN_IMG,  QUEEN_IMG_H));
        buttons.add(new MouseoverLabel("King",   KING_IMG,   KING_IMG_H));
        buttons.add(new MouseoverLabel("Rook",   ROOK_IMG,   ROOK_IMG_H));
        buttons.add(new MouseoverLabel("Knight", KNIGHT_IMG, KNIGHT_IMG_H));
        buttons.add(new MouseoverLabel("Pawn",   PAWN_IMG,   PAWN_IMG_H));

        frame.setContentPane(buttons);

        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    class MouseoverLabel extends JComponent {
        final JLabel label;
        final Image image, hover;

        final Dimension imageMaxSize;

        boolean isHovering = false;

        MouseoverLabel(String text, Image image, Image hover) {
            setLayout(new BorderLayout());
            setOpaque(false);

            this.image = Objects.requireNonNull(image);
            this.hover = Objects.requireNonNull(hover);

            imageMaxSize =
                new Dimension(Math.max(image.getWidth(this), hover.getWidth(this)),
                              Math.max(image.getHeight(this), hover.getHeight(this)));

            label = new JLabel(text);
            label.setForeground(Color.RED);
            label.setOpaque(false);
            label.setHorizontalAlignment(JLabel.CENTER);
            add(label, BorderLayout.CENTER);

            MouseoverListener ml = new MouseoverListener();

            addMouseListener(ml);
            label.addMouseListener(ml);
        }

        private Dimension getMax(Dimension size) {
            size.width = Math.max(size.width, imageMaxSize.width);
            size.height = Math.max(size.height, imageMaxSize.height);
            return size;
        }

        @Override
        public Dimension getPreferredSize() {
            return getMax(super.getPreferredSize());
        }
        @Override
        public Dimension getMinimumSize() {
            return getMax(super.getMinimumSize());
        }
        @Override
        public Dimension getMaximumSize() {
            return getMax(super.getMaximumSize());
        }

        @Override
        protected void paintChildren(Graphics g) {
            // Note that the label is always "visible",
            // so it will e.g. receive mouse events even
            // while we aren't painting it.
            // If the label needs to receive, say, mouse
            // clicks, then you need to check isHovering
            // in the mouse click listener.
            // If the label is a JButton, then you could
            // call button.setEnabled(isHovering) in the
            // MouseoverListener.
            if (isHovering) {
                paintImage(g, hover);
                super.paintChildren(g);
            } else {
                paintImage(g, image);
            }
        }

        private void paintImage(Graphics g, Image image) {
            int w = image.getWidth(this);
            int h = image.getHeight(this);
            int x = (getWidth() - w) / 2;
            int y = (getHeight() - h) / 2;
            g.drawImage(image, x, y, w, h, this);
        }

        class MouseoverListener extends MouseAdapter {
            @Override
            public void mouseEntered(MouseEvent e) {
                recomputeView(e);
            }
            @Override
            public void mouseExited(MouseEvent e) {
                recomputeView(e);
            }
            void recomputeView(MouseEvent e) {
                Component comp = e.getComponent();
                Point     loc  = SwingUtilities.convertPoint(comp, e.getPoint(), MouseoverLabel.this);
                isHovering     = contains(loc);
                repaint();
            }
        }
    }

    static final Image QUEEN_IMG,
                       QUEEN_IMG_H,
                       KING_IMG,
                       KING_IMG_H,
                       ROOK_IMG,
                       ROOK_IMG_H,
                       KNIGHT_IMG,
                       KNIGHT_IMG_H,
                       PAWN_IMG,
                       PAWN_IMG_H;
    static {
        try {
            // source for sprite sheet: https://stackoverflow.com/a/19209651/2891664
            BufferedImage sprites = ImageIO.read(new URL("https://i.stack.imgur.com/memI0.png"));
            int n = 64;
            QUEEN_IMG    = sprites.getSubimage(0 * n, 0, n, n);
            QUEEN_IMG_H  = sprites.getSubimage(0 * n, n, n, n);
            KING_IMG     = sprites.getSubimage(1 * n, 0, n, n);
            KING_IMG_H   = sprites.getSubimage(1 * n, n, n, n);
            ROOK_IMG     = sprites.getSubimage(2 * n, 0, n, n);
            ROOK_IMG_H   = sprites.getSubimage(2 * n, n, n, n);
            KNIGHT_IMG   = sprites.getSubimage(3 * n, 0, n, n);
            KNIGHT_IMG_H = sprites.getSubimage(3 * n, n, n, n);
            PAWN_IMG     = sprites.getSubimage(4 * n, 0, n, n);
            PAWN_IMG_H   = sprites.getSubimage(4 * n, n, n, n);
        } catch (IOException x) {
            throw new UncheckedIOException(x);
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM