我有一个将图像缩放到屏幕大小的程序。我目前有一个组件侦听器,它正在侦听componentResized事件,但这不是我想要的。我希望这种方法只能被称为用户松开鼠标的手指,而不是因为他们正在调整大小。这样,我的图像将不会一直调整为用户的规格。
谢谢!
解决方案是提供一个Swing Timer
,每次调用componentResized
时都会对其进行重置。这会在上一次调整大小事件与您执行调整大小操作的时间之间产生一个小的延迟。
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();
}
基本上,将其设置为在尝试调整图像大小之前,在调整大小事件之间需要250毫秒。您可以根据自己的需要试用价值。
已更新为可运行的示例
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 Perils of Image.getScaledInstance();有关替代方法,请参见Scale the ImageIcon automatically to label size。
如果将Toolkit.getDefaultToolkit().setDynamicLayout(false);
放置在main的内部,则当您增加/减小其大小时,它将使框架无法动态更新。 ui只会在您停止调整大小后才更新。
import MainMenu.GameManager;
import java.awt.*;
import java.io.IOException;
public class Main {
Main(){
}
public static void main(String[] args) throws IOException {
GameManager manager = new GameManager();
Toolkit.getDefaultToolkit().setDynamicLayout(false);
}
}