
本文旨在帮助开发者理解为什么`repaint()`方法可能无法按预期调用`paintComponent()`方法,并提供使用Swing Timer的解决方案,确保UI的正确更新和渲染。我们将深入探讨Swing的线程安全性和被动渲染机制,并通过代码示例展示如何避免常见错误,实现流畅的动画效果。
在Swing应用开发中,repaint()和paintComponent()方法是实现自定义绘制和动画效果的关键。然而,初学者经常遇到repaint()调用后paintComponent()没有被执行的问题。这通常与Swing的线程模型和渲染机制有关。
Swing是单线程的,这意味着所有UI更新都应该在事件分发线程(EDT)上执行。长时间运行或阻塞的操作在EDT上会导致UI冻结。因此,避免在EDT上执行耗时操作至关重要。
Swing不是线程安全的,这意味着从EDT之外更新UI或UI所依赖的状态会导致不可预测的结果。
Swing使用被动渲染引擎。这意味着你不能直接控制绘画过程。相反,你需要通过调用repaint()来请求重绘,Swing系统会在适当的时候调用paintComponent()方法。
解决repaint()不调用paintComponent()问题的常用方法是使用javax.swing.Timer。Timer类允许你以指定的时间间隔在EDT上执行代码。这可以确保UI更新是线程安全的,并且不会阻塞EDT。
以下是一个使用Swing Timer的示例:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new GamePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class GamePane extends JPanel {
final int ORIGINAL_TILE_SIZE = 16;
final int SCALE = 3;
final int TILE_SIZE = ORIGINAL_TILE_SIZE * SCALE;
final int MAX_SCREEN_COLUMNS = 16;
final int MAX_SCREEN_ROWS = 12;
final int SCREEN_WIDTH = TILE_SIZE * MAX_SCREEN_COLUMNS;
final int SCREEN_HEIGHT = TILE_SIZE * MAX_SCREEN_ROWS;
private Timer timer;
@Override
public Dimension getPreferredSize() {
return new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT);
}
@Override
public void addNotify() {
super.addNotify();
if (timer != null) {
timer.stop();
}
timer = new Timer(5, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
update();
}
});
timer.start();
}
@Override
public void removeNotify() {
super.removeNotify();
if (timer != null) {
timer.stop();
}
}
public void update() {
System.out.println("Updatey update");
repaint();
}
public void paintComponent(final Graphics g) {
super.paintComponent(g);
System.out.println("Painty paint paint");
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(Color.white);
g2.fillRect(100, 100, TILE_SIZE, TILE_SIZE);
g2.dispose();
}
}
}在这个例子中,Timer以5毫秒的间隔触发ActionListener,其中调用了update()方法。update()方法然后调用repaint(),这反过来触发paintComponent()方法。
代码解释:
理解Swing的线程模型和渲染机制是编写健壮的Swing应用程序的关键。通过使用Swing Timer和遵循线程安全的最佳实践,你可以避免repaint()不调用paintComponent()的问题,并创建流畅的动画效果。记住,始终在EDT上执行UI更新,并避免阻塞EDT。
以上就是解决repaint()方法不调用paintComponent()的问题的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号