加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 问题:创建一个非常精确的摆动定时器

发布时间:2020-12-14 05:31:47 所属栏目:Java 来源:网络整理
导读:为了使SwingTimer准确,我喜欢@Tony Docherty提出的逻辑和示例 在CR上.这是 Link. 为了强调给定的单词,一次又一次地总是有几微秒的延迟.如果我有话要突出说:“你好怎么样”,每个单词的值分别是(延迟):200,300,400 ms,那么定时器的实际时间总是更多.说,而不
为了使SwingTimer准确,我喜欢@Tony Docherty提出的逻辑和示例
在CR上.这是 Link.

为了强调给定的单词,一次又一次地总是有几微秒的延迟.如果我有话要突出说:“你好怎么样”,每个单词的值分别是(延迟):200,300,400 ms,那么定时器的实际时间总是更多.说,而不是200毫秒,它需要216毫秒.像这样,如果我有很多话,最后,额外的延迟是显而易见的.

我必须强调每个字母说:’h””””’0’每个应该得到200 /长度(即5)= 40毫秒约.设置每个字母后的延迟.

我的逻辑是,拿起当前时间说startTime,就在开始之前.另外,计算totalDelay的totalDelay = delay / .length().

现在检查条件:(startTime totalDelay-System.currentTime)
如果这是-ve,那意味着时间消耗更多,所以跳过这个信.检查直到有一个积极的延迟.这意味着我正在添加到现在的时间,并且超过了这个过程在开始时所花费的时间差异.

这可能会导致跳过来突出显示字母.

但有些事情是错误的.什么,我很难做出来.这可能是循环的问题.我已经看到它进入循环(检查时间是否是-ve)只有两次.但不应该是这样.而且我也不知道如何设置我的下一个延迟.有任何想法吗?

这是一个SSCCE:

import java.awt.Color;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.lang.reflect.InvocationTargetException;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JTextPane;
    import javax.swing.SwingUtilities;
    import javax.swing.Timer;
    import javax.swing.text.BadLocationException;
    import javax.swing.text.DefaultStyledDocument;
    import javax.swing.text.StyleConstants;
    import javax.swing.text.StyledDocument;

    public class Reminder {
        private static final String TEXT = "arey chod chaad ke apnee saleem ki gali anarkali disco chalo";
        private static final String[] WORDS = TEXT.split(" ");
        private JFrame frame;
        private Timer timer;
        private StyledDocument doc;
        private JTextPane textpane;
        private int[] times = new int[100];
      private long totalDelay=0,startTime=0;

        private int stringIndex = 0;
        private int index = 0;

        public void startColoring() {
              times[0]=100;times[9]=200;times[10]=200;times[11]=200;times[12]=200;
              times[1]=400;times[2]=300;times[3]=900;times[4]=1000;times[5]=600;times[6]=200;times[7]=700;times[8]=700;

      ActionListener actionListener = new ActionListener() {
       @Override
       public void actionPerformed(ActionEvent actionEvent) 
       {

       doc.setCharacterAttributes(stringIndex,1,textpane.getStyle("Red"),true);
        stringIndex++;

 try {

 if (stringIndex >= doc.getLength() || doc.getText(stringIndex,1).equals(" ")|| doc.getText(stringIndex,1).equals("n"))
 {
                            index++;
  }
    if (index < WORDS.length) {

       double delay = times[index];
     totalDelay+=delay/WORDS[index].length();

  /*Check if there is no -ve delay,and you are running according to the time*/
  /*The problem is here I think. It's just entered this twice*/
   while(totalDelay+startTime-System.currentTimeMillis()<0)
      { 
      totalDelay+=delay/WORDS[index].length();
      stringIndex++;
     /*this may result into the end of current word,jump to next word.*/
    if (stringIndex >= doc.getLength() || doc.getText(stringIndex,1).equals(" ") || doc.getText(stringIndex,1).equals("n"))
       {
   index += 1;
   totalDelay+=delay/WORDS[index].length();
       }
      }

     timer.setDelay((int)(totalDelay+startTime-System.currentTimeMillis()));

                        } 
else {
         timer.stop();
    System.err.println("Timer stopped");
       }
                    } catch (BadLocationException e) {
                        e.printStackTrace();
                    }
                }
            };

            startTime=System.currentTimeMillis();
            timer = new Timer(times[index],actionListener);
            timer.setInitialDelay(0);
            timer.start();
        }

        public void initUI() {
            frame = new JFrame();
            frame.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
            JPanel panel = new JPanel();
            doc = new DefaultStyledDocument();
            textpane = new JTextPane(doc);
            textpane.setText(TEXT);
            javax.swing.text.Style style = textpane.addStyle("Red",null);
            StyleConstants.setForeground(style,Color.RED);
            panel.add(textpane);
            frame.add(panel);
            frame.pack();
            frame.setVisible(true);
        }

        public static void main(String args[]) throws InterruptedException,InvocationTargetException {
            SwingUtilities.invokeAndWait(new Runnable() {
                @Override
                public void run() {
                    Reminder reminder = new Reminder();
                    reminder.initUI();
                    reminder.startColoring();
                }
            });
        }
    }

