我创造了一段时间,以显示一天中高速公路上的密度。数据保存在double[][]
数组data
中,其中data.length
为2880(每个索引代表30秒间隔),data[0].length
约为450(表示三次插值)穿过高速公路路段的长度。)
我的时间间隔代码如下:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.Timer;
public class TimeLapse extends JPanel {
static double[][] data;
int index = 0;
double max;
double lineWidth;
Timer timer;
final JProgressBar progressBar = new JProgressBar(0, 2879);
BufferedImage[] images;
Color colors[][];
public static void main(String[] args) {
data=getData(); //arbitrary method to get interpolated data
new TimeLapse(data, 90);
}
public TimeLapse(double[][] data1, double max) {
data = data1;
this.max = max;
JFrame frame = new JFrame("Timelapse");
frame.setPreferredSize(new Dimension(800, 600));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.anchor = GridBagConstraints.NORTH;
c.gridwidth = 1;
c.gridx = 0;
c.gridheight = 1;
c.weightx = 1;
c.weighty = .01;
c.gridy = 0;
frame.add(progressBar, c);
c.anchor = GridBagConstraints.SOUTH;
c.gridy = 1;
c.gridheight = 9;
c.weighty = 1;
frame.add(this, c);
frame.pack();
getColorArray();
frame.setVisible(true);
int dataLength;
dataLength = data.length;
// Make the animation 5 seconds long
int delay = (int) (5000d / dataLength);
timer = new Timer(delay, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateIndex();
repaint();
Toolkit.getDefaultToolkit().sync();
}
});
timer.start();
}
private void getColorArray() {
double cutOff = max / 2;
colors = new Color[data.length][data[0].length];
for (int index = 0; index < data.length; index++) {
for (double x = 0; x < data[0].length; x++) {
colors[index][(int) x] =
getColor(data[index][(int) x], cutOff);
}
}
}
private void updateIndex() {
index = index < data.length - 1 ? index + 1 : 0;
progressBar.setValue(2879 * index / data.length);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
int panelHeight = getHeight();
lineWidth = ((double) getWidth()) / ((double) (data[0].length));
// guaranteed counter, as doing it in timer's ActionListener could overlap with rendering
for (double x = 0; x < data[0].length; x++) {
g2.setColor(colors[index][(int) x]);
double rectHeight = panelHeight * data[index][(int) x] / max;
g2.fillRect((int) (x * lineWidth),
(int) (panelHeight - rectHeight),
(int) (lineWidth + 1), (int) rectHeight + 1);
}
g2.dispose();
}
private Color getColor(double value, double cutOff) {
int hueR, hueG, hueB = 0;
if (value < cutOff) {
hueG = 255;
hueR = (int) (255 * value / (cutOff));
} else if (max != cutOff) {
hueR = 255;
hueG = (int) (255 - (255 * (value - cutOff) / (max - cutOff)));
} else {
hueR = 255;
hueG = 0;
}
hueR = (hueR < 0) ? 0 : ((hueR > 255) ? 255 : hueR);
hueG = (hueG < 0) ? 0 : ((hueG > 255) ? 255 : hueG);
hueB = (hueB < 0) ? 0 : ((hueB > 255) ? 255 : hueB);
return new Color(hueR, hueG, hueB);
}
}
动画功能很流畅,但它通常需要的时间比我设置的五秒钟要长很多,我可以在面板中对数百行进行恒定着色和生成。
为了验证我是否正确并且它确实比它应该慢得多,我使用了Google“小秒表”计时时出现的Google Chrome小部件。这样做,我发现当我运行秒表时,动画加速,以及每当我将鼠标移动到某些元素上时(超链接,顶部的标签,以及看似任何其他可以对鼠标悬停的视觉响应) 。这只发生在我移动鼠标或运行秒表时;保持鼠标仍然不会加快速度,并且它似乎只有在将鼠标悬停在Chrome上时才有这种行为(即任何其他应用程序都可以)。任何人都可以解释这种奇怪的行为吗?
编辑:重新加载标签时也会发生这种情况,但重新加载后却没有。
编辑2:我现在肯定知道计时器正在加速。我创建了一个带有计时器的小类,该计时器每毫秒打印一个增加的索引:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class TimerTest {
static int index = 0;
public static void main(String[] args) {
Timer t = new Timer(1, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(index++);
}
});
t.start();
while (true) {
}
}
}
这与时间推移类完全相同,当将鼠标移动到Chrome的元素上时,速度会大大加快。我相信原因是,在这种情况下,println
是一种慢速方法,执行速度比定时器更新慢。同样,有人可以解释为什么Chrome专门加速备份计时器吗?
答案 0 :(得分:1)
绘画方法仅适用于绘画。
您不应该在绘画方法中更改类的属性。
当Swing确定需要重新绘制组件时,您无法控制。因此可能会有一些系统调用导致组件重新绘制,因此比您想象的更频繁地更改属性。
例如,您不应该更新“索引”变量或进度条值。相反,你的Timer应该调用一个方法来改变这些属性,然后该方法应该调用面板上的重绘。
仅当我移动鼠标
时才会发生这种情况
也许你在面板上有工具提示会导致它被重新绘制。
这很容易测试,只需将一个System.out.println(...)语句添加到paintComponent()方法,看它是否比计时器的5秒更频繁地显示。