Reputation: 29
Im a newbie to java, Im trying to create an application like a desktop widget for which i have made the JPanel transparent. I have two JLabels on top of it one for holding an image and other for displaying time. I had a timer to update the time displayed in the JLabel. But With a transparent JPanel behind the jlabel's text gets overwritten instead of replacement. After Googling and Looking up on stackoverflow i tried many methods to override the paintcomponent method of the JLabel. But it didnt affect anything. Later I manually called the paintcomponent method inside the timer which worked out. But I feel its just a workaround. I need to know why the paintcomponent didnt get invoked and when it usually gets invoked.
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);
}
}
Upvotes: 3
Views: 1205
Reputation: 2526
I can't believe there is still nobody who answered the right answer. Here's how you get away with this kind of problem :
Apply setOpaque(false)
to your components, but also to all the parents.
It will prevent painting problems on your components with transparent backgrounds.
Upvotes: 0
Reputation: 347314
You seem to be going about it the hard way...
null
layouts are never a good idea, they might seem like a good idea, but you will spend more time correcting for funny little inconsistencies which be resolved using an appropriate layout manager...java.util.Timer
is not a suitable timer for Swing, instead you want to use javax.swing.Timer
instead. It will trigger it's updates within the context of the EDT.Based off what I think you want to do...
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);
}
});
}
}
Take a look at How to use icons for more details about icon support in Swing.
You may also find Window#alwaysOnTop
useful (remember, all frames lead to Window
)
Upvotes: 2
Reputation: 16844
Use javax.swing.Timer instead of java.util.Timer. Have a look at this tutorial from oracle about timers and swing.
Upvotes: 2
Reputation: 324147
Read Backgrounds With Transparency for information on how transparency works and for some possible solutions.
Also, some other comments with your code:
Upvotes: 4