【发布时间】:2014-06-17 07:57:31
【问题描述】:
我正在编写一个必须每隔一段时间重新绘制的摇摆程序。出于某种原因,javax.swing.Timer 似乎每 800-900 毫秒才重新绘制一次,即使我指定了较低的延迟。 (例如 100 毫秒)我认为延迟可能是由于 repaint() 方法需要 800 毫秒才能运行,但我对其进行了计时,它只需要 0.3 毫秒。我尝试使用 Thread.sleep() 并以所需的时间间隔重新绘制。谁能帮忙解释一下为什么会这样?
我正在尝试做的似乎是javax.swing.Timer 的预期目的,所以我很困惑为什么它会减慢代码的速度。
主驱动类:
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
}
}
自定义JPanel 扩展:
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();
}
}
}
【问题讨论】:
-
能否发布完整的可运行代码?
-
javax.swing.timer函数旨在在计时器从启动时达到特定时间时执行特定操作,而 sleep 函数只是将程序暂停一定时间,因此它们不会t 完全设计为能够相互替换。 -
您是否尝试过使用
ScheduledExecutorService.scheduleAtFixedRate? docs.oracle.com/javase/7/docs/api/java/util/concurrent/… -
尽量避免每次都使用“新字体”...也许它会在图形资源中进行一些扫描。
-
根据您断开连接的代码 sn-ps,您的 Thread.sleep 示例根本不应该工作,因为它会阻塞 EDT。我无法制作绘图循环的头部或尾部。考虑提供一个可运行的示例来演示您的问题