Use of setIcon on jLabel repeats old image - java

I'm attempting to display an image that was downloaded from a website, with the use of setIcon and a jLabel
jLabel5.setIcon(new ImageIcon("image.png"));
At the start of the program, the image doesn't exist, it gets downloaded, and after that displayed, with no problems. But if it changes, even if it downloads a newer version of the image, it will display the old one, as if it had a cache of it or something.
Does someone know why this happens? How to get a workaround with or without this method?
I have also tried to do the following to see if it could help, with no success:
jLabel5.setIcon(null);
jLabel5.setIcon(new ImageIcon("image.png"));
It would display nothing and then the same old image again.

it will display the old one, as if it had a cache of it or something.
Yep, caching is the problem. Here are a couple of options:
// This works using ImageIO
imageLabel.setIcon( new ImageIcon(ImageIO.read( new File(imageName) ) ) );
// Or you can flush the image
ImageIcon icon = new ImageIcon(imageName);
icon.getImage().flush();
imageLabel.setIcon( icon );

Have you tried to use the SwingUtilities.invokeLater() method, similar to this:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//JLabel myLabel = new JLabel("Old Text");
jLabel5.setIcon(new ImageIcon("image.png"));
}
});
Taken from here.

If the problem is about caching, try downloading the image with a query string. For example, http://abc.co.th/image.png?t=149534274 The number is obtained from System.currentTimeMillis()

for example
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.*;
public class LabelsIcon extends JFrame implements Runnable {
private static final long serialVersionUID = 1L;
private JLabel label = new JLabel();
private Random random = new Random();
private boolean runProcess = true;
public LabelsIcon() {
label.setLayout(new BorderLayout());
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
label.setPreferredSize(new Dimension(d.width / 3, d.height / 3));
add(label, BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
new Thread(this).start();
}
#Override
public void run() {
while (runProcess) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
label.setIcon(new ImageIcon(getImage()));
}
});
try {
Thread.sleep(300);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public BufferedImage getImage() {
int w = label.getWidth();
int h = label.getHeight();
GradientPaint gp = new GradientPaint(0f, 0f, new Color(
127 + random.nextInt(128),
127 + random.nextInt(128),
127 + random.nextInt(128)),
w, w,
new Color(random.nextInt(128), random.nextInt(128), random.nextInt(128)));
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bi.createGraphics();
g2d.setPaint(gp);
g2d.fillRect(0, 0, w, h);
g2d.setColor(Color.BLACK);
return bi;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
LabelsIcon t = new LabelsIcon();
}
});
}
}

Related

How to set imageicon fix on jlabel

