在 JLabel 上显示交互式圆形覆盖

Posted

技术标签:

【中文标题】在 JLabel 上显示交互式圆形覆盖【英文标题】:Display interactive circular overlay on JLabel 【发布时间】:2021-11-11 00:39:10 【问题描述】:

我有一个 JFrame,其中包含一个显示 BufferedImage 的 JLabel。 当我将鼠标悬停在此图像上时,我需要在鼠标包含另一个图像的地方显示一个圆形叠加层。

到目前为止我的代码:

JFrame frame = new JFrame();
GridBagLayout layout = new GridBagLayout();
frame.getContentPane().setLayout(gLayout);
JLabel myLabel= new JLabel(new ImageIcon(baseImage));
GridBagConstraints constraints = new GridBagConstraints();
...
frame.getContentPane().add(myLabel, constraints);

现在我需要在鼠标显示另一个 BufferedImage 的位置显示一个圆形叠加层。

所以我需要这样的东西:

myLabel.onMouseHover(event -> 
    Pane p = new Pane();
    x = event.x;
    y = event.y;
    p.setImage(newImage);
    // draw this pane on the label but with an offset for it to be at the center
    myLabel.draw(pane, x - offset, y - offset);
)

【问题讨论】:

我需要在鼠标的位置显示一个圆形叠加层 - 你是说这个“叠加层”需要在你在图像周围移动鼠标时跟随鼠标,还是覆盖显示在标签上的固定位置? 请注意,您可以将叠加图像直接绘制到baseImage,或从baseImage 复制的另一个图像上。这样你就不需要处理多个图层了,你只需使用鼠标悬停事件和鼠标坐标来计算出从一个图像中绘制哪些像素到baseImage @camickr 是的,我需要使用鼠标移动覆盖层 查看How to Decorate Components With the JLayer Class。 Responding to Events 上的部分听起来像你想要的。而不是绘制“聚光灯”,而是绘制图像。 @camickr 我会试试的。谢谢! 【参考方案1】:

如果我理解正确,那么您有点想要“透视”样式效果。如果您不这样做并且想要在鼠标点处显示静态图像,则“基本”想法将起作用,您只需将覆盖的图像重新定位到正确的位置。

此示例采用两个相同大小的图像,当您四处移动鼠标时,它会使其看起来好像您正在“透视”主图像。这是幻觉,但大多数这样的效果都是。

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Test 

    public static void main(String[] args) 
        new Test();
    

    public Test() 
        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 

        private Point mousePoint;

        private BufferedImage background;
        private BufferedImage seeThrough;

        public TestPane() 

            try 
                background = ImageIO.read(BYO your own image));
                seeThrough = ImageIO.read(BYO your own image));
             catch (IOException ex) 
                ex.printStackTrace();;
            

            MouseAdapter ma = new MouseAdapter() 
                @Override
                public void mouseMoved(MouseEvent e) 
                    mousePoint = e.getPoint();
                    repaint();
                

                @Override
                public void mouseExited(MouseEvent e) 
                    mousePoint = null;
                    repaint();
                

            ;

            addMouseMotionListener(ma);
            addMouseListener(ma);
        

        @Override
        public Dimension getPreferredSize() 
            if (background != null) 
                return new Dimension(background.getWidth(), background.getHeight());
            

            return new Dimension(200, 200);
        

        @Override
        protected void paintComponent(Graphics g) 
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();

            g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
            g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));

            if (background != null) 
                g2d.drawImage(background, 0, 0, this);
            

            if (seeThrough != null && mousePoint != null) 
                double radius = 45;
                Ellipse2D.Double clip = new Ellipse2D.Double(mousePoint.x - radius, mousePoint.y - radius, radius * 2, radius * 2);
                g2d.setClip(clip);
                g2d.drawImage(seeThrough, 0, 0, this);
            

            g2d.dispose();
        

    

但这不使用JLabel

不,它没有。 JLabel 是 ... 代码中的痛苦。没有办法确定图像的位置,假设这对你很重要,但在大多数情况下,我更愿意控制。你可以用JLabel 做类似的事情,从概念上讲是一样的想法。

另一种解决方案可能是直接在目标组件顶部使用一种“覆盖”面板,例如

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Test 

    public static void main(String[] args) 
        new Test();
    

    public Test() 
        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() 
            setLayout(new BorderLayout());
            JLabel label = new JLabel();
            OverlayPane overlayPane = new OverlayPane(label);
            try 
                label.setIcon(new ImageIcon(ImageIO.read(BYO your own image))));
             catch (IOException ex) 
                ex.printStackTrace();;
            

            add(overlayPane);
        

    

    public class OverlayPane extends JPanel 

        public OverlayPane(JComponent child) 
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.fill = GridBagConstraints.BOTH;

            add(new GlassPane(), gbc);
            add(child, gbc);
        

        protected class GlassPane extends JPanel 

            private Point mousePoint;
            private BufferedImage pointer;

            public GlassPane() 
                try 
                    pointer = ImageIO.read(BYO your own image));
                 catch (IOException ex) 
                    ex.printStackTrace();
                

                MouseAdapter ma = new MouseAdapter() 
                    @Override
                    public void mouseMoved(MouseEvent e) 
                        mousePoint = e.getPoint();
                        repaint();
                    

                    @Override
                    public void mouseExited(MouseEvent e) 
                        mousePoint = null;
                        repaint();
                    

                ;

                addMouseMotionListener(ma);
                addMouseListener(ma);

                setOpaque(false);
            

            @Override
            protected void paintComponent(Graphics g) 
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();

                g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
                g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));

                if (pointer != null && mousePoint != null) 
                    double radius = Math.max(pointer.getWidth() + 10, pointer.getHeight() + 10) / 2;
                    g2d.setColor(Color.WHITE);
                    Ellipse2D.Double clip = new Ellipse2D.Double(mousePoint.x - radius, mousePoint.y - radius, radius * 2, radius * 2);
                    g2d.fill(clip);
                    int x = (int) (mousePoint.x - radius) + 5;
                    int y = (int) (mousePoint.y - radius) + 5;
                    g2d.drawImage(pointer, x, y, this);
                

                g2d.dispose();
            
        

    

或者,您可以直接使用框架的glassPane,但需要驱动器

Annnd JLayer style concept - 当然,它允许您绘制点,但它应该为您提供使图像移动到顶部所需的内容

【讨论】:

这正是我所需要的。我为 JPanel 放弃了 JLabel,它变得容易多了。

以上是关于在 JLabel 上显示交互式圆形覆盖的主要内容,如果未能解决你的问题,请参考以下文章

Mil学习之显示鼠标交互交互绘图交互Mask

在 iOS 中检测不活动(无用户交互)以显示单独的屏幕,如覆盖

Android 使用圆形揭露动画巧妙地隐藏或显示View

Android 使用圆形揭露动画巧妙地隐藏或显示View

d3友好的交互

d3友好的交互