更新:

为了更好地了解:

由@Tony Docherty提供的EG:

让我们用单词“测试”,并说需要突出显示1秒钟,因此每个字母都突出显示250ms.
以你最初的方式做事情,这意味着你为每个字母设置了一个250ms的定时器,但是如果每个周期实际上花费了260ms,并且让’e’周期花费了400ms(可能是由于GC或其他使用CPU周期的)这个词的结尾应该比你应该有180ms.这个错误将继续为每个单词构建,直到错误是如此之大,突出显示不再是视觉上同步的.

我正在尝试的方式,而不是反复说这个字母需要突出显示x的时间量,计算每个字母相对于序列开始的时间,即T = 250,e = 500,s = 750,t = 1000.

所以为了获得实际的时间延迟,你需要添加开始时间并减去当前时间.要用上面给我的时间运行示例:

StartTime   Letter   Offset    CurrentTime    Delay  ActualTimeTaken   
100000         T       250       100010        240      250  
100000         e       500       100260        240      400  
100000         s       750       100660         90      100  
100000         t      1000       100760        240      250

所以你现在应该可以看到,每个字母的时间调整是为了考虑到上一封信超时的时间.当然这是可能的时间超限是如此之大,你必须跳过突出显示下一个字母(或可能超过1),但至少我将保持广泛的同步.

EDITED SSCCE

UPDATE2

在第一阶段,我将每个单词的时间顺序.也就是说,当用户击中ESC键时,存储一个特定单词的时间(当歌曲在背景中播放时).当按下ESC键时,当前单词突出显示,并在当前时间上花费时间字存储在数组中.我继续存储时间.当用户结束时,现在我想根据设置的时间突出显示这些单词.所以在这里,用户的时机很重要.如果时间快,话语的亮点也是如此之快,反之亦然.

新更新:进度

下面的答案有不同的逻辑,但令我吃惊的是,他们的工作或多或少是相同的.我发现所有的逻辑(包括我的)的一个非常奇怪的问题是,他们似乎完美地工作了几条线,但之后他们获得速度,这也不慢,但是有很大的区别.

此外,如果您认为我应该以不同的方式思考,您的建议是非常感激的.

解决方法

好的,所以我一直在看一些代码(我在最后一个问题上发布的代码卡拉OK计时器)

使用该代码,我通过System.out.println()使用System.nanoTime()放置一些测量系统,这将帮助我们看到发生了什么:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;

public class KaraokeTest {

    private int[] timingsArray = {1000,1000,9000,1000};//word/letters timings
    private String[] individualWordsToHighlight = {" nHellon"," worldn"," Hello"," world"," world"};//each individual word/letters to highlight
    private int count = 0;
    private final JTextPane jtp = new JTextPane();
    private final JButton startButton = new JButton("Start");
    private final JFrame frame = new JFrame();
    //create Arrays of individual letters and their timings
    final ArrayList<String> chars = new ArrayList<>();
    final ArrayList<Long> charsTiming = new ArrayList<>();

    public KaraokeTest() {
        initComponents();
    }

    private void initComponents() {
        frame.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);

        for (String s : individualWordsToHighlight) {
            String tmp = jtp.getText();
            jtp.setText(tmp + s);
        }
        jtp.setEditable(false);

        startButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                startButton.setEnabled(false);
                count = 0;
                charsTiming.clear();
                chars.clear();

                for (String s : individualWordsToHighlight) {
                    for (int i = 0; i < s.length(); i++) {
                        chars.add(String.valueOf(s.charAt(i)));
                        //System.out.println(String.valueOf(s.charAt(i)));
                    }
                }

                //calculate each letters timings
                for (int x = 0; x < timingsArray.length; x++) {
                    for (int i = 0; i < individualWordsToHighlight[x].length(); i++) {
                        individualWordsToHighlight[x] = individualWordsToHighlight[x].replace("n"," ").replace("r"," ");//replace line breaks
                        charsTiming.add((long) (timingsArray[x] / individualWordsToHighlight[x].trim().length()));//dont count spaces
                        //System.out.println(timingsArray[x] / individualWordsToHighlight[x].length());
                    }
                }

