2

我是 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

4 回答 4

4

阅读具有透明度的背景,了解有关透明度如何工作以及一些可能的解决方案的信息。

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

  1. 不要使用空布局。Swing 被设计为与布局管理器一起使用,这里列出的原因有很多。
  2. 自定义绘画是通过覆盖paintComponent()(没有“s”)来完成的。但是,在您的情况下,如果您遵循我上面提供的链接中的建议,我认为没有任何理由进行自定义绘画。我也不认为您需要在面板中进行自定义绘画,但我并不完全理解您要做什么。
于 2013-09-20T05:10:56.707 回答
2

使用javax.swing.Timer而不是 java.util.Timer。看看这个来自 oracle的关于计时器和摇摆的教程。

于 2013-09-20T05:29:57.450 回答
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 中图标支持的更多详细信息。

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

于 2013-09-20T05:32:13.850 回答
0

我不敢相信仍然没有人回答正确的答案。以下是解决此类问题的方法:

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

它将防止在具有透明背景的组件上出现绘画问题。

于 2017-12-22T16:19:28.427 回答