I have a program that scales an image to the size of the screen. I currently have a component listener listening for a componentResized event, but this is not what I want. I would like the method to only be called one the user lift's there finger off their mouse, not as they are doing the resizing. This way, my image will not constantly be resizing to the user's specifications.
Thanks!
A solution is to supply a Swing Timer
which is reset each time componentResized
is called. This injects a small delay between the last resize event and the time you should perform the resize action.
import javax.swing.Timer;
//...
// Declare an instance variable...
private Timer resizeTimer;
//...
// Probably in you classes constructor
resizeTimer = new Timer(250, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
// Actually perform the resizing of the image...
resizeBackgroundImage();
}
});
// Don't want a repeating event...
resizeTimer.setRepeats(false);
//...
public void componentResized(ComponentEvent evt) {
resizeTimre.restart();
}
This basically, sets it up so that it will require 250 milliseconds between resize events before an attempt is made to resize the image. You can play around with the value to suit your own needs.
Updated with runnable example
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class RescaleTest {
public static void main(String[] args) {
new RescaleTest();
}
public RescaleTest() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage master;
private Image scaled;
private Timer resizeTimer;
public TestPane() {
try {
master = ImageIO.read(new File("/path/to/your/image"));
scaled = master;
} catch (IOException exp) {
exp.printStackTrace();
}
resizeTimer = new Timer(250, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
resizeBackground();
}
});
resizeTimer.setRepeats(false);
addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
resizeTimer.restart();
}
});
}
protected void resizeBackground() {
// This is not my preferred scaling process, I prefer to use
// a divide and conqure approach and do so in the background
// where possible, but this is beyond the scope of the question...
if (getWidth() < getHeight()) {
scaled = master.getScaledInstance(getWidth(), -1, Image.SCALE_SMOOTH);
} else {
scaled = master.getScaledInstance(-1, getHeight(), Image.SCALE_SMOOTH);
}
repaint();
}
@Override
public Dimension getPreferredSize() {
return master != null ? new Dimension(master.getWidth(), master.getHeight()) : new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (scaled != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - scaled.getWidth(this)) / 2;
int y = (getHeight() - scaled.getHeight(this)) / 2;
g2d.drawImage(scaled, x, y, this);
g2d.dispose();
}
}
}
}
nb: The scaling used in this example is not my preferred method and was done for demonstration purposes only. See The Perils of Image.getScaledInstance() for details and Scale the ImageIcon automatically to label size for an alterantive approach...