                Timer t = new Timer(1,new AbstractAction() {
                    long startTime = 0;
                    long acum = 0;
                    long timeItTookTotal = 0;
                    long dif = 0,timeItTook = 0,timeToTake = 0;
                    int delay = 0;

                    @Override
                    public void actionPerformed(ActionEvent ae) {
                        if (count < charsTiming.size()) {

                            if (count == 0) {
                                startTime = System.nanoTime();
                                System.out.println("Started: " + startTime);
                            }

                            timeToTake = charsTiming.get(count);
                            acum += timeToTake;

                            //highlight the next word
                            highlightNextWord();

                            //System.out.println("Acum " + acum);
                            timeItTook = (acum - ((System.nanoTime() - startTime) / 1000000));
                            timeItTookTotal += timeItTook;
                            //System.out.println("Elapsed since start: " + (System.nanoTime() - startTime));
                            System.out.println("Time the char should take: " + timeToTake);
                            System.out.println("Time it took: " + timeItTook);
                            dif = (timeToTake - timeItTook);
                            System.out.println("Difference: " + dif);
                            //System.out.println("Difference2 " + (timeToTake - dif));

                            //calculate start of next letter to highlight less the difference it took between time it took and time it should actually take
                            delay = (int) (timeToTake - dif);

                            if (delay < 1) {
                                delay = 1;
                            }

                            //restart timer with new timings
                            ((Timer) ae.getSource()).setInitialDelay((int) timeToTake);//timer is usually faster thus the entire highlighting will be done too fast
                            //((Timer) ae.getSource()).setInitialDelay(delay);
                            ((Timer) ae.getSource()).restart();

                        } else {//we are at the end of the array
                            long timeStopped = System.nanoTime();
                            System.out.println("Stopped: " + timeStopped);
                            System.out.println("Time it should take in total: " + acum);
                            System.out.println("Time it took using accumulator of time taken for each letter: " + timeItTookTotal
                                    + "nDifference: " + (acum - timeItTookTotal));
                            long timeItTookUsingNanoTime = ((timeStopped - startTime) / 1000000);
                            System.out.println("Time it took using difference (endTime-startTime): " + timeItTookUsingNanoTime
                                    + "nDifference: " + (acum - timeItTookUsingNanoTime));
                            reset();
                            ((Timer) ae.getSource()).stop();//stop the timer
                        }
                        count++;//increment counter
                    }
                });
                t.setRepeats(false);
                t.start();
            }
        });

        frame.add(jtp,BorderLayout.CENTER);
        frame.add(startButton,BorderLayout.SOUTH);

        frame.pack();
        frame.setVisible(true);
    }

    private void reset() {
        startButton.setEnabled(true);
        jtp.setText("");
        for (String s : individualWordsToHighlight) {
            String tmp = jtp.getText();
            jtp.setText(tmp + s);
        }
        JOptionPane.showMessageDialog(frame,"Done");
    }

    private void highlightNextWord() {
        //we still have words to highlight
        int sp = 0;
        for (int i = 0; i < count + 1; i++) {//get count for number of letters in words (we add 1 because counter is only incrementd after this method is called)
            sp += 1;
        }

        while (chars.get(sp - 1).equals(" ")) {
            sp += 1;
            count++;
        }

        //highlight words
        Style style = jtp.addStyle("RED",null);
        StyleConstants.setForeground(style,Color.RED);
        ((StyledDocument) jtp.getDocument()).setCharacterAttributes(0,sp,style,true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new KaraokeTest();
            }
        });
    }
}

我的电脑上的输出是:

Started: 10289712615974

Time the char should take: 166

Time it took: 165

Difference 1

Time the char should take: 166

Time it took: 155

Difference 11

Time the char should take: 166

Time it took: 5

Difference 161

Stopped: 10299835063084

Time it should take in total: 9960

Time it took using accumulator of time taken for each letter: 5542

Difference: 4418

Time it took using difference (endTime-startTime): 10122

Difference: -162

因此,我的结论是,摆动计时器实际上运行速度比我们预期的要快,因为Timers actionPerformed中的代码不一定需要长久的字母,预计突出显示时间会导致雪崩效应,即定时器运行的速度越快/越慢/更小的差异将会变得和定时器下一次执行重新启动(..)将需要在不同的时间,即更快或更慢.

在代码中做这个:

//calculate start of next letter to highlight less the difference it took between time it took and time it should actually take
delay = (int) (timeToTake - dif);


//restart timer with new timings
//((Timer) ae.getSource()).setInitialDelay((int)timeToTake);//timer is usually faster thus the entire highlighting will be done too fast
((Timer) ae.getSource()).setInitialDelay(delay);
((Timer) ae.getSource()).restart();

产生更准确的结果(每个字母的最大延迟Ive为4ms):

Started: 10813491256556

Time the char should take: 166

Time it took: 164

Difference 2

Time the char should take: 166

Time it took: 164

Difference 2

Time the char should take: 166

Time it took: 162

Difference 4

Stopped: 10823452105363

Time it should take in total: 9960

Time it took using accumulator of time taken for each letter: 9806

Difference: 154

Time it took using difference (endTime-startTime): 9960

Difference: 0

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读