I am trying to make a java desktop application. I have a JLabel where I am shuffling image but all image sizes are different so I want to fix size of the image on JLabel.
How can I do this?
Here is my code :
public class ImageShuffle1 extends JPanel {
private List<Icon> list = new ArrayList<Icon>();
private List<Icon> shuffled;
private JLabel label = new JLabel();
private Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
update();
}
});
public ImageShuffle1() {
this.setLayout(new GridLayout(1, 0));
list.add(new ImageIcon("E:\\SOFTWARE\\TrainPIS\\res\\drawable\\e.jpg"));
list.add(new ImageIcon("E:\\SOFTWARE\\TrainPIS\\res\\drawable\\d.jpg"));
list.add(new ImageIcon("E:\\SOFTWARE\\TrainPIS\\res\\drawable\\yellow.png"));
list.add(new ImageIcon("E:\\SOFTWARE\\TrainPIS\\res\\drawable\\f.jpg"));
list.add(new ImageIcon("E:\\SOFTWARE\\TrainPIS\\res\\drawable\\l.jpg"));
//label.setIcon(UIManager.getIcon("OptionPane.informationIcon"));
for(Icon icon: list){
Image img = icon.getImage() ;
// put here the size properties
Image newimg = img.getScaledInstance( 45, 34, java.awt.Image.SCALE_SMOOTH ) ;
icon = new ImageIcon(newimg);
}
shuffled = new ArrayList<Icon>(list);
Collections.shuffle(shuffled);
timer.start();
}
private void update() {
if (shuffled.isEmpty()) {
shuffled = new ArrayList<Icon>(list);
Collections.shuffle(shuffled);
}
Icon icon = shuffled.remove(0);
label.setIcon(icon);
}
private void display() {
JFrame f = new JFrame("ImageShuffle");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.add(label);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ImageShuffle1().display();
}
});
}
}
I am getting error herein this.
line/variable getimage can not found mage img = icon.getImage() ;
Thanks in advance
Use BufferedImage in place of Icon that has a functionality to re size it.
Here is the code
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class ImageShuffle1 extends JPanel {
private List<BufferedImage> list = new ArrayList<BufferedImage>();
private List<BufferedImage> shuffled;
private JLabel label = new JLabel();
private int width = 50;
private int height = 100;
private Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
update();
}
});
public ImageShuffle1() {
try {
list.add(resizeImage(ImageIO.read(new File("resources/1.png"))));
list.add(resizeImage(ImageIO.read(new File("resources/2.png"))));
list.add(resizeImage(ImageIO.read(new File("resources/6.png"))));
list.add(resizeImage(ImageIO.read(new File("resources/Tulips.jpg"))));
} catch (IOException e) {
e.printStackTrace();
}
shuffled = new ArrayList<BufferedImage>(list);
Collections.shuffle(shuffled);
timer.start();
}
private BufferedImage resizeImage(BufferedImage originalImage) throws IOException {
BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, width, height, null);
g.dispose();
return resizedImage;
}
private void update() {
if (shuffled.isEmpty()) {
shuffled = new ArrayList<BufferedImage>(list);
Collections.shuffle(shuffled);
}
BufferedImage icon = shuffled.remove(0);
label.setIcon(new ImageIcon(icon));
}
private void display() {
JFrame f = new JFrame("ImageShuffle");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.add(label);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ImageShuffle1().display();
}
});
}
}
Lets start with this...
for(Icon icon: list){
Image img = icon.getImage() ;
Icon does not have a method getImage, there is actually no way to get the "image" data maintained by the Icon class without first rendering it to something (like a BufferedImage)
A better solution might be to load the images into a List that supports BufferedImage. BufferedImage is a more versatile starting point and because it extends from Image, it can be used with ImageIcon. For example...
private List<BufferedImage> list = new ArrayList<BufferedImage>();
//...
list.add(ImageIO.read("E:\\SOFTWARE\\TrainPIS\\res\\drawable\\e.jpg"));
Take a look at Reading/Loading an Image
For scaling you might like to take a look at
The Perils of Image.getScaledInstance
Java: maintaining aspect ratio of JPanel background image
Quality of Image after resize very low -- Java
First you resize every image to a fixed size and it must be fit in JLabel
public static Boolean resizeImage(String sourceImage, String destinationImage, Integer Width, Integer Height) {
BufferedImage origImage;
try {
origImage = ImageIO.read(new File(sourceImage));
int type = origImage.getType() == 0? BufferedImage.TYPE_INT_ARGB : origImage.getType();
//*Special* if the width or height is 0 use image src dimensions
if (Width == 0) {
Width = origImage.getWidth();
}
if (Height == 0) {
Height = origImage.getHeight();
}
int fHeight = Height;
int fWidth = Width;
//Work out the resized width/height
if (origImage.getHeight() > Height || origImage.getWidth() > Width) {
fHeight = Height;
int wid = Width;
float sum = (float)origImage.getWidth() / (float)origImage.getHeight();
fWidth = Math.round(fHeight * sum);
if (fWidth > wid) {
//rezise again for the width this time
fHeight = Math.round(wid/sum);
fWidth = wid;
}
}
BufferedImage resizedImage = new BufferedImage(fWidth, fHeight, type);
Graphics2D g = resizedImage.createGraphics();
g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(origImage, 0, 0, fWidth, fHeight, null);
g.dispose();
ImageIO.write(resizedImage, "png", new File(destinationImage));
...

Proper way to use JLabels to update an image

I am creating a GUI, and am fairly new to swing and awt. I am trying to create a gui that, upon launch, sets the background to an image, then uses a method to create a slideshow of sorts. I have attempted it, and I am not attached to the code so I am able to take both revisions and/or whole new concepts.
EDIT(9/15/13): I am having trouble with the slideshow, I cant seem to get it to work.
Here is my current code.
public class MainFrame extends JFrame{
JLabel backgroundL = null;
private JLabel bakckgroundL;
BufferedImage backimg;
Boolean busy;
double width;
double height;
public MainFrame() throws IOException {
initMainframe();
}
public void initMainframe() throws IOException {
//misc setup code, loads a default jpg as background
setTitle("Pemin's Aura");
busy = true;
String backgroundDir = "resources/frame/background.jpg";
backimg = ImageIO.read(new File(backgroundDir));
backgroundL = new JLabel(new ImageIcon(backimg));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
refreshframe();
setVisible(true);
busy = false;
}
public void adjSize() { // the attempted start of a fullscreen mode
GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(this);
width = this.getWidth();
height = this.getHeight();
setVisible(true);
}
public void setmastheadText() {//unfinished code
busy = true;
busy = false;
}
public void setbackground() {
add(backgroundL);
}
public void refreshframe() { //should refresh image?
setSize(2049, 2049);
setSize(2048, 2048);
}
public void loadingscreen() throws IOException, InterruptedException {
//this is the code in question that is faulty.
if (busy == false) {
busy = true;
String backgroundDir1 = "resources/frame/background.jpg";
String backgroundDir2 = "resources/frame/scr1.jpg";
String backgroundDir3 = "resources/frame/scr2.jpg";
BufferedImage backimg1 = ImageIO.read(new File(backgroundDir1));
BufferedImage backimg2 = ImageIO.read(new File(backgroundDir2));
BufferedImage backimg3 = ImageIO.read(new File(backgroundDir3));
backgroundL = new JLabel(new ImageIcon(backimg1));
Thread.sleep(2000);
setbackground();
setVisible(true);
backgroundL = new JLabel(new ImageIcon(backimg2));
setbackground();
setVisible(true);
Thread.sleep(2000);
bakckgroundL = new JLabel(new ImageIcon(backimg3));
setbackground();
setVisible(true);
if(backimg != null) {
backgroundL = new JLabel(new ImageIcon(backimg));;
}
}
busy = false;
}//end of loading screen
See ImageViewer for a working example of displaying images using a Swing based Timer.
See also How to use Swing Timers.
And while I'm here, another (prettier) example of animating an image. It uses this Mercator map of land masses. The image can be tiled horizontally, and therefore be scrolled left/right as needed.
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import javax.swing.*;
import java.net.URL;
import javax.imageio.ImageIO;
public class WorldView {
public static void main(String[] args) throws Exception {
URL url = new URL("http://i.stack.imgur.com/P59NF.png");
final BufferedImage bi = ImageIO.read(url);
Runnable r = new Runnable() {
#Override
public void run() {
int width = 640;
int height = 316;
Graphics2D g = bi.createGraphics();
float[] floats = new float[]{0f, .4f, .55f, 1f};
Color[] colors = new Color[]{
new Color(20, 20, 20, 0),
new Color(0, 10, 20, 41),
new Color(0, 10, 20, 207),
new Color(0, 10, 20, 230),};
final LinearGradientPaint gp2 = new LinearGradientPaint(
new Point2D.Double(320f, 0f),
new Point2D.Double(0f, 0f),
floats,
colors,
MultipleGradientPaint.CycleMethod.REFLECT);
final BufferedImage canvas = new BufferedImage(
bi.getWidth(), bi.getHeight() + 60,
BufferedImage.TYPE_INT_RGB);
final JLabel animationLabel = new JLabel(new ImageIcon(canvas));
ActionListener animator = new ActionListener() {
int x = 0;
int y = 30;
#Override
public void actionPerformed(ActionEvent e) {
Graphics2D g = canvas.createGraphics();
g.setColor(new Color(55, 75, 125));
g.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
int offset = (x % bi.getWidth());
g.drawImage(bi, offset, y, null);
g.drawImage(bi, offset - bi.getWidth(), y, null);
g.setPaint(gp2);
g.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
g.dispose();
animationLabel.repaint();
x++;
}
};
Timer timer = new Timer(40, animator);
timer.start();
JOptionPane.showMessageDialog(null, animationLabel);
timer.stop();
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}
Here is a version of that image with the equator added (it is 44 pixels 'south' of the center of the image).
You're calling Thread.sleep(...) and likely on the EDT or Swing event thread (full name is the Event Dispatch Thread). This thread is responsible for all Swing painting/drawing and user interactions, and so sleeping it will only serve to freeze your entire GUI. Instead you should use a Swing Timer to allow you to swap a JLabel's ImageIcon.
So, briefly:
Don't call Thread.sleep(...) on the Swing event thread (Event Dispatch Thread or EDT).
Do use a Swing Timer to do your repeating delayed actions.
Don't make and add many JLabels. Just make and add one.
Do Swap the ImageIcon that the JLabel displays by calling setIcon(...) on the label.
Better (cleaner) to write if (busy == false) { as if (!busy) {
e.g.,
ImageIcon[] icons = {...}; // filled up with your ImageIcons
if (!busy) {
int timerDelay = 2000;
new Timer(timerDelay, new ActionListener() {
private int i = 0;
public void actionPerfomed(ActionEvent e) {
myLabel.setIcon(icons(i));
i++;
if (i == icons.length) {
((Timer)e.getSource).stop();
}
};
}).start();
}

Image Capture in BufferedImage

I am new here and also quite new to Java.
I am making an app where one can select an area of image and it simply returns the selected coordinates. The problem is that, instead of displaying the image, it displays a black area instead of the image.
Also tried with BufferedImage.TYPE_INT_ARGB and now it shows a blank area.
Here is the code. Please help.
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class ScreenCaptureRectangle {
Rectangle captureRect;
ScreenCaptureRectangle(final Image im) {
final BufferedImage screenCopy = new BufferedImage(
im.getWidth(null),
im.getHeight(null),
BufferedImage.TYPE_INT_ARGB);
final BufferedImage screenCopy1 = new BufferedImage(
im.getWidth(null),
im.getHeight(null),
BufferedImage.TYPE_INT_ARGB);
final JLabel screenLabel = new JLabel(new ImageIcon(screenCopy));
JScrollPane screenScroll = new JScrollPane(screenLabel);
screenScroll.setPreferredSize(new Dimension(
(int)(im.getWidth(null)),
(int)(im.getHeight(null))));
JPanel panel = new JPanel(new BorderLayout());
panel.add(screenScroll, BorderLayout.CENTER);
final JLabel selectionLabel = new JLabel(
"Drag a rectangle in the screen shot!");
panel.add(selectionLabel, BorderLayout.SOUTH);
repaint(screenCopy1, screenCopy);
screenLabel.repaint();
screenLabel.addMouseMotionListener(new MouseMotionAdapter() {
Point start = new Point();
#Override
public void mouseMoved(MouseEvent me) {
start = me.getPoint();
repaint(screenCopy1, screenCopy);
selectionLabel.setText("Start Point: " + start);
screenLabel.repaint();
}
#Override
public void mouseDragged(MouseEvent me) {
Point end = me.getPoint();
captureRect = new Rectangle(start,
new Dimension(end.x-start.x, end.y-start.y));
repaint(screenCopy1, screenCopy);
screenLabel.repaint();
selectionLabel.setText("Rectangle: " + captureRect);
}
});
JOptionPane.showMessageDialog(null, panel);
System.out.println("Rectangle of interest: " + captureRect);
}
public void repaint(BufferedImage orig, BufferedImage copy) {
Graphics2D g = copy.createGraphics();
g.drawImage(orig,0,0, null);
if (captureRect!=null) {
g.setColor(Color.RED);
g.draw(captureRect);
g.setColor(new Color(255,255,255,150));
g.fill(captureRect);
}
g.dispose();
}
public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
new ScreenCaptureRectangle(ImageIO.read(new File("Desert.jpg")));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}
Your problem is that you never paint the original image (im, read from "Desert.jpg") into any of your screenCopy or screenCopy1 images, you only create empty BufferedImages of the same size. These "copies" will always stay blank.

Scaling an image quickly, and making sure it actually scales

I am trying to scale a screenshot taken by:
robot.createScreenCapture(SCREEN_RECT);
Im trying to get it down to an image that is 600X400 and fits into a JFrame that is 600X400
My program is using a swing worker to create an video out of each picture, or frames. The frames have a delay of 200ms per each. the image when told to rescale just shows the original image at the original dimensions. Does anyone know how to fix this, or should I just give up on the resize-ing?
#SuppressWarnings("serial")
public class temporaryShit extends JPanel
{
private static final int width = 600;
private static final int height = 400;
private JLabel displayedLabel = new JLabel();
public temporaryShit()
{
setLayout(new BorderLayout());
add(displayedLabel);
try {
MySwingWorker mySwingWorker = new MySwingWorker();
mySwingWorker.execute();
} catch (AWTException e) {
}
}
public void setLabelIcon(Icon icon) {
displayedLabel.setIcon(icon);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
private class MySwingWorker extends SwingWorker<Void, Icon>
{
private final Rectangle SCREEN_RECT = new Rectangle(0, 0, width, height);
private long delay = 200;
private Robot robot = null;
public MySwingWorker() throws AWTException
{
robot = new Robot();
}
#Override
protected Void doInBackground() throws Exception
{
Timer utilTimer = new Timer();
TimerTask task = new TimerTask()
{
#Override
public void run()
{
BufferedImage capturedImage = captureScreen();
publish(new ImageIcon(capturedImage));
}
};
utilTimer.scheduleAtFixedRate(task, delay, delay);
return null;
}
#Override
protected void process(List<Icon> chunks)
{
for (Icon icon : chunks)
{
setLabelIcon(icon);
}
}
private BufferedImage captureScreen()
{
BufferedImage img = robot.createScreenCapture(SCREEN_RECT);
return createResizedImage(img, width, height);
}
public BufferedImage createResizedImage(Image original, int width, int height)
{
BufferedImage scaledBI = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = scaledBI.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(original, 0, 0, width, height, null);
g.dispose();
return scaledBI;
}
}
private static void createAndShowGui()
{
temporaryShit mainPanel = new temporaryShit();
JFrame frame = new JFrame("SwingWorker Eg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGui();
}
});
}
}
You already have a new image with specified size - scaled, which you can use for rendering.
Here is a simple example:
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
class TestBrightness {
public static void main(String args[]) {
try {
URL imageUrl = new URL(
"http://duke.kenai.com/comfyChair/ComfyChairRadSmall.jpg");
BufferedImage ioImage = ImageIO.read(imageUrl);
JPanel panel = new JPanel();
Image scaledImg = ioImage.getScaledInstance(ioImage.getWidth() / 2,
ioImage.getHeight() / 2, Image.SCALE_SMOOTH);
panel.add(new JLabel(new ImageIcon(ioImage)));
panel.add(new JLabel(new ImageIcon(scaledImg)));
JOptionPane.showMessageDialog(null, panel, "100% vs 50%",
JOptionPane.INFORMATION_MESSAGE);
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e.getMessage(), "Failure",
JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
}
}
}
As a side note, there are many ways to scale an image and Image.getScaledInstance() may not be the best. You may be interested to take a look at The Perils of Image.getScaledInstance() for some details on Image.getScaledInstance()
EDIT: question update
Last question update removed all the details regarding getScaledInstance and invalidated this answer. getScaledInstance is a very slow method and it is also asynchronous. Try this method to get a resized image:
public static BufferedImage createResizedImage(Image original, int width,
int height) {
BufferedImage scaledBI = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = scaledBI.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(original, 0, 0, width, height, null);
g.dispose();
return scaledBI;
}
You may want to change rendering hints for better quality.
For a nicer and more complete image scaler take a look at getFasterScaledInstance() from Filthy Rich Clients book.
EDIT : last question update with posted code and SwingWorker
The implementation of SwingWorker is not correct. doInBackground() schedules java.Utils.Timer. This timer handles all updates, while the actual SwingWorker worker thread ends. All updates from the timer are fired not on Event Dispatch Thread. It may not be safe to allocate ImageIcon not on EDT. And for sure it is not safe to update UI, ie calling setLabelIcon() not on EDT. See Concurrency in Swing tutorial for details.
You can add while loop and Thread.sleep in doInBackground() and remove the timer. Alternatively, Swing timer may be more suitable for this case. Here is an example:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
public class DemoRobotPanel extends JPanel{
private static final long serialVersionUID = 1L;
private Image image;
private Robot robot;
private Rectangle CAPTURE_RECT;
private int TIMER_DELAY = 1000;
private int desiredWidth = 600;
private int desiredHeight = 400;
public DemoRobotPanel() {
CAPTURE_RECT = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
try {
robot = new Robot();
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
try {
BufferedImage img = robot.createScreenCapture(CAPTURE_RECT);
setImage(img);
} catch (HeadlessException e) {
e.printStackTrace();
}
}
};
Timer timer = new Timer(TIMER_DELAY, taskPerformer);
timer.start();
} catch (AWTException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(desiredWidth, desiredHeight);
}
public void setImage(Image image) {
this.image = image;
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null)
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
}
private static void createAndShowGui() {
final DemoRobotPanel panel = new DemoRobotPanel();
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Try this:
public BufferedImage resize(BufferedImage bufferedImage, int resizeWidth, int resizeHeight) {
// Create new (blank) image of required (scaled) size
BufferedImage scaledImage = new BufferedImage(resizeWidth, resizeHeight, BufferedImage.TYPE_INT_ARGB);
// Paint scaled version of image to new image
Graphics2D graphics2D = scaledImage.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.drawImage(bufferedImage, 0, 0, resizeWidth, resizeHeight, null);
graphics2D.dispose();
return scaledImage;
}
You may want to try different RenderingHints.

JButton setIcon Updation error

Currently i m making a java program using netbeans based on changing image in a button....
Actually my requirement is to change the Image icon of a button as i click another button (Say A).....
i came out with the following program........
// Following function is included inside the button's (Here A) ActionListener........
public void change_image()
{
if(sex==0)
{
ic=new ImageIcon("E:\\java_images\\female_profile.jpg");
sex=1;
}
else if(sex==1)
{
ic = new ImageIcon("E:\\java_images\\male_profile.png");
sex=0;
}
// To resize the image into the size of the button...
labelicon.setImage(ic.getImage().getScaledInstance(image_btn.getWidth(),image_btn.getHeight(), Image.SCALE_DEFAULT));
img_btn.setIcon(labelicon);
}
The Variables i've included are
private int sex; // 0 - female, 1 - male
private ImageIcon ic,labelicon; // variables meant for storing ImageIcons.....
private JButton img_btn; // the button at which the image is to be displayed....
Now the Weird Behaviour i observed is.......
The image gets displayed on the button click, only when i click the minimize button.
i.e when the i click the button A, the code specified in the ActionListener is getting executed. But the effect of the image change appears only when i minimize the window and again make it appear on the screen.... Can anyone tell why this is occuring and how can i remove the problem ??
All i want is to change the image the moment i click the A Button.....
Well..i haven't included for the code for creating button since they are easily done by netbeans swing GUI builder......
load Icon / ImageIcon as local variable once time, there no reason to re_loading image from ActionListener
in the API is description that Image#ScaledInstance is pretty asynchronous
otherwise you have to call
.
labelicon.getImage().flush();
img_btn.setIcon(labelicon);
EDIT
#akp wrote but..how would you resize the icon image..??
there are two or three another ways how to put Icon /ImageIcon and will be resiziable with its parent, JLabelcould be easiest of ways
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.swing.*;
public class JButtonAndIcon {
private static JLabel label = new JLabel();
private static Random random = new Random();
private static ImageIcon image1; // returns null don't worry about
private static ImageIcon image2; // returns null don't worry about
private static Timer backTtimer;
private static int HEIGHT = 300, WEIGHT = 200;
public static void main(String[] args) throws IOException {
label.setPreferredSize(new Dimension(HEIGHT, WEIGHT));
final JButton button = new JButton("Push");
button.setBorderPainted(false);
button.setBorder(null);
button.setFocusable(false);
button.setMargin(new Insets(0, 0, 0, 0));
button.setContentAreaFilled(false);
button.setLayout(new BorderLayout());
button.add(label);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (button.getIcon() == image1) {
label.setIcon(image2);
} else {
label.setIcon(image1);
}
}
});
JFrame frame = new JFrame("Test");
frame.add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
startBackground();
frame.setVisible(true);
}
private static void startBackground() {
backTtimer = new javax.swing.Timer(750, updateBackground());
backTtimer.start();
backTtimer.setRepeats(true);
}
private static Action updateBackground() {
return new AbstractAction("Background action") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
label.setIcon(new ImageIcon(getImage()));
}
};
}
public static BufferedImage getImage() {
int w = label.getWidth();
int h = label.getHeight();
GradientPaint gp = new GradientPaint(0f, 0f, new Color(
127 + random.nextInt(128),
127 + random.nextInt(128),
127 + random.nextInt(128)),
w, w,
new Color(random.nextInt(128), random.nextInt(128), random.nextInt(128)));
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bi.createGraphics();
g2d.setPaint(gp);
g2d.fillRect(0, 0, w, h);
g2d.setColor(Color.BLACK);
return bi;
}
}
The problem here is that you are updating the internals of an Icon. The setIcon method will think that it's the same icon that the button already has. I would recommend you to do two different Icon objects that to use to update the icon with. That will fix the problems.
Example (with two different icons):
public static void main(String[] args) throws IOException {
final ImageIcon redIcon = createImageIcon(10, 10, Color.RED);
final ImageIcon blueIcon = createImageIcon(10, 10, Color.BLUE);
final JButton button = new JButton("Push", blueIcon);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (button.getIcon() == redIcon)
button.setIcon(blueIcon);
else
button.setIcon(redIcon);
}
});
JFrame frame = new JFrame("Test");
frame.add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private static ImageIcon createImageIcon(int w, int h, Color color) {
Image image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
g.setColor(color);
g.fillRect(0, 0, w, h);
g.dispose();
return new ImageIcon(image);
}
Background:
Looking at the source of AbstractButton.setIcon, you can see that it won't know about the update if the reference "isn't updated":
.....
if (defaultIcon != oldValue) {
if (defaultIcon == null || oldValue == null ||
defaultIcon.getIconWidth() != oldValue.getIconWidth() ||
defaultIcon.getIconHeight() != oldValue.getIconHeight()) {
revalidate();
}
repaint();
}
Note to #HarryJoy, you actually had a point even though you didn't know why... :) Sorry! +1 again!
//Call img_btn.revalidate() and img_btn.repaint()
Correction, setIcon should already do this. I use the hacky way of img_btn.setText("<HTML><BODY><IMG SRC=\"/path/to/img.jpg\"/></BODY</HTML>"); personally.

Categories