Java 在鼠标下放置JLabel?

Java 在鼠标下放置JLabel?,java,user-interface,mouse,Java,User Interface,Mouse,我正在制作一个鼠标事件侦听器和处理程序。我有这样的想法: JLabel status = new JLabel("I can change"); add(status, BorderLayout.SOUTH); 使用我的MouseListener,我正在根据给定的条件更改JLabel的文本。我可以轻松地将此JLabel放在一个位置,例如在窗口底部,如下所示: JLabel status = new JLabel("I can change"); add(status, BorderLayo

我正在制作一个鼠标事件侦听器和处理程序。我有这样的想法:

JLabel status = new JLabel("I can change");
add(status, BorderLayout.SOUTH);
使用我的MouseListener,我正在根据给定的条件更改JLabel的文本。我可以轻松地将此JLabel放在一个位置,例如在窗口底部,如下所示:

JLabel status = new JLabel("I can change");
add(status, BorderLayout.SOUTH);
但是我想做的是,获取JLabel,并将其直接显示在鼠标下。这将类似于

.setToolTipText
方法,但我不能使用它,因为我将鼠标移动到JDialog中的图像上,该图像是网格布局格式的。请解释如何将正在更改的JLabel直接放在鼠标下,就像.setToolTiptText一样

GridLayout中有两个图像,位于JDialog中:

    JDialog giraffewindow = new JDialog();
            Icon giraffe = new ImageIcon(getClass().getResource("giraffe.png"));
            Icon windows = new ImageIcon(getClass().getResource("windows.png"));

            giraffewindow.setLayout(new GridLayout(1, 2, 0, 0));
            giraffewindow.add(new JLabel (windows));
            giraffewindow.add(new JLabel (giraffe));

非常感谢您花这么多时间阅读本文,我非常感谢您为帮助一位程序员同事所付出的努力

为此,需要将
JLabel
的父容器(JDialog)的布局设置为绝对布局。这将允许您手动设置标签的位置

要将布局设置为null,请执行以下操作:

myPanel.setLayout(null);
然后,要设置标签的位置,请调用
setBounds
方法:

status.setBounds(int xPos, int yPos, int width, int height);
在您的情况下,每当移动鼠标时,您都会将
xPos
yPos
偶然移动到鼠标的坐标。如果需要一点偏移量,您可能还需要向坐标添加一些常量

例如:

    giraffewindow.add(status);

    giraffewindow.addMouseMotionListener(new MouseMotionListener() {

        @Override
        public void mouseMoved(MouseEvent evt) {
            status.setBounds(evt.getX(), evt.getY(), labelWidth,
                    labelHeight);
        }

        @Override
        public void mouseDragged(MouseEvent arg0) {}
    });

编辑:

我刚刚了解到,仍然可以在非绝对布局上设置边界,例如
GridLayout
。我以为只有绝对布局支持这一点,但快速测试证明了我的错误。然而,在
网格布局中添加另一个组件似乎有点混乱。我将在解决此问题时提供另一个更新


编辑2:

为了使
JLabel
不会弄乱布局,您有两个选项:

  • 使用
    玻璃窗格
    。将窗格玻璃视为覆盖其下方组件的一片玻璃。通过将
    JLabel
    而不是
    JDialog
    添加到玻璃窗格中,我们可以避免弄乱布局。见下文:

    JPanel glass = ((JPanel) giraffewindow.getGlassPane());
    glass.setVisible(true);
    glass.add(status);
    
    glass.addMouseMotionListener(new MouseMotionListener() {
    
        @Override
        public void mouseMoved(MouseEvent evt) {
            status.setBounds(evt.getX(), evt.getY(), labelWidth,
                    labelHeight);
        }
    
        @Override
        public void mouseDragged(MouseEvent arg0) {
        }
    });
    
    JLayeredPane layeredPane = new JLayeredPane();
    {
        JPanel imagePanel = new JPanel();
        layeredPane.add(imagePanel);
        layeredPane.setLayer(imagePanel, 0);
        imagePanel.setLayout(new GridLayout(1, 2, 0, 0));
        {
            imagePanel.add(new JLabel (windows));
            imagePanel.add(new JLabel (giraffe));
        }
    
        layeredPane.add(status);
        layeredPane.setLayer(status, 1);
    }
    giraffewindow.add(layeredPane);
    
  • 这种方法的问题在于它会截获所有鼠标事件,这意味着JButtons和类似的玻璃下面的东西不会被截获。一些可能的解决方法包括让玻璃查看每个鼠标事件,并决定是否应该将该事件传递给另一个组件。有关如何使用此概念的详细信息,请参见

  • 另一种可能性是使用
    JLayeredPane
    s。注意:我几乎没有使用
    JLayeredPane
    s的经验,因此可能会有一些小的误差。基本上,
    JLayeredPane
    允许您将组件分层。出于您的目的,我将创建两个层:一个层包含一个新的
    JPanel
    ,其中
    GridLayout
    包含图像,另一个层包含
    status
    移动标签。见下文:

    JPanel glass = ((JPanel) giraffewindow.getGlassPane());
    glass.setVisible(true);
    glass.add(status);
    
    glass.addMouseMotionListener(new MouseMotionListener() {
    
        @Override
        public void mouseMoved(MouseEvent evt) {
            status.setBounds(evt.getX(), evt.getY(), labelWidth,
                    labelHeight);
        }
    
        @Override
        public void mouseDragged(MouseEvent arg0) {
        }
    });
    
    JLayeredPane layeredPane = new JLayeredPane();
    {
        JPanel imagePanel = new JPanel();
        layeredPane.add(imagePanel);
        layeredPane.setLayer(imagePanel, 0);
        imagePanel.setLayout(new GridLayout(1, 2, 0, 0));
        {
            imagePanel.add(new JLabel (windows));
            imagePanel.add(new JLabel (giraffe));
        }
    
        layeredPane.add(status);
        layeredPane.setLayer(status, 1);
    }
    giraffewindow.add(layeredPane);
    
  • 不幸的是,这也存在同样的问题。您可以在
    JPanel
    中包围状态标签,并将鼠标侦听器添加到此面板,但不会将鼠标操作传递给下面的任何按钮。或者,您可以简单地将鼠标侦听器添加到主
    JDialog
    ,这意味着对捕获鼠标事件的组件(例如
    JButton
    )进行诅咒将阻止
    状态标签移动

    但是我不能使用-setToolTipText()

    为什么?

    我正在将鼠标移到图像上

    将鼠标移动到支持工具提示文本的JLabel上

    如果希望工具提示随鼠标移动,只需覆盖
    getToolTipLocation(…)
    方法,如下所示:

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.*;
    import javax.swing.plaf.*;
    import javax.swing.UIManager.*;
    
    
    public class ToolTipPanel extends JPanel
    {
        public ToolTipPanel()
        {
            setPreferredSize( new Dimension(200, 200) );
            setToolTipText("");
        }
    
        public void paintComponent(Graphics g)
        {
            g.setColor( Color.red );
            g.fillRect(0, 0, 100, 200);
            g.setColor( Color.blue );
            g.fillRect(100, 0, 100, 200);
        }
    
        @Override
        public String getToolTipText(MouseEvent e)
        {
            if (e.getX() < 100)
                return "red";
            else
                return "blue";
        }
    
        @Override
        public Point getToolTipLocation(MouseEvent e)
        {
            Point p = e.getPoint();
            p.y += 15;
    
            return p;
        }
    
        private static void createAndShowGUI()
        {
            JFrame frame = new JFrame("SSCCE");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new ToolTipPanel());
            frame.setLocationByPlatform( true );
            frame.pack();
            frame.setVisible( true );
        }
    
        public static void main(String[] args)
        {
            EventQueue.invokeLater(new Runnable()
            {
                public void run()
                {
                    createAndShowGUI();
                }
            });
        }
    }
    
    import java.awt.*;
    导入java.awt.event.*;
    导入javax.swing.*;
    导入javax.swing.*;
    导入javax.swing.plaf.*;
    导入javax.swing.UIManager.*;
    公共类ToolTipPanel扩展了JPanel
    {
    公共工具面板()
    {
    setPreferredSize(新尺寸(200200));
    setToolTipText(“”);
    }
    公共组件(图形g)
    {
    g、 setColor(Color.red);
    g、 fillRect(0,0,100,200);
    g、 setColor(Color.blue);
    g、 fillRect(100,0100200);
    }
    @凌驾
    公共字符串getToolTipText(MouseEvent e)
    {
    如果(如getX()<100)
    返回“红色”;
    其他的
    返回“蓝色”;
    }
    @凌驾
    公共点getToolTipLocation(MouseeEvent e)
    {
    点p=e.getPoint();
    p、 y+=15;
    返回p;
    }
    私有静态void createAndShowGUI()
    {
    JFrame=新JFrame(“SSCCE”);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(新的ToolTipPanel());
    frame.setLocationByPlatform(真);
    frame.pack();
    frame.setVisible(true);
    }
    公共静态void main(字符串[]args)
    {
    invokeLater(新的Runnable()
    {
    公开募捐
    {
    createAndShowGUI();
    }
    });
    }
    }
    

    另一种方法是使用JXLayer在移动鼠标时绘制文本。查看Swing教程中的
    响应事件
    示例,以获取入门示例。

    如果我将其设置为null,是否仍保留网格布局?抱歉,我在问题中遗漏了这一点。JDialog的布局是GridLayout吗?是的,JDialog中的GridLayout中有两个图像由于注释部分的代码格式不正确,我将编辑我的问题,将其放在inI中。我也尝试了你的方法,通过更改JLabel的坐标以对应于鼠标的坐标,我将在下面的评论中发表这一点。请注意,我这样做时没有将格式更改为null。执行此操作后,我收到错误消息,表示类型ActionEvent的getX方法未定义。