【问题标题】:Two JLabels copying backgrounds and contents from each other on mouse over两个 JLabel 在鼠标悬停时相互复制背景和内容
【发布时间】:2016-02-16 04:05:25
【问题描述】:

我正在尝试为几个用文本填充的 JLabel 元素创建 mouseOver 视觉效果。这个想法是在鼠标进入时使每个标签变暗,然后在鼠标离开其区域时使其恢复正常。此外,所有标签都放置在具有背景图像的面板上。

虽然很简单,但我遇到了我无法克服的恶劣行为。

错误 1:当我第一次将鼠标移到标签上时,它会显示主窗口的左上角作为其背景。

错误 2:然后,每次我将鼠标移到一个标签上一次,然后将其移到第二个标签上,第二个标签的背景就会更改为第一个标签的“总和背景”(面板图像 + 半透明背景)。除此之外,似乎甚至第一个标签的文本内容都被“复制”到了第二个标签的背景。每次标签更改只发生一次:如果我将鼠标移到同一个标签上两次,则第二个鼠标悬停事件被正确绘制。

我已经尝试使用 MouseMotionListener,一个不同的元素 (JButton),使用组件修改方法并尝试覆盖绘制方法。没有结果。

我附上了一个动画 GIF,显示了所描述的行为: Two JLabels copying backgrounds and contents from each other

我对 Swing 比较陌生,所以我不熟悉它的注意事项。知道是什么原因造成的吗?

自定义面板类:

public class ImagePanel extends JPanel{
    private static final long serialVersionUID = -3995745756635082049L;

    private Image image = null;

    public ImagePanel(Image image){
        this.image = image;
    }

    public void paintComponent(Graphics g){
        super.paintComponent(g);
        if(image != null){
            g.drawImage(image, 0, 0, this);
        }
    }
}

MouseListener 类:

public class MouseHoverPiece implements MouseListener{

private static final Cursor CURSOR_HAND = new Cursor(Cursor.HAND_CURSOR);
private static final Cursor CURSOR_DEFAULT = new Cursor(Cursor.DEFAULT_CURSOR);
private static final Color HOVER_SHADOW = new Color(40, 80, 60, 50);

@Override
public void mouseEntered(MouseEvent e) {
    JLabel component = (JLabel)e.getComponent();
    component.setBackground(HOVER_SHADOW);
    component.setCursor(CURSOR_HAND);
    component.setOpaque(true);
    component.repaint();
}

@Override
public void mouseExited(MouseEvent e) {
    JLabel component = (JLabel)e.getComponent();
    component.setBackground(null);
    component.setCursor(CURSOR_DEFAULT);
    component.setOpaque(false);
    component.repaint();
}

MainWindow 类:

Image background = ResourceLoader.loadImage("board.png");
ImagePanel panel = new ImagePanel(background);
panel.setBounds(10, 55, 480, 480);
panel.setLayout(null);
panel_main.add(panel);

final JLabel lblNewLabel1 = new JLabel("N");
lblNewLabel1.setHorizontalAlignment(SwingConstants.CENTER);
lblNewLabel1.setOpaque(false);
lblNewLabel1.setBounds(25, 24, 52, 52);
lblNewLabel1.setFont(lblNewLabel1.getFont().deriveFont(42f));
lblNewLabel1.addMouseListener(new MouseHoverPiece());
panel.add(lblNewLabel1);

final JLabel lblNewLabel2 = new JLabel("O");
lblNewLabel2.setHorizontalAlignment(SwingConstants.CENTER);
lblNewLabel2.setOpaque(false);
lblNewLabel2.setBounds(25+52+2, 24, 52, 52);
lblNewLabel2.setFont(lblNewLabel2.getFont().deriveFont(42f));
lblNewLabel2.addMouseListener(new MouseHoverPiece());
panel.add(lblNewLabel2);

【问题讨论】:

  • 请避免setBounds(...),通常是新手代码的标志。我猜你的图片是半透明的,对吗?
  • 我应该使用什么来代替边界?我只需要将标签的大小强制为固定尺寸。面板的图像和标签的错误背景是不透明的,而我要应用的鼠标悬停背景是 50% 透明。
  • What should I use instead of bounds? - 你使用layout managers
  • 是的,我尝试了 GridLayout,但在相对定位方面遇到了一些问题。会再试一次,谢谢。

标签: java swing background jlabel mouseover


【解决方案1】:
private static final Color HOVER_SHADOW = new Color(40, 80, 60, 50);

Swing 组件在透明背景方面存在问题,因为您违反了规定不透明组件将完全绘制背景的绘制规则。

查看Backgrounds With Transparency 了解更多信息和一些解决问题的方法。您可以:

  1. 在标签上进行自定义绘制以手动绘制背景
  2. 使用包装器组件并让该组件为您绘制。

【讨论】:

  • 我在调查我的问题时阅读了上述文章。实际上,我的一些代码基于它。但我想我正在开始理解这个问题(“规定不透明组件将完全绘制背景的规则”)。
【解决方案2】:

我想我已经找到了解决方案。两个虫子都消失了。我所做的是添加父容器(在我的情况下是具有板背景的面板)重绘:

@Override
public void mouseEntered(MouseEvent e) {
    JLabel component = (JLabel)e.getComponent();
    component.setBackground(HOVER_SHADOW);
    component.setCursor(CURSOR_HAND);
    component.setOpaque(true);
    Container container = component.getParent();
    component.repaint();
    container.repaint(); //fix
}

@Override
public void mouseExited(MouseEvent e) {
    JLabel component = (JLabel)e.getComponent();
    component.setBackground(null);
    component.setCursor(CURSOR_DEFAULT);
    component.setOpaque(false);
    Container container = component.getParent();
    component.repaint();
    container.repaint(); //fix
}

感谢大家的帮助;)

【讨论】:

  • 不需要在子组件上调用 repaint()。当您重新绘制父级时,所有子级都将重新绘制。这并不是一个真正合适的解决方案。当您更改组件的属性时,该组件负责重新绘制自身。您的应用程序代码不需要知道必须先重新绘制父级。
  • 有趣...虽然没有在父级上调用 repaint 它不起作用。我在几篇文章中读到,由于 Swing 实现错误,在更改某些特定属性时需要重新绘制。我不是在争论,只是想了解做事的正确方法。在 Swing 方面,我 12 年的 Java 经验似乎毫无意义......
  • 您将基于 alpha 的颜色应用于不透明组件这一事实是问题的原因,其他任何事情都只是可能导致进一步问题的 hack
猜你喜欢
  • 2013-07-10
  • 2013-12-09
  • 1970-01-01
  • 1970-01-01
  • 2018-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多