Java Trayicon Using Image with Transparent Background

java TrayIcon using image with transparent background

Chances are this problem cannot be resolved. It depends on wether Java is doing a good job in creating the tray subwindow in Linux or not. If Jave does it wrong, transparency is already lost when the image is drawn.

  1. What is the real background value of the icon you are using? Is it the gray tone shown above? Set it to purple to see if the transparency of the image is used (Java defaults to gray background) or not.

  2. Make sure you tried both transparency options of PNG: transparent color index as well as alpha channel. Alpha channel is very common in Linux, not so in the Windows world.

  3. The resolution of your icon is too small. Do it in 64x64 or better 128x128. AFAIK there is no standard resolution for tray icons, and even if so, it is certainly not 16x16.

  4. Another format you could try is SVG. Only try that after making sure that the transparency of the image is the problem (see 1).

See here for background information on this issue:
http://www.rasterman.com/index.php?page=News (scroll down to 2 February 2006)

System Tray icon looks distorted

After you've retrieved the actual image resource from disk, you can resize it to the size you need by creating a "fake" one on-the-fly and taking its width.

I found that this was better than using the setImageAutoSize(true) method, as that method does not scale the image smoothly at all.

BufferedImage trayIconImage = ImageIO.read(getClass().getResource("/path/to/icon.png"));
int trayIconWidth = new TrayIcon(trayIconImage).getSize().width;
TrayIcon trayIcon = new TrayIcon(trayIconImage.getScaledInstance(trayIconWidth, -1, Image.SCALE_SMOOTH));

Change System tray Icon in java

images/Graph.png is not a valid URL for an image located in your jar. Hence, I guess that img is null on your second try.

I suggest you this way :

//Get the URL with method class.getResource("/path/to/image.png")
URL url = System.class.getResource("/images/Graph.png");

//Use it to get the image
Image img = Toolkit.getDefaultToolkit().getImage(url);

final TrayIcon trayIcon = new TrayIcon(img, "Application Name", popup);

You shall also ensure that images/ is in your classpath.

Transparent JTexfield with background image

All Swing components have a concept of transparency, which is controlled via the use of opaque property. Setting the background to null tents to rest the background color of the field to it's UI default.

Having said that, some components can ignore this (partially or completely). In these case we can cheat...

In the following example, set the field transparent via the opaque property, this is important, as the RepaintManager will not paint areas behind components unless they are transparent, and use a fully transparent background color.

Field

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestTextField {

public static void main(String[] args) {
new TestTextField();
}

public TestTextField() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}

JTextField field = new JTextField(20);
field.setBackground(new Color(0, 0, 0, 0));
field.setOpaque(false);

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.RED);
frame.setLayout(new GridBagLayout());
frame.add(field);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

}

Updated based on comments...

This is a very specific example designed to provide a direct answer to the presented problem. Basically, what this does is creates a custom border and uses an Image to render the "border"

Border example

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.AbstractBorder;
import javax.swing.border.Border;
import javax.swing.border.MatteBorder;

public class TestTextField {

public static void main(String[] args) {
new TestTextField();
}

public TestTextField() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}

JTextField field = new JTextField(20);
try {
BufferedImage img = ImageIO.read(getClass().getResource("/FieldBorder.png"));
field.setBorder(new ImageBorder(img, 8, 6));
} catch (IOException ex) {
ex.printStackTrace();
}

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
frame.add(field);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

public class ImageBorder implements Border {

private BufferedImage img;
private int bottomMargin;
private int leftMargin;

public ImageBorder(BufferedImage img, int leftMargin, int bottomMargin) {
this.img = img;
this.bottomMargin = bottomMargin;
this.leftMargin = leftMargin;
}

@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
g.drawImage(img, x, y + height - img.getHeight(), c);
}

@Override
public Insets getBorderInsets(Component c) {
return new Insets(0, leftMargin, bottomMargin, 0);
}

@Override
public boolean isBorderOpaque() {
return false;
}

}

}

Now, this could also be done using custom painting within the custom Border instead, but was quicker this way ;)

Another option...

Is to simply use a JPanel and add the field and a JLabel holding the border outline together, for example...

CompoundField

import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;

public class TestTextField {

public static void main(String[] args) {
new TestTextField();
}

public TestTextField() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}

JTextField field = new JTextField(20);
field.setBorder(null);

JPanel fieldPane = new JPanel(new GridBagLayout());
fieldPane.setBackground(Color.WHITE);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.anchor = GridBagConstraints.WEST;
gbc.insets = new Insets(0, 8, 0, 0);
fieldPane.add(field, gbc);

try {
BufferedImage img = ImageIO.read(getClass().getResource("/FieldBorder.png"));
gbc.insets = new Insets(0, 0, 0, 0);
fieldPane.add(new JLabel(new ImageIcon(img)), gbc);
} catch (IOException ex) {
ex.printStackTrace();
}

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
frame.add(fieldPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

}

But this will come down to needs and requirements...

Text field with a background

Textfield with background

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.Document;

public class TextFieldBackground {

public static void main(String[] args) {
new TextFieldBackground();
}

public TextFieldBackground() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}

TextFieldWithBackground field = new TextFieldWithBackground(40);
try {
field.setBackgroundImage(ImageIO.read(getClass().getResource("/clouds.jpg")));
} catch (IOException ex) {
ex.printStackTrace();
}

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
frame.add(field);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

public class TextFieldWithBackground extends JTextField {

private BufferedImage bg;

public TextFieldWithBackground() {
}

public TextFieldWithBackground(String text) {
super(text);
}

public TextFieldWithBackground(int columns) {
super(columns);
}

public TextFieldWithBackground(String text, int columns) {
super(text, columns);
}

public TextFieldWithBackground(Document doc, String text, int columns) {
super(doc, text, columns);
}

public void setBackgroundImage(BufferedImage bg) {
this.bg = bg;
setOpaque(bg == null);
repaint();
}

@Override
protected void paintComponent(Graphics g) {
if (bg != null) {
int x = 0;
int y = (getHeight() - bg.getHeight()) / 2;
while (x < getWidth()) {
g.drawImage(bg, x, y, this);
x += bg.getWidth();
}
}
super.paintComponent(g);
}

}

}

Blank icon on system tray

Most probably your image is larger than the tray icon size and gets cropped. That's why you see the icon as blank. So you have to set,
trayIcon.setImageAutoSize(true);

JavaDoc:

public void setImageAutoSize(boolean autosize)

Sets the auto-size property. Auto-size determines whether the tray
image is automatically sized to fit the space allocated for the image
on the tray. By default, the auto-size property is set to false.

If auto-size is false, and the image size doesn't match the tray icon
space, the image is painted as-is inside that space — if larger than
the allocated space, it will be cropped.

If auto-size is true, the image is stretched or shrunk to fit the tray
icon space.



Related Topics



Leave a reply



Submit