【问题标题】:java setOpaque(false) makes hovering slowjava setOpaque(false) 使悬停变慢
【发布时间】:2018-04-02 16:38:26
【问题描述】:

我通过扩展 JPanel 并使用 OverlayLayout 在彼此之上添加 2 个 JLabel 制作了一个按钮。其中一个 JLabels 是图标,它只是一个很棒的字体图标。另一个是悬停文本。我希望 JPanel 的背景是透明的,所以它没有白色边框。我使用这个 AlphaContainer 方法做到了这一点:

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

这就是我所说的缓慢悬停的意思:

我现在只将 setOpaque(false) 属性添加到图标的下半部分。 这是它的样子:

我在这里添加了 6 个按钮:

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);

这是我正在使用的按钮类:

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);
    }
}

我已经编辑了 RadioDef 中的代码以更符合我的需要,奇怪的是它没有出现在这段代码中

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);
        }
    }


}

我用悬停做的小项目:https://www.dropbox.com/s/wq4ggufbxrfcvb8/HoverButton.zip?dl=0

【问题讨论】:

    标签: java swing button graphics jpanel


    【解决方案1】:

    最好的方法可能是使用 CardLayout,它已经为良好的行为设置。

    这是一个 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);
            }
        }
    }
    

    我认为您看到的性能影响可能因为调用 setVisible may cause revalidate to be called 会调用布局管理器,但很难确定,尤其是没有适当的 MCVE (see )。


    这是另一个仅通过自定义绘画实现此目的的示例。像这样的方法应该更容易制作动画。这通常可能不可行,除了我们在这里处理的唯一“真实”组件是文本本身。

    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);
            }
        }
    }
    

    【讨论】:

    • 我玩过你的代码,发现当我让它看起来像我的例子时,它不会发生。您可以在主帖中找到我的编辑。
    • 好吧,我的建议是 1. 尝试在您的实际项目中使用 CardLayout 和/或 2. 看看您是否可以重现 MCVE 中的缓慢。你仍然可以使用CardLayout 来做一些更类似于你修改我的例子的事情。例如,您可以将标签放在绘制背景图像的面板中,或使用嵌套的OverlayLayout。 CardLayout 的意义在于它预先计算了所有大小,您可以在不调用 setVisible、revalidate 等的情况下切换组件。
    • 我真的很想使用 CardLayout。问题是我想做一个悬停过渡,所以图标从起始颜色变为深色,我希望文本出现,这一切都应该逐渐进行。我认为使用 CardLayout 是不可能的
    • 查看我的编辑以了解可能更容易制作动画的另一个想法。
    • 我检查了您的编辑,并尝试再次根据需要对其进行编辑。我用它做了一个小项目,只添加我需要的东西,比如透明度和背景。奇怪的是,在那个小项目中它并不慢,而在我的大项目中,它很慢。在主帖中我添加了一个小项目,它并不慢,不知道你是否可以用它做任何事情。
    猜你喜欢
    • 2011-05-04
    • 1970-01-01
    • 2015-04-02
    • 1970-01-01
    • 1970-01-01
    • 2013-05-16
    • 2010-12-04
    • 2015-03-09
    • 1970-01-01
    相关资源
    最近更新 更多