2016-09-13 8 views
0

私は友人のためにrubixキューブタイマーを作ろうとしています。タイマーを開始するには、スペースバーを押したままにしておきます。私は問題を抱えていますが、私がスペースバーを押している間は、タイマーはいつでも始まります。私は0にリセットすることができますが、私がしようとするたびに、すべてが不具合になります。それを修正する方法やもっと効率的なやり方を教えてもらえますか?ありがとう!Javaタイマープログラム - rubixキューブ

package dev.suns.rubix_timer; 

import java.awt.Color; 
import java.awt.Font; 
import java.awt.Toolkit; 
import java.awt.event.KeyAdapter; 
import java.awt.event.KeyEvent; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.util.Calendar; 
import java.util.GregorianCalendar; 
import java.util.Timer; 

import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.SwingConstants; 

public class RubixTimerMain extends JFrame { 

private JPanel contentPane; 
private JLabel labelTimer; 
private Timer timer; 

public RubixTimerMain() { 
    createWindow(); 
} 

public static void main(String[] args) { 
    new RubixTimerMain(); 
} 

private void createWindow() { 

    // setUndecorated(true); 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    setSize(Toolkit.getDefaultToolkit().getScreenSize()); 
    setLocationRelativeTo(null); 
    setExtendedState(JFrame.MAXIMIZED_BOTH); 
    contentPane = new JPanel(); 

    contentPane.setBackground(new Color(201, 77, 83)); 
    contentPane.setLayout(null); 
    setContentPane(contentPane); 

    addKeyListener(new KeyAdapter() { 
     @Override 
     public void keyReleased(KeyEvent e) { 
      if (e.getKeyCode() == KeyEvent.VK_SPACE) { 
       startTimer(); 
      } 
     } 
    }); 

    JLabel lblMinimize = new JLabel("-"); 
    lblMinimize.setBounds(1835, -20, 16, 95); 
    lblMinimize.addMouseListener(new MouseAdapter() { 
     @Override 
     public void mouseReleased(MouseEvent e) { 
      setState(JFrame.ICONIFIED); 
     } 

     @Override 
     public void mouseEntered(MouseEvent e) { 
      lblMinimize.setForeground(Color.BLACK); 
     } 

     @Override 
     public void mouseExited(MouseEvent e) { 
      lblMinimize.setForeground(Color.WHITE); 
     } 
    }); 
    lblMinimize.setForeground(Color.WHITE); 
    lblMinimize.setFont(new Font("Segoe UI", Font.PLAIN, 40)); 
    contentPane.add(lblMinimize); 

    JLabel lblX = new JLabel("X"); 
    lblX.setBounds(1873, 0, 24, 54); 
    lblX.addMouseListener(new MouseAdapter() { 
     @Override 
     public void mouseReleased(MouseEvent e) { 
      System.exit(0); 
     } 

     @Override 
     public void mouseEntered(MouseEvent e) { 
      lblX.setForeground(Color.BLACK); 
     } 

     @Override 
     public void mouseExited(MouseEvent e) { 
      lblX.setForeground(Color.WHITE); 
     } 
    }); 

    lblX.setFont(new Font("Segoe UI", Font.PLAIN, 40)); 
    lblX.setHorizontalAlignment(SwingConstants.CENTER); 
    lblX.setForeground(Color.WHITE); 
    contentPane.add(lblX); 

    labelTimer = new JLabel("0.0.0"); 
    labelTimer.setHorizontalAlignment(SwingConstants.CENTER); 
    labelTimer.setFont(new Font("DINPro-Bold", Font.PLAIN, 200)); 
    labelTimer.setForeground(Color.WHITE); 
    labelTimer.setBounds(371, 134, 1418, 653); 
    contentPane.add(labelTimer); 
    setVisible(true); 
} 

ここに私はタイマーコードを持っています。私はいくつかの異なる場所で0にcalをリセットしようとしましたが、それは動作していません。

private void startTimer() { 
    new Thread() 
    { 
     public void run() 
     { 
      while(true) 
      { 
      Calendar cal = new GregorianCalendar(); 
      int minutes = cal.get(Calendar.MINUTE); 
      int seconds = cal.get(Calendar.SECOND); 
      int milliseconds = cal.get(Calendar.MILLISECOND); 
      labelTimer.setText(minutes + "." + seconds + "." + milliseconds); 
      } 
     } 
    }.start(); 
} 

}

+0

:パズルのその種類はルービックキューブの代わりに、ルービックキューブ –

答えて

0

あなたは、メインスレッド間通信のいくつかの手段を持っている必要がありタイマースレッドを停止することができるようにするためにとタイマースレッド。 RubixTimerMainクラスの同期メンバ変数を使用することができます:

private Boolean isStopped = new Boolean(true); 

次に、2つのメソッドを追加できます。変数を設定してタイマーを停止し、もう1つは変数の現在の状態をチェックします。

private void stopTimer(){ 
    synchronized(isStopped){ 
     isStopped = true; 
    } 
} 

private boolean isTimerRunning(){ 
    boolean result = false; 
    synchronized(isStopped){ 
     result = !isStopped; 
    } 
    return result; 
} 

あなたはそれがタイミングを開始し、停止するように、このように(のcreateWindow中)スペースキーのリスナーイベントを変更したくなるでしょう:

addKeyListener(new KeyAdapter() { 
    @Override 
    public void keyReleased(KeyEvent e) { 
     if (e.getKeyCode() == KeyEvent.VK_SPACE) { 
      if (isTimerRunning()){ 
       stopTimer(); 
      } else { 
       startTimer(); 
      } 
     } 
    } 
}); 

最後に、あなたはので、あなたのスレッド機能を適応させる必要があります停止状態変数がfalseの場合にのみ実行されます。変数に直接アクセスするのではなく、isTimerRunningメソッドを使用することに注意してください。また、GregorianCalendarの値をミリ秒単位に変換してから、現在の時刻から記録された開始時刻を差し引くことで、誤った時刻を表示するエラーを修正しました。トピックオフ

private void startTimer() { 
    new Thread() 
    { 
     public void run() 
     { 
      long timeStart = new GregorianCalendar().getTimeInMillis(); 
      synchronized(isStopped){ 
       isStopped = false; 
      } 

      while(isTimerRunning()) 
      { 
       long timeNow = new GregorianCalendar().getTimeInMillis() - timeStart; 
       long milliseconds = (timeNow % 1000); 
       timeNow = (long) Math.floor(timeNow * 0.001f); 
       long seconds = (timeNow % 60); 
       timeNow = (long)Math.floor((float)timeNow/60f); 
       long minutes = timeNow; 

       labelTimer.setText(minutes + "." + seconds + "." + milliseconds); 
      } 
     } 
    }.start(); 
} 
+0

と呼ばれるコードの一つ最大の問題は、あなたが同期するように、間違ったターゲットを選択しているということです。この場合、それは致命的ではないかもしれませんが、あなたがそのような練習を続けていれば、結局は大きな問題を抱えています。メソッドを 'synchronized'としてマークするだけで十分です。 –

+0

' isStopped'との同期の問題については、このケースを考えてください: 'isStopped = false';スレッド1がロックされた 'isStopped';スレッド2は来て待ちます。スレッド1は 'isStopped'を' true'に変更し、ロックを解除します。スレッド2は「偽」のロックを取得し、次にスレッド3が来て、「isStopped」が真となり、スレッド3は「真」のロックを得ることができる。この時点で、スレッド2とスレッド3は同期していると同時に実行されています。 –

+0

@AdrianShum:申し訳ありませんが、間違っていると思います。 isStoppedの値は、synchronized文とは完全に無関係です。特に、複数のスレッドは、その変数の複数の異なる状態を決して見ることはできません。いつでも1つの異なる値しか存在しません。 ここをクリックしてください:https://docs.oracle.com/javase/tutorial/essential/concurrency/locksynchtml 上記のリンクでは、複数の(待機中の)スレッドが "this"の異なる状態を取得/表示する場合に動作しないsynchronized(this)を使用していることがわかります。 – Jireugi

0

一つの問題は、あなたがEDT(イベントディスパッチスレッド)にlabelTimerと相互作用していないということかもしれません。

スイングでは、UIオブジェクトとのすべてのやり取りがこのスレッドで行われている必要があります。

あなたが setTextへのお電話は SwingUtilities#invokeLaterの呼び出し中に発生したことを確認したらどうなりますか

https://docs.oracle.com/javase/7/docs/api/javax/swing/SwingUtilities.html#invokeLater(java.lang.Runnable)

関連する問題