JPanel 不重绘
JPanel does not repaint
我正在使用多个 BufferedImages。我正在使用的 JPanel 的 paint 函数在 JPanel 上绘制 currentImg:
@Override
public void paint(Graphics g) {
g.drawImage(currentImg, 0, 0, null);
}
使用currentImg方便切换图片,一开始就等于normalImg。
redImg 是一个 BufferedImage,看起来与 normalImg 不同。
现在我想画 redImg 半秒,然后再画 normalImg。
currentImg = redImg;
repaint();
Thread.sleep(1000);
currentImg = normalImg;
repaint();
但是这段代码什么都不做,JPanel 没有被重新绘制。这段代码虽然有效:
currentImg = redImg;
repaint();
JOptionPane.showMessageDialog(this,"test");
Thread.sleep(1000);
JOptionPane.showMessageDialog(this,"test");
currentImg = normalImg;
repaint();
但我不想显示消息对话框只是为了正确地重新绘制它。
感谢您的帮助:)
您通过在绘画方法和 Swing 事件线程中调用 Thread.sleep(...)
来冻结整个应用程序。不要这样做。而是使用 Swing 计时器并从计时器中交换 JLabel 的图标。
例如:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.*;
public class SwapImages extends JPanel {
private static final int TIMER_DELAY = 200;
private static final String SPRITE_PATH = "http://th02.deviantart.net/"
+ "fs70/PRE/i/2011/169/0/8/blue_player_sprite_sheet_by_resetado-d3j7zba.png";
public static final int SPRITE_ROWS = 6;
public static final int SPRITE_COLS = 6;
public static final int SPRITE_CELLS = 35;
private JLabel label = new JLabel();
private List<ImageIcon> iconList = new ArrayList<ImageIcon>();
private int iconIndex = 0;
public SwapImages() throws IOException {
URL imgUrl = new URL(SPRITE_PATH);
BufferedImage mainImage = ImageIO.read(imgUrl);
for (int i = 0; i < SPRITE_CELLS; i++) {
int row = i / SPRITE_COLS;
int col = i % SPRITE_COLS;
int x = (int) (((double) mainImage.getWidth() * col) / SPRITE_COLS);
int y = (int) ((double) (mainImage.getHeight() * row) / SPRITE_ROWS);
int w = (int) ((double) mainImage.getWidth() / SPRITE_COLS);
int h = (int) ((double) mainImage.getHeight() / SPRITE_ROWS);
BufferedImage img = mainImage.getSubimage(x, y, w, h);
ImageIcon icon = new ImageIcon(img);
iconList.add(icon);
}
add(label);
label.setIcon(iconList.get(iconIndex));
new Timer(TIMER_DELAY, new TimerListener()).start();
}
private class TimerListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent arg0) {
iconIndex++;
iconIndex %= iconList.size();
label.setIcon(iconList.get(iconIndex));
}
}
private static void createAndShowGui() {
SwapImages mainPanel = null;
try {
mainPanel = new SwapImages();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
JFrame frame = new JFrame("SwapImages");
frame.setDefaultCloseOperation(JFrame.DISPOSE_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();
}
});
}
}
- 避免覆盖
paint
,尤其是顶级容器,使用基于 JComponent
的组件并覆盖其 paintComponent
方法。查看 Painting in AWT and Swing and Performing Custom Painting 以了解有关 Swing 中喘息的更多详细信息
- 始终调用
super.paintXxx
您覆盖的任何绘制方法
- 不要在事件调度线程的上下文中使用
Thread.sleep
,这将阻止它处理来自 EventQueue
的新事件,包括重绘事件。
- 不要从事件调度线程的上下文之外修改 UI。
查看 Concurrency in Swing for more details and How to use Swing Timers 以获得可能的解决方案
还有一个
我正在使用多个 BufferedImages。我正在使用的 JPanel 的 paint 函数在 JPanel 上绘制 currentImg:
@Override
public void paint(Graphics g) {
g.drawImage(currentImg, 0, 0, null);
}
使用currentImg方便切换图片,一开始就等于normalImg。 redImg 是一个 BufferedImage,看起来与 normalImg 不同。 现在我想画 redImg 半秒,然后再画 normalImg。
currentImg = redImg;
repaint();
Thread.sleep(1000);
currentImg = normalImg;
repaint();
但是这段代码什么都不做,JPanel 没有被重新绘制。这段代码虽然有效:
currentImg = redImg;
repaint();
JOptionPane.showMessageDialog(this,"test");
Thread.sleep(1000);
JOptionPane.showMessageDialog(this,"test");
currentImg = normalImg;
repaint();
但我不想显示消息对话框只是为了正确地重新绘制它。 感谢您的帮助:)
您通过在绘画方法和 Swing 事件线程中调用 Thread.sleep(...)
来冻结整个应用程序。不要这样做。而是使用 Swing 计时器并从计时器中交换 JLabel 的图标。
例如:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.*;
public class SwapImages extends JPanel {
private static final int TIMER_DELAY = 200;
private static final String SPRITE_PATH = "http://th02.deviantart.net/"
+ "fs70/PRE/i/2011/169/0/8/blue_player_sprite_sheet_by_resetado-d3j7zba.png";
public static final int SPRITE_ROWS = 6;
public static final int SPRITE_COLS = 6;
public static final int SPRITE_CELLS = 35;
private JLabel label = new JLabel();
private List<ImageIcon> iconList = new ArrayList<ImageIcon>();
private int iconIndex = 0;
public SwapImages() throws IOException {
URL imgUrl = new URL(SPRITE_PATH);
BufferedImage mainImage = ImageIO.read(imgUrl);
for (int i = 0; i < SPRITE_CELLS; i++) {
int row = i / SPRITE_COLS;
int col = i % SPRITE_COLS;
int x = (int) (((double) mainImage.getWidth() * col) / SPRITE_COLS);
int y = (int) ((double) (mainImage.getHeight() * row) / SPRITE_ROWS);
int w = (int) ((double) mainImage.getWidth() / SPRITE_COLS);
int h = (int) ((double) mainImage.getHeight() / SPRITE_ROWS);
BufferedImage img = mainImage.getSubimage(x, y, w, h);
ImageIcon icon = new ImageIcon(img);
iconList.add(icon);
}
add(label);
label.setIcon(iconList.get(iconIndex));
new Timer(TIMER_DELAY, new TimerListener()).start();
}
private class TimerListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent arg0) {
iconIndex++;
iconIndex %= iconList.size();
label.setIcon(iconList.get(iconIndex));
}
}
private static void createAndShowGui() {
SwapImages mainPanel = null;
try {
mainPanel = new SwapImages();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
JFrame frame = new JFrame("SwapImages");
frame.setDefaultCloseOperation(JFrame.DISPOSE_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();
}
});
}
}
- 避免覆盖
paint
,尤其是顶级容器,使用基于JComponent
的组件并覆盖其paintComponent
方法。查看 Painting in AWT and Swing and Performing Custom Painting 以了解有关 Swing 中喘息的更多详细信息 - 始终调用
super.paintXxx
您覆盖的任何绘制方法 - 不要在事件调度线程的上下文中使用
Thread.sleep
,这将阻止它处理来自EventQueue
的新事件,包括重绘事件。 - 不要从事件调度线程的上下文之外修改 UI。
查看 Concurrency in Swing for more details and How to use Swing Timers 以获得可能的解决方案
还有一个