Java Swing图形故障处理透明度和图像

所以我有这个登录表单,我有一张“用户照片”。 我试图这样做,以便当您将鼠标hover在照片区域上时,将出现带有彩色背景的透明标签(以显示“选择照片”的效果)。 它看起来像这样:

此搜索

一旦你将鼠标移开,它就会被“取消选择”。

现在我的问题是,如果您先将鼠标hover在登录按钮上,然后将鼠标移到照片上,则会出现“幽灵登录按钮”。 它看起来像这样:

图像2

我不知道为什么会这样。 有人可以帮忙吗? 这是相关的代码:

package com.stats; public class Stats extends JFrame implements Serializable { private JLabel fader; public Stats() { try { Image image = ImageIO.read(new File(System.getenv("APPDATA") + "\\Stats\\Renekton_Cleave.png")); JLabel labelUserPhoto = new JLabel(new ImageIcon(image)); fader = new JLabel(); fader.setBounds(97, 44, 100, 100); fader.setOpaque(true); fader.setBackground(new Color(0, 0, 0, 0)); labelUserPhoto.setBounds(97, 44, 100, 100); PicHandler ph = new PicHandler(); contentPane.add(fader); contentPane.add(labelUserPhoto); fader.addMouseMotionListener(ph); } catch(Exception e) { e.printStackTrace(); } } private class PicHandler implements MouseMotionListener { public void mouseDragged(MouseEvent e) { } public void mouseMoved(MouseEvent e) { int x = e.getX(); int y = e.getY(); System.out.println("x: " + x + ", y: " + y); if ((x > 16 && x  16 && y < 80)) { if (!fader.isOpaque()) { fader.setOpaque(true); fader.setBackground(new Color(0, 0, 0, 40)); fader.repaint(); } } else { if (fader.isOpaque()) { fader.setOpaque(false); fader.repaint(); } } } } 

我可以看到你的例子有很多问题,但最重要的是使用带有alpha值的颜色。

 fader.setBackground(new Color(0, 0, 0, 40)); 

Swing不会很好地渲染具有基于alpha颜色的组件(在此上下文中)。 通过使组件不透明,然后设置背景颜色以使用alpha值,您告诉Swing它不需要担心绘制组件下面的内容,这不是真的……

Graphics上下文也是一个共享资源,这意味着在组件之前绘制的任何内容仍然被“绘制”,您需要在绘制之前清除Graphics上下文。

在此处输入图像描述在此处输入图像描述

这个例子使用了一个相当讨厌的技巧来完成它的工作。 因为所有绘画都发生在UI委托中,如果我们只是允许默认的绘画链继续,我们就无法在图标下面渲染。 相反,我们接管“脏”细节的控制并代表父母绘制背景。

如果我们简单地从像JPanel这样的东西扩展并自己绘制图像,这将更容易实现

 import java.awt.AlphaComposite; import java.awt.Color; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridBagLayout; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class FadingIcon { public static void main(String[] args) { new FadingIcon(); } public FadingIcon() { startUI(); } public void startUI() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { ex.printStackTrace(); } BufferedImage img = null; try { img = ImageIO.read(new File("C:\\Users\\swhitehead\\Documents\\My Dropbox\\Ponies\\SmallPony.png")); } catch (IOException ex) { ex.printStackTrace(); } JFrame frame = new JFrame("Testing"); frame.setLayout(new GridBagLayout()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new FadingLabel(new ImageIcon(img))); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class FadingLabel extends JLabel { private boolean mouseIn = false; private MouseHandler mouseHandler; public FadingLabel(Icon icon) { super(icon); setBackground(Color.RED); super.setOpaque(false)( } @Override public void setOpaque(boolean opaque) { } @Override public final boolean isOpaque() { return false; } protected MouseHandler getMouseHandler() { if (mouseHandler == null) { mouseHandler = new MouseHandler(); } return mouseHandler; } @Override public void addNotify() { super.addNotify(); addMouseListener(getMouseHandler()); } @Override public void removeNotify() { removeMouseListener(getMouseHandler()); super.removeNotify(); } @Override protected void paintComponent(Graphics g) { if (mouseIn) { Graphics2D g2d = (Graphics2D) g.create(); g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f)); g2d.setColor(getBackground()); g2d.fillRect(0, 0, getWidth(), getHeight()); g2d.dispose(); } getUI().paint(g, this); } public class MouseHandler extends MouseAdapter { @Override public void mouseEntered(MouseEvent e) { mouseIn = true; repaint(); } @Override public void mouseExited(MouseEvent e) { mouseIn = false; repaint(); } } } } 

我还建议您花时间学习如何使用合适的布局管理器,它们可以为您节省大量的时间

查看布局管理器的可视指南和在容器中布置组件

由于我无法发表评论,我必须将此作为答案:

正如trashgod所提到的,这个问题可能是由于缺少super.paintComponent(g)调用引起的,但是你似乎根本没有覆盖paintComponent方法(至少你没有在这里显示它)。 如果你覆盖了JFrame或任何JPanels的paintComponent方法,你需要:

 public void paintComponent(Graphics g) { super.paintComponent(g); //rest of your drawing code.... } 

但如果您根本没有使用过,那么问题可能是由其他原因造成的。

从jdk7开始,有一种新的机制来应用视觉装饰(以及监听子组件的事件):这就是JLayer / LayerUI对。

在您的情况下,自定义layerUI会

  • 在翻转时触发重画
  • 实现绘画以应用透明色

下面是一个示例,类似于教程中的WallPaperUI:

 // usage: create the component and decorate it with the custom ui JLabel label = new JLabel(myIcon); content.add(new JLayer(label, new RolloverUI())); // custom layerUI public static class RolloverUI extends LayerUI { private Point lastMousePoint; private JLayer layer; /** * Implemented to install the layer and enable mouse/motion events. */ @Override public void installUI(JComponent c) { super.installUI(c); this.layer = (JLayer) c; layer.setLayerEventMask(AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK); } @Override protected void processMouseMotionEvent(MouseEvent e, JLayer l) { updateLastMousePoint(e.getPoint()); } @Override protected void processMouseEvent(MouseEvent e, JLayer l) { if (e.getID() == MouseEvent.MOUSE_EXITED) { updateLastMousePoint(null); } else if (e.getID() == MouseEvent.MOUSE_ENTERED) { updateLastMousePoint(e.getPoint()); } } /** * Updates the internals and calls repaint. */ protected void updateLastMousePoint(Point e) { lastMousePoint = e; layer.repaint(); } /** * Implemented to apply painting decoration below the component. */ @Override public void paint(Graphics g, JComponent c) { if (inside()) { Graphics2D g2 = (Graphics2D) g.create(); int w = c.getWidth(); int h = c.getHeight(); g2.setComposite(AlphaComposite.getInstance( AlphaComposite.SRC_OVER, .5f)); g2.setPaint(new GradientPaint(0, 0, Color.yellow, 0, h, Color.red)); g2.fillRect(0, 0, w, h); g2.dispose(); } super.paint(g, c); } protected boolean inside() { if (lastMousePoint == null || lastMousePoint.x < 0 || lastMousePoint.y < 0) return false; Rectangle r = layer.getView().getBounds(); r.grow(-r.width / 10, -r.height / 10); return r.contains(lastMousePoint); } } 

在移动或resize后,我对幻影图像有类似的问题。 @MadProgrammer有一些非常好的点,但最后,它们对我不起作用(可能是因为我有多个层使用0.0 alpha值颜色,其中一些也有图像,所以我无法设置复合整个组件的价值)。 最后,修复它的是一个简单的调用

 .repaint() 

执行完所有绘制命令后。