I'm writing a swing program that has to repaint at intervals. For some reason, javax.swing.Timer
seems to only be repainting once every 800-900ms even when I specify lower delays. (e.g. 100ms) I thought the delay might be due to the repaint()
method taking 800ms to run, but I timed it and it only takes .3ms. I tried using Thread.sleep()
and it repaints at the desired intervals. Can anyone help explain why this might be?
What I'm trying to do seems like the intended purpose of javax.swing.Timer
and so I'm confused as to why it would slow down the code so much.
Main driver class:
import java.awt.Dimension;
import javax.swing.JFrame;
public class GUIDriver{
public AnimationPanel animationPanel;
public static void main(String[] args){
GUIDriver gui = new GUIDriver();
gui.createAndShowGUI();
}
public void createAndShowGUI(){
animationPanel = AnimationPanel(50);
JFrame frame = new JFrame("Animations");
frame.setContentPane(animationPanel);
frame.setPreferredSize(new Dimension(1015, 840));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.validate();
frame.doLayout();
frame.setVisible(true);
animationPanel.draw(); //only here when using Thread.sleep() method
}
}
Custom JPanel
extension:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Point2D;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
import java.text.SimpleDateFormat;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
import javax.swing.Timer;
/**
* This extension of the JPanel overrides the paintComponent method to provide a framework for
* creating 2-D animations.
*/
@SuppressWarnings("serial")
public class AnimationPanel extends JPanel implements ActionListener{
public ArrayList<LeakInstance> data;
public Timer timer;
public SimpleDateFormat dateOutput = new SimpleDateFormat("MM/dd/yyyy");
BufferedImage background;
public Color lineColor = Color.black;
public Color under = Color.blue;
public Color over = Color.red;
public Font defaultFont = new Font("default", Font.BOLD, 14);
public float cutoff = 50;
public int timeStep = 0;
public long startTime = 0;
public Graphics2D screen;
public AnimationPanel(float cutoff) {
super();
setLayout(null);
read("Data.txt");
this.cutoff = cutoff;
timer = new Timer(100, this); //commented out when using Thread.sleep()
try {
background = ImageIO.read(new File("img.png"));
} catch (IOException e) {
e.printStackTrace();
}
repaint();
timer.start(); //commented out when using Thread.sleep()
}
/**
* This method overrides JPanel's paintComponent method in order to customize the rendering of 2-D graphics
* and thus make animation possible. It is not called directly; it is called by repaint() which fully refreshes
* the screen.
*/
@Override
public void paintComponent(Graphics g) {
ArrayList<String> drawn = new ArrayList<String>();
screen = (Graphics2D)g;
RenderingHints renderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
renderHints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
screen.setRenderingHints(renderHints);
screen.drawImage(background.getScaledInstance(1000, 800, Image.SCALE_SMOOTH), 0, 0, this);
g.setFont(defaultFont);
screen.setColor(Color.orange);
screen.fillRect(485, 735, 100, 20); //cover old date
screen.setColor(lineColor);
screen.drawString(dateOutput.format(data.get(timeStep).getDate()), 500, 750);
screen.drawString(Integer.toString(timeStep), 300, 750);
System.out.println((System.nanoTime() - startTime)/1e9f);
startTime = System.nanoTime();
float x, y;
float z;
int xoffset, yoffset;
for(int i = 0; drawn.size() < 24 && (timeStep-i) > -1; i++){
if(!drawn.contains(data.get(timeStep-i).getName())){
xoffset = 0;
yoffset = 15;
String name = data.get(timeStep-i).getName();
drawn.add(name);
x = data.get(timeStep-i).getLocation().x;
y = data.get(timeStep-i).getLocation().y;
z = data.get(timeStep-i).getZ();
if(z > cutoff)
screen.setColor(over);
else
screen.setColor(under);
switch(name){
//various cases to change x or y offset
}
screen.drawString(Float.toString(z), x+xoffset, y+yoffset);
screen.setColor(lineColor);
screen.drawLine((int)x-2, (int)y, (int)x+2,(int) y);
screen.drawLine((int)x, (int)y-2, (int)x, (int)y+2);
}
}
}
public void draw(){
try{
for(; timeStep < data.size()-1; timeStep++){
Thread.sleep(100);
repaint();
}
}catch(Exception e){
e.printStackTrace();
}
}
public void read(String filename){
File file = new File(filename);
data = new ArrayList<MyType>(100);
try(Scanner scan = new Scanner(file)){
while(scan.hasNextLine())
data.add(new MyType(scan.next(), scan.next(), scan.nextFloat(),
new Point2D.Float(scan.nextFloat(), scan.nextFloat())));
}catch (Exception e){
e.printStackTrace();
}
Collections.sort(data);
}
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(timer)){
if(timeStep < data.size()-1){
timeStep++;
repaint();
}
else
timer.stop();
}
}
}