Я сделал этот базовый пример c, используя JPanel
и javax.swing.Timer
, и я ожидаю, что анимация будет относительно плавной.
Если я удерживаю курсор мыши над окном, анимация плавная. Если я вообще не взаимодействую с окном, анимация начинает прыгать.
import javax.swing.*;
import java.awt.*;
public class SmoothSwing{
double x = 0;
double y = 0;
double theta = 0;
public void step(){
x = 175 + 175*Math.sin( theta );
y = 175 + 175*Math.cos( theta );
theta += 0.02;
if(theta > 6.28) theta = 0;
}
public void buildGui(){
JFrame frame = new JFrame("smooth");
JPanel panel = new JPanel(){
Dimension dim = new Dimension(400, 400);
@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawOval((int)x, (int)y, 50, 50);
}
@Override
public Dimension getMinimumSize(){
return dim;
}
@Override
public Dimension getPreferredSize(){
return dim;
}
};
frame.add(panel, BorderLayout.CENTER);
frame.setVisible(true);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Timer timer = new Timer(30, evt->{
step();
panel.repaint();
});
timer.start();
}
public static void main(String[] args){
EventQueue.invokeLater( new SmoothSwing()::buildGui );
}
}
Мне показалось, что перекрашивание накапливается и перекрашивается в комки. Поэтому я закомментировал строку super.paintComponent(g);
, из-за которой панель не будет очищена.
Когда я это сделаю, я вижу, что paintComponent запускается, потому что все круги нарисованы, но дисплей все еще обновляется только после того, как нарисованы несколько кругов.
У меня есть эта проблема на jdk-14 + 36, jdk-11.0.6 и 1.8 .0_181 используя Linux. Ubuntu 18.04.
Вот графики, сравнивающие разницу. У меня были проблемы с управлением скоростью GIF-файлов, но это показывает, что происходит.
Слева направо, если я перемещаю мышь по окну, я получаю поведение слева, после остановки оно становится немного нервным (посередине), тогда оно становится более нервным (справа).
Единственное, что я могу сделать, чтобы избежать этой проблемы, это разделить мой таймер на две задачи.
Timer t1 = new Timer(30, evt->step());
Timer t2 = new Timer(3, evt->panel.repaint());
t1.start();
t2.start();