JLabel文本被覆盖在透明的bg上

时间:2013-09-20 05:08:47

标签: java swing jlabel paintcomponent

我是java的新手,我试图创建一个像桌面小部件的应用程序,我已经使JPanel透明。我上面有两个JLabel,一个用于保存图像,另一个用于显示时间。我有一个计时器来更新JLabel中显示的时间。但是,在jlabel背后的透明JPanel文本被覆盖而不是替换。在谷歌搜索和查看stackoverflow后,我尝试了许多方法来覆盖JLabel的paintcomponent方法。但它并没有影响任何事情。后来我手动调用了计时器中的paintcomponent方法。但我觉得它只是一种解决方法。我需要知道为什么paintcomponent没有被调用以及通常何时被调用。

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.RepaintManager;
import javax.swing.SwingConstants;
import javax.swing.text.SimpleAttributeSet;

import java.awt.BorderLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class WindowSample {

private JFrame frame;
MyLabel panel1;

// JLabel panel1;

/**
 * Launch the application.
 */
public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                WindowSample window = new WindowSample();
                window.frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

/**
 * Create the application.
 */
public WindowSample() {
    initialize();
}

/**
 * Initialize the contents of the frame.
 */
private void initialize() {
    frame = new JFrame();
    Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
    frame.setSize(dim);
    frame.setBounds(0, 0, 500, 500);
    frame.setBackground(new Color(0, 255, 0, 0));
    frame.setUndecorated(true);
    frame.setContentPane(new ContentPane());
    frame.getContentPane().setBackground(Color.WHITE);
    frame.getContentPane().setLayout(null);

    // ImagePanel panel = new ImagePanel();
    JLabel panel = new JLabel(
            scale(new ImageIcon("Science Drops.png").getImage()));
    panel.setBounds(0, 0, 200, 200);

    panel1 = new MyLabel();
    // panel1 = new JLabel();

    panel1.setHorizontalAlignment(SwingConstants.CENTER);
    panel1.setAlignmentX(SwingConstants.CENTER);
    panel1.setFont(new Font("Calibiri",Font.BOLD,16));
    panel1.setBounds(0, 205, 200, 50);
    Timer n = new Timer();
    panel1.setBackground(Color.white);

    n.scheduleAtFixedRate(new TimerTask() {

        @Override
        public void run() {
            DateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
            // this manual call to paintComponent did the trick. If i remove this line the text gets overwritten over itself for every second.
                            panel1.paintComponents(panel1.getGraphics());
            panel1.setText(df.format(new Date()));

        }
    }, 1000, 1000);
    frame.getContentPane().add(panel1);
    frame.getContentPane().add(panel);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

}

@SuppressWarnings("serial")
public class MyLabel extends JLabel {
    MyLabel() {
        setOpaque(false);
    }

    @Override
    public void paintComponents(Graphics arg0) {
        Graphics2D g2d = (Graphics2D) arg0.create();
        g2d.clearRect(0, 0, getWidth(), getHeight());
        g2d.dispose();
                    super.paintComponents(arg0);
    }
}

public class ContentPane extends JPanel {

    public ContentPane() {

        setOpaque(false);

    }

    @Override
    protected void paintComponent(Graphics g) {

        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.0f));

        g2d.setColor(getBackground());
        g2d.fill(getBounds());

        g2d.dispose();
        super.paintComponent(g);

    }

}

public ImageIcon scale(Image src) {
    int w = 200;
    int h = 200;
    int type = BufferedImage.TYPE_INT_ARGB;
    BufferedImage dst = new BufferedImage(w, h, type);
    Graphics2D g2 = dst.createGraphics();
    g2.drawImage(src, 0, 0, w, h, frame);
    g2.dispose();
    return new ImageIcon(dst);
}
}

4 个答案:

答案 0 :(得分:4)

阅读Backgrounds With Transparency,了解有关透明度如何运作的信息以及一些可能的解决方案。

此外,您的代码还有其他一些评论:

  1. 不要使用null布局。 Swing旨在与布局管理器一起使用,其原因有很多,可在此处列出。
  2. 通过覆盖paintComponent()(无“s”)来完成自定义绘制。但是,在您的情况下,如果您按照我上面提供的链接中的建议,我认为没有任何理由进行自定义绘画。我也不认为你需要在你的面板上做自定义绘画,但我不完全明白你想要做什么。

答案 1 :(得分:2)

使用javax.swing.Timer代替java.util.Timer。看一下关于计时器和摇摆的this tutorial from oracle

答案 2 :(得分:2)

你似乎正在努力解决这个问题......

  1. 标签默认是透明的。
  2. 标签支持开箱即用的图标(包括GIF动画;))
  3. null布局从来都不是一个好主意,它们似乎是一个好主意,但你会花更多的时间来纠正有趣的小不一致性,这些不一致性可以通过适当的布局管理器来解决......
  4. java.util.Timer不是Swing的合适计时器,而是您想要使用javax.swing.Timer。它将在EDT的背景下触发它的更新。
  5. 基于我认为你想做的事情......

    enter image description here

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.EventQueue;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import javax.swing.ImageIcon;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class MyClock {
    
        public static void main(String[] args) {
            new MyClock();
        }
    
        public MyClock() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    final DateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
                    final JLabel label = new JLabel(df.format(new Date()));
                    label.setIcon(new ImageIcon("Clock.png"));
    
                    Timer timer = new Timer(500, new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            label.setText(df.format(new Date()));
                        }
                    });
                    timer.start();
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.setUndecorated(true);
                    frame.setBackground(new Color(0, 255, 0, 0));
                    frame.add(label);
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    }
    

    有关Swing中图标支持的更多详细信息,请查看How to use icons

    您可能还会发现Window#alwaysOnTop有用(请记住,所有帧都会导致Window

答案 3 :(得分:0)

我无法相信仍有人没有回答正确的答案。以下是您如何解决这类问题:

setOpaque(false)应用于您的组件,但也应用于所有父母

它可以防止具有透明背景的组件上的绘画问题。