2017-02-21 28 views
0

Я делаю игру. Я хочу иметь что-то вроде часов, показывающих, сколько времени прошло от попрошайничества. Он работает почти отлично, но он начинается, может быть, на секунду или два позже, чем начинается настоящая игра. Я не знаю, в чем причина этого, поэтому я буду признателен за любую помощь. Благодаря!Java - Swing Timer начинает отображаться немного позже, чем ожидалось

Я создал похожую ситуацию (runnable).

import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.concurrent.TimeUnit; 
import javax.swing.Timer; 


public class GUI extends javax.swing.JFrame { 

    private Timer SimpleTimer; 

    public GUI() { 
     initComponents(); 
    } 

    private void initComponents() { 

     jLabel1 = new javax.swing.JLabel(); 
     jButton1 = new javax.swing.JButton(); 

     setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 

     jButton1.setText("jButton1"); 
     jButton1.addActionListener(new java.awt.event.ActionListener() { 
      public void actionPerformed(java.awt.event.ActionEvent evt) { 
       jButton1ActionPerformed(evt); 
      } 
     }); 

     javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); 
     getContentPane().setLayout(layout); 
     layout.setHorizontalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
      .addGroup(layout.createSequentialGroup() 
       .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
        .addGroup(layout.createSequentialGroup() 
         .addGap(154, 154, 154) 
         .addComponent(jLabel1)) 
        .addGroup(layout.createSequentialGroup() 
         .addGap(131, 131, 131) 
         .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE))) 
       .addContainerGap(196, Short.MAX_VALUE)) 
     ); 
     layout.setVerticalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
      .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() 
       .addContainerGap(92, Short.MAX_VALUE) 
       .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) 
       .addGap(48, 48, 48) 
       .addComponent(jLabel1) 
       .addGap(137, 137, 137)) 
     ); 

     pack(); 
    }      

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {           
     startGame(); 
    }           

    public static void main(String args[]) { 
     java.awt.EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       new GUI().setVisible(true); 
      } 
     }); 
    } 

    private javax.swing.JButton jButton1; 
    private javax.swing.JLabel jLabel1;    

    private void startGame() { 
     long startTime = System.currentTimeMillis(); 
     if(SimpleTimer != null) { 
      SimpleTimer.stop(); 
     } 
     SimpleTimer = new Timer(1000, new ActionListener(){ 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       long millis = System.currentTimeMillis() - startTime; 
       jLabel1.setText("Time passed: " + String.format("%02d:%02d:%02d", TimeUnit.MILLISECONDS.toHours(millis), 
      TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)), 
      TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)))); 
      } 
     }); 
     SimpleTimer.start(); 
    } 
} 
+0

Временная задержка '0' здесь:' Таймер (0, новый ActionListener() ...) 'нереалистичен и рискован. Это должно быть от 13 до 15 на самом низком уровне. –

+1

'' Я думаю, что это весь код, относящийся к таймеру ... "' - посмотрите на [mcve], а затем попытайтесь создать и опубликовать один из них. Если вы упростите нам возможность понять свой код и вашу проблему, вы, вероятно, получите ответы на все более быстрые и быстрые ответы. –

+0

И это неправильно: '// Мне просто нужно было инициализировать его, чтобы я мог проверить, если он уже запущен'. Нет. Все, что вам нужно сделать, это сначала проверить значение null, а затем, если не null, проверьте, работает ли он. –

ответ

4

Ваши расчеты времени выходят. Не должно быть что-то вроде:

String text = String.format(TIME_FORMAT, 
     TimeUnit.MILLISECONDS.toHours(millis) % 24, 
     TimeUnit.MILLISECONDS.toMinutes(millis) % 60, 
     TimeUnit.MILLISECONDS.toSeconds(millis) % 60); 
timerLabel.setText("Time passed: " + text); 

Редактировать: нет, ваши преобразования в порядке. Я рекомендую, чтобы ваш таймер использовал более тонкую детализацию, а затем 1 секунду, если вы показываете единицы секунды. Здесь я использую гранулярность 100 миллисекунд.

Обратите внимание, что ваш код не работает для меня (попробуйте скопировать и запустить свой опубликованный код, чтобы узнать, что он делает).

Пожалуйста, проверьте, что такое MCVE должно выглядеть, как показано ниже, а затем скопировать и запустить этот код, чтобы увидеть таймер, который работает:

import java.awt.BorderLayout; 
import java.awt.Dimension; 
import java.awt.GridBagLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.KeyEvent; 
import java.util.concurrent.TimeUnit; 

import javax.swing.*; 

@SuppressWarnings("serial") 
public class SimpleTimer extends JPanel { 
    private static final String TIME_FORMAT = "%02d:%02d:%02d"; 
    public static final int TIMER_DELAY = 100; 
    private static final int PREF_W = 300; 
    private static final int PREF_H = 100; 
    private long startTime; 
    private Timer myTimer; 
    private JLabel timerLabel = new JLabel("00:00:00"); 
    private JCheckBox fastChkBox = new JCheckBox("Run Artificially Fast", false); 

    public SimpleTimer() { 
     JPanel centerPanel = new JPanel(new GridBagLayout()); 
     centerPanel.add(new JButton(new RestartAction("Restart", KeyEvent.VK_R))); 
     centerPanel.add(fastChkBox); 

     JPanel topPanel = new JPanel(); 
     topPanel.add(new JLabel("Time passed: ")); 
     topPanel.add(timerLabel); 

     setLayout(new BorderLayout()); 
     add(topPanel, BorderLayout.PAGE_START); 
     add(centerPanel, BorderLayout.CENTER); 
    } 

    private class RestartAction extends AbstractAction { 
     public RestartAction(String name, int mnemonic) { 
      super(name); 
      putValue(MNEMONIC_KEY, mnemonic); 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      if (myTimer != null && myTimer.isRunning()) { 
       myTimer.stop(); 
      } 

      startTime = System.currentTimeMillis(); 
      myTimer = new Timer(TIMER_DELAY, new TimerListener()); 
      myTimer.start(); 
     } 
    } 

    // make it bigger 
    @Override 
    public Dimension getPreferredSize() { 
     Dimension superSz = super.getPreferredSize(); 
     if (isPreferredSizeSet()) { 
      return superSz; 
     } 
     int prefW = Math.max(superSz.width, PREF_W); 
     int prefH = Math.max(superSz.height, PREF_H); 
     return new Dimension(prefW, prefH); 
    } 


    private class TimerListener implements ActionListener { 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      long millis = System.currentTimeMillis() - startTime; 

      if (fastChkBox.isSelected()) { 
       millis *= 512; // make time go faster 
      } 
      String text = String.format(TIME_FORMAT, 
        TimeUnit.MILLISECONDS.toHours(millis) % 24, 
        TimeUnit.MILLISECONDS.toMinutes(millis) % 60, 
        TimeUnit.MILLISECONDS.toSeconds(millis) % 60); 
      timerLabel.setText(text); 
     } 
    } 

    private static void createAndShowGui() { 
     SimpleTimer mainPanel = new SimpleTimer(); 

     JFrame frame = new JFrame("SimpleTimer"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(mainPanel); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(() -> createAndShowGui()); 
    } 
} 

Edit: код без строитель NetBeans хлама:

import java.awt.BorderLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.concurrent.TimeUnit; 

import javax.swing.JPanel; 
import javax.swing.Timer; 

@SuppressWarnings("serial") 
public class GUI extends javax.swing.JFrame { 

    private Timer SimpleTimer; 

    public GUI() { 
     initComponents(); 
    } 

    private void initComponents() { 

     jLabel1 = new javax.swing.JLabel(" Time passed: 00:00:00 "); 
     jButton1 = new javax.swing.JButton(); 

     setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 

     jButton1.setText("Restart"); 
     jButton1.addActionListener(new java.awt.event.ActionListener() { 
      public void actionPerformed(java.awt.event.ActionEvent evt) { 
       jButton1ActionPerformed(evt); 
      } 
     }); 

     JPanel btnPanel = new JPanel(); 
     btnPanel.add(jButton1); 
     JPanel labelPanel = new JPanel(); 
     labelPanel.add(jLabel1); 

     setLayout(new BorderLayout()); 
     add(labelPanel, BorderLayout.PAGE_START); 
     add(btnPanel, BorderLayout.CENTER); 

     pack(); 
    } 

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) { 
     startGame(); 
    } 

    public static void main(String args[]) { 
     java.awt.EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       new GUI().setVisible(true); 
      } 
     }); 
    } 

    private javax.swing.JButton jButton1; 
    private javax.swing.JLabel jLabel1; 

    private void startGame() { 
     long startTime = System.currentTimeMillis(); 
     if (SimpleTimer != null) { 
      SimpleTimer.stop(); 
     } 
     SimpleTimer = new Timer(100, new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       long millis = System.currentTimeMillis() - startTime; 
       jLabel1.setText("Time passed: " + String.format("%02d:%02d:%02d", 
         TimeUnit.MILLISECONDS.toHours(millis), 
         TimeUnit.MILLISECONDS.toMinutes(millis) 
           - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)), 
         TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES 
           .toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)))); 
      } 
     }); 
     SimpleTimer.start(); 
    } 
} 
+0

Я скопировал его из другого места, поэтому я думаю, что это проблема, но ваша версия не работает для меня :( – vixenn

+0

Ваш код не работает для меня. Пожалуйста, см. Edit, чтобы ответить, чтобы увидеть, что я имею в виду исправьте [mcve] и пример перезапуска таймера.Я также включил флажок, чтобы таймер пошел искусственно быстро. –

+0

Я запустил его, это рабочий для меня, это странно. Я увижу ваш пример. – vixenn