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

问题描述 投票:2回答:4

我是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);
}
}
java swing jlabel paintcomponent
4个回答
4
投票

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

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

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

2
投票

使用javax.swing.Timer而不是java.util.Timer。看看this tutorial from oracle有关计时器和挥杆的信息。


2
投票

你好像在努力解决这个问题......

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

基于我认为你想做的事情......

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


0
投票

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

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

它将防止具有透明背景的组件上的绘制问题。

© www.soinside.com 2019 - 2024. All rights reserved.