2016-08-24 7 views
0

私は1日のコースでハイウェイの密度を表示するために時間の経過を作成しました。データはdouble[][]アレイdataに保持され、data.lengthは2880(各インデックスは30秒間隔を表します)およびdata[0].lengthは約450(ハイウェイセクションの長さ全体の3次補間を表します)に保持されます。Chromeウェブページの要素上にマウスを移動すると、タイマーが速くなります

次のように時間の経過のための私のコードは次のとおりです。スムーズ

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); 
    } 
} 

アニメーション機能を、それは一般的に、私は定数までチョーク、私はそれを設定し、5秒、より長く多くを取りますパネル内で数百の線の着色および生成を引き起こす。

私が正しかったことを確かめるためには、Googleの「ストップウォッチ」で時刻を表示するときに表示されるGoogle Chromeウィジェットを使用しました。これを行うと、私はストップウォッチを実行したときに、アニメーションが大幅にスピードアップし、マウスを特定の要素(ハイパーリンク、上部のタブ、マウスのホバーリングに視覚的に反応する他のもの) 。これは、マウスを動かすか、ストップウォッチを実行しているときにのみ発生します。マウスを維持しても速度が上がらず、Chrome上でマウスを動かしている間(つまり、他のアプリケーションであれ)正常に動作するように見えます。誰もこの奇妙な行動を説明できますか?

編集:タブの再読み込み中にも発生しますが、再読み込みが終了した後ではありません。

EDIT 2:タイマーが高速化していることがわかりました。これは、Chromeの要素の上にマウスを移動するときに大幅にスピードアップし、時間の経過クラスとまったく同じ動作を持ってい

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) { 
     } 
    } 
} 

:私はミリ秒ごとに増加し、インデックスを印刷し、タイマーで小さなクラスを作成しました。理由は、この場合、printlnが遅い方法であり、タイマーの更新よりも遅く実行するという理由が考えられます。繰り返しますが、Chromeがバックアップされたタイマーの速度を上げる理由を説明できますか?

答えて

1

塗装方法は塗装のみです。

ペイントメソッドでクラスのプロパティを変更しないでください。

コンポーネントを再描画する必要があるとSwingが判断したときは制御できません。そのため、コンポーネントが再描画され、その結果、あなたが考えるよりも頻繁にプロパティを変更するシステムコールが発生する可能性があります。

たとえば、「インデックス」変数またはプログレスバーの値を更新しないでください。代わりに、Timerはこれらのプロパティを変更するメソッドを呼び出す必要があり、そのメソッドはパネル上で再描画を呼び出す必要があります。私は

はたぶん、あなたはそれが再描画される原因となるパネルのツールチップを持つマウスを動かすと

にのみ発生します。

これはテストするのが簡単です。paintComponent()メソッドにSystem.out.println(...)ステートメントを追加して、タイマーの5秒よりも頻繁に表示されるかどうかを確認するだけです。

+0

私は、 'paint'が呼び出される時期を予測できないことを知っています。私がここでやっていることを避けようとしています(paintメソッドのプロパティを更新しています)。これは実際に私がこのクラスで元々持っていたものですが、描画速度が遅いため、 'timer'は準備が整う前にインデックスを更新してしまい、レンダリングやインデックス作成のバグやエラーが発生します。 – 17slim

+0

ツールチップを使う限り、私は何も使っていません。 – 17slim

+0

とにかく、インデックスとプログレスバーを更新し、それをタイマーに入れる方法を提案して作成しました(私が使っていた以前のバグは私が使っている新しいインデックス計算には表示されません) 。私はコードを更新しますが、その動作はそのままです。 – 17slim

関連する問題