Java 问题:创建非常精确的摆动计时器
为了使Java 问题:创建非常精确的摆动计时器,java,swing,timer,event-dispatch-thread,Java,Swing,Timer,Event Dispatch Thread,为了使SwingTimer准确,我喜欢@Tony Docherty建议的逻辑和示例 在CR上,这里是 为了一次又一次地突出显示给定的单词,总是会有几微秒的延迟。如果我有要突出显示的单词,比如说:“你好,你好”,每个单词的值分别是(延迟):200300400毫秒,那么计时器实际花费的时间总是更多。比如说,不是200毫秒,而是216毫秒。像这样,如果我有很多单词……最后,额外的延迟是显而易见的 我必须突出显示每个字母,并说:“h”“e”“l”“l”“0”每个字母应获得200/长度(即5)=40毫秒左
SwingTimer
准确,我喜欢@Tony Docherty建议的逻辑和示例
在CR上,这里是
为了一次又一次地突出显示给定的单词,总是会有几微秒的延迟。如果我有要突出显示的单词,比如说:“你好,你好”,每个单词的值分别是(延迟):200300400毫秒,那么计时器实际花费的时间总是更多。比如说,不是200毫秒,而是216毫秒。像这样,如果我有很多单词……最后,额外的延迟是显而易见的
我必须突出显示每个字母,并说:“h”“e”“l”“l”“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();
}
});
}
}
因此,您现在应该能够看到,每封信的计时都进行了调整,以考虑到前一封信的任何时间超限。当然,可能是时间超限太大了,以至于你不得不跳过突出显示下一个字母(或者可能超过1个),但至少我会保持大致同步
编辑的SSCCE
更新2
在第一阶段,我为每个单词记录时间。也就是说,当用户点击ESC键时,会存储特定单词的时间(他在后台播放歌曲时会这样做)。当按下ESC键时,当前单词会高亮显示,并且在当前单词上花费的时间会存储在一个数组中。我一直在储存时间。当用户结束时,现在我想根据设置的时间突出显示单词。因此,在这里,用户的计时很重要。如果计时很快,那么单词的突出显示也很快,如果计时很慢,反之亦然
新更新:进度
下面的答案有不同的逻辑,但令我惊讶的是,它们的工作原理基本相同。我发现所有逻辑(包括我的逻辑)都存在一个非常奇怪的问题,它们似乎在少数几行中都能完美工作,但在这之后它们获得了速度,这也不是很慢,而是有着巨大的差异
另外,如果你认为我应该换一种方式思考,你的建议将受到高度赞赏。我认为,要做这样的事情,你需要一个摆动计时器,它以恒定的速率跳动,比如说15毫秒,只要它足够快以允许你需要的时间粒度,然后,当经过的时间满足您的要求时,触发计时器内所需的行为
- 换句话说,根本不更改计时器的延迟,只需根据需要更改所需的时间
- 您不应该在EDT上有
循环。让“while循环”成为摆动计时器本身while(true)
- 为了使您的逻辑更简单,您需要检查经过的时间是否>=需要的时间
- 同样,不要设置计时器的延迟。换句话说,不要将其用作计时器,而是用作轮询器。让它每隔xx毫秒不断轮询运行时间,然后在运行时间>=符合您的需要时做出反应
public void actionPerformed(ActionEvent actionEvent) {
if (index > WORDS.length || stringIndex >= doc.getLength()) {
((Timer)actionEvent.getSource()).stop();
}
currentElapsedTime = calcCurrentElapsedTime();
if (currentElapsedTime >= elapsedTimeForNextChar) {
setNextCharAttrib(stringIndex);
stringIndex++;
if (atNextWord(stringIndex)) {
stringIndex++; // skip whitespace
deltaTimeForEachChar = calcNextCharDeltaForNextWord();
} else {
elapsedTimeForNextChar += deltaTimeForEachChar;
}
}
// else -- we haven't reached the next time to change char attribute yet.
// keep polling.
}
例如,我的SSCCE:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;
import java.util.List;
import javax.swing.*;
import javax.swing.text.*;
public class Reminder3 {
private static final String TEXT = "arey chod chaad ke apnee saleem ki gali anarkali disco chalo";
private static final String[] WORDS = TEXT.split(" ");
private static final int[] TIMES = { 100, 400, 300, 900, 1000, 600, 200,
700, 700, 200, 200, 200, 200 };
private static final int POLLING_TIME = 12;
private StyledDocument doc;
private JTextPane textpane;
private JPanel mainPanel = new JPanel();
private List<ReminderWord> reminderWordList = new LinkedList<ReminderWord>();
private Timer timer;
// private int stringIndex = 0;
public Reminder3() {
doc = new DefaultStyledDocument();
textpane = new JTextPane(doc);
textpane.setText(TEXT);
javax.swing.text.Style style = textpane.addStyle("Red", null);
StyleConstants.setForeground(style, Color.RED);
JPanel textPanePanel = new JPanel();
textPanePanel.add(new JScrollPane(textpane));
JButton startBtn = new JButton(new AbstractAction("Start") {
@Override
public void actionPerformed(ActionEvent arg0) {
goThroughWords();
}
});
JPanel btnPanel = new JPanel();
btnPanel.add(startBtn);
mainPanel.setLayout(new BorderLayout());
mainPanel.add(textPanePanel, BorderLayout.CENTER);
mainPanel.add(btnPanel, BorderLayout.SOUTH);
}
public void goThroughWords() {
if (timer != null && timer.isRunning()) {
return;
}
doc = new DefaultStyledDocument();
textpane.setDocument(doc);
textpane.setText(TEXT);
javax.swing.text.Style style = textpane.addStyle("Red", null);
StyleConstants.setForeground(style, Color.RED);
int wordStartTime = 0;
for (int i = 0; i < WORDS.length; i++) {
if (i > 0) {
wordStartTime += TIMES[i - 1];
}
int startIndexPosition = 0; // set this later
ReminderWord reminderWord = new ReminderWord(WORDS[i], TIMES[i],
wordStartTime, startIndexPosition);
reminderWordList.add(reminderWord);
}
int findWordIndex = 0;
for (ReminderWord word : reminderWordList) {
findWordIndex = TEXT.indexOf(word.getWord(), findWordIndex);
word.setStartIndexPosition(findWordIndex);
findWordIndex += word.getWord().length();
}
timer = new Timer(POLLING_TIME, new TimerListener());
timer.start();
}
public JComponent getMainPanel() {
return mainPanel;
}
private void setNextCharAttrib(int textIndex) {
doc.setCharacterAttributes(textIndex, 1,
textpane.getStyle("Red"), true);
}
private class TimerListener implements ActionListener {
private ReminderWord currentWord = null;
private long startTime = System.currentTimeMillis();
@Override
public void actionPerformed(ActionEvent e) {
if (reminderWordList == null) {
((Timer) e.getSource()).stop();
return;
}
if (reminderWordList.isEmpty() && currentWord.atEnd()) {
((Timer) e.getSource()).stop();
return;
}
// if just starting, or if done with current word
if (currentWord == null || currentWord.atEnd()) {
currentWord = reminderWordList.remove(0); // get next word
}
long totalElapsedTime = System.currentTimeMillis() - startTime;
if (totalElapsedTime > (currentWord.getStartElapsedTime() + currentWord
.getIndex() * currentWord.getTimePerChar())) {
setNextCharAttrib(currentWord.getStartIndexPosition() + currentWord.getIndex());
currentWord.increment();
}
}
}
private static void createAndShowGui() {
Reminder3 reminder = new Reminder3();
JFrame frame = new JFrame("Reminder");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(reminder.getMainPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class ReminderWord {
private String word;
private int totalTime;
private int timePerChar;
private int startTime;
private int startIndexPosition;
private int index = 0;
public ReminderWord(String word, int totalTime, int startTime,
int startIndexPosition) {
this.word = word;
this.totalTime = totalTime;
this.startTime = startTime;
timePerChar = totalTime / word.length();
this.startIndexPosition = startIndexPosition;
}
public String getWord() {
return word;
}
public int getTotalTime() {
return totalTime;
}
public int getStartElapsedTime() {
return startTime;
}
public int getTimePerChar() {
return timePerChar;
}
public int getStartIndexPosition() {
return startIndexPosition;
}
public int increment() {
index++;
return index;
}
public int getIndex() {
return index;
}
public boolean atEnd() {
return index > word.length();
}
public void setStartIndexPosition(int startIndexPosition) {
this.startIndexPosition = startIndexPosition;
}
@Override
public String toString() {
return "ReminderWord [word=" + word + ", totalTime=" + totalTime
+ ", timePerChar=" + timePerChar + ", startTime=" + startTime
+ ", startIndexPosition=" + startIndexPosition + ", index=" + index
+ "]";
}
}
导入java.awt.BorderLayout;
导入java.awt.Color;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.util.LinkedList;
导入java.util.List;
导入javax.swing.*;
导入javax.swing.text.*;
公开课提醒3{
私有静态最终字符串TEXT=“arey chod chaad ke apnee saleem ki gali anarkali disco chalo”;
私有静态最终字符串[]WORDS=TEXT.split(“”);
私有静态final int[]次={1004003009001000600200,
700, 700, 200, 200, 200, 200 };
私有静态最终整数轮询时间=12;
私人文件;
私有JTextPane textpane;
private JPanel mainPanel=new JPanel();
private List rementerwordlist=new LinkedList();
私人定时器;
//私有int stringIndex=0;
公众提醒3(){
doc=新的DefaultStyledDocument();
textpane=新的JTextPane(doc);
textpane.setText(TEXT);
javax.swing.text.Style=textpane.addStyle(“红色”,null);
设置前景(样式、颜色、红色);
JPanel textPanePanel=新的JPanel();
添加(新的JScrollPane(textpane));
JButton startBtn=新JButton(新抽象动作(“开始”){
@凌驾
已执行的公共无效操作(操作事件arg0){
goThroughWords();
}
});
JPanel btnPanel=新的JPanel();
btnPanel.add(startBtn);
setLayout(新的BorderLayout());
添加(textPanePanel,BorderLayout.CENTER);
主面板。添加(btnPanel,BorderLayout.SOUTH);
}
公共空间goThroughWords(){
if(timer!=null&&timer.isRunning()){
返回;
}
doc=新的DefaultStyledDocument();
textpane.setDocument(doc);
textpane.setText(TEXT);
javax.swing.text.Style=textpane.addStyle(“红色”,null);
设置前景(样式、颜色、红色);
int-wordStartTime=0;
对于(int i=0;i<
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;
import java.util.List;
import javax.swing.*;
import javax.swing.text.*;
public class Reminder3 {
private static final String TEXT = "arey chod chaad ke apnee saleem ki gali anarkali disco chalo";
private static final String[] WORDS = TEXT.split(" ");
private static final int[] TIMES = { 100, 400, 300, 900, 1000, 600, 200,
700, 700, 200, 200, 200, 200 };
private static final int POLLING_TIME = 12;
private StyledDocument doc;
private JTextPane textpane;
private JPanel mainPanel = new JPanel();
private List<ReminderWord> reminderWordList = new LinkedList<ReminderWord>();
private Timer timer;
// private int stringIndex = 0;
public Reminder3() {
doc = new DefaultStyledDocument();
textpane = new JTextPane(doc);
textpane.setText(TEXT);
javax.swing.text.Style style = textpane.addStyle("Red", null);
StyleConstants.setForeground(style, Color.RED);
JPanel textPanePanel = new JPanel();
textPanePanel.add(new JScrollPane(textpane));
JButton startBtn = new JButton(new AbstractAction("Start") {
@Override
public void actionPerformed(ActionEvent arg0) {
goThroughWords();
}
});
JPanel btnPanel = new JPanel();
btnPanel.add(startBtn);
mainPanel.setLayout(new BorderLayout());
mainPanel.add(textPanePanel, BorderLayout.CENTER);
mainPanel.add(btnPanel, BorderLayout.SOUTH);
}
public void goThroughWords() {
if (timer != null && timer.isRunning()) {
return;
}
doc = new DefaultStyledDocument();
textpane.setDocument(doc);
textpane.setText(TEXT);
javax.swing.text.Style style = textpane.addStyle("Red", null);
StyleConstants.setForeground(style, Color.RED);
int wordStartTime = 0;
for (int i = 0; i < WORDS.length; i++) {
if (i > 0) {
wordStartTime += TIMES[i - 1];
}
int startIndexPosition = 0; // set this later
ReminderWord reminderWord = new ReminderWord(WORDS[i], TIMES[i],
wordStartTime, startIndexPosition);
reminderWordList.add(reminderWord);
}
int findWordIndex = 0;
for (ReminderWord word : reminderWordList) {
findWordIndex = TEXT.indexOf(word.getWord(), findWordIndex);
word.setStartIndexPosition(findWordIndex);
findWordIndex += word.getWord().length();
}
timer = new Timer(POLLING_TIME, new TimerListener());
timer.start();
}
public JComponent getMainPanel() {
return mainPanel;
}
private void setNextCharAttrib(int textIndex) {
doc.setCharacterAttributes(textIndex, 1,
textpane.getStyle("Red"), true);
}
private class TimerListener implements ActionListener {
private ReminderWord currentWord = null;
private long startTime = System.currentTimeMillis();
@Override
public void actionPerformed(ActionEvent e) {
if (reminderWordList == null) {
((Timer) e.getSource()).stop();
return;
}
if (reminderWordList.isEmpty() && currentWord.atEnd()) {
((Timer) e.getSource()).stop();
return;
}
// if just starting, or if done with current word
if (currentWord == null || currentWord.atEnd()) {
currentWord = reminderWordList.remove(0); // get next word
}
long totalElapsedTime = System.currentTimeMillis() - startTime;
if (totalElapsedTime > (currentWord.getStartElapsedTime() + currentWord
.getIndex() * currentWord.getTimePerChar())) {
setNextCharAttrib(currentWord.getStartIndexPosition() + currentWord.getIndex());
currentWord.increment();
}
}
}
private static void createAndShowGui() {
Reminder3 reminder = new Reminder3();
JFrame frame = new JFrame("Reminder");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(reminder.getMainPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class ReminderWord {
private String word;
private int totalTime;
private int timePerChar;
private int startTime;
private int startIndexPosition;
private int index = 0;
public ReminderWord(String word, int totalTime, int startTime,
int startIndexPosition) {
this.word = word;
this.totalTime = totalTime;
this.startTime = startTime;
timePerChar = totalTime / word.length();
this.startIndexPosition = startIndexPosition;
}
public String getWord() {
return word;
}
public int getTotalTime() {
return totalTime;
}
public int getStartElapsedTime() {
return startTime;
}
public int getTimePerChar() {
return timePerChar;
}
public int getStartIndexPosition() {
return startIndexPosition;
}
public int increment() {
index++;
return index;
}
public int getIndex() {
return index;
}
public boolean atEnd() {
return index > word.length();
}
public void setStartIndexPosition(int startIndexPosition) {
this.startIndexPosition = startIndexPosition;
}
@Override
public String toString() {
return "ReminderWord [word=" + word + ", totalTime=" + totalTime
+ ", timePerChar=" + timePerChar + ", startTime=" + startTime
+ ", startIndexPosition=" + startIndexPosition + ", index=" + index
+ "]";
}
}
public class Reminder {
private static final String TEXT = "arey chod chaad ke apnee saleem ki gali anarkali disco chalo\n" +
"arey chod chaad ke apnee saleem ki gali anarkali disco chalo\n" +
"arey chod chaad ke apnee saleem ki gali anarkali disco chalo\n" +
"arey chod chaad ke apnee saleem ki gali anarkali disco chalo\n" +
"arey chod chaad ke apnee saleem ki gali anarkali disco chalo\n" +
"arey chod chaad ke apnee saleem ki gali anarkali disco chalo";
private static final String[] WORDS = TEXT.split("\\s+");
private JFrame frame;
private StyledDocument doc;
private JTextPane textpane;
private static final int[] TIMES = {100, 400, 300, 900, 1000, 600, 200, 700, 700, 200, 200,
100, 400, 300, 900, 1000, 600, 200, 700, 700, 200, 200,
100, 400, 300, 900, 1000, 600, 200, 700, 700, 200, 200,
100, 400, 300, 900, 1000, 600, 200, 700, 700, 200, 200,
100, 400, 300, 900, 1000, 600, 200, 700, 700, 200, 200,
100, 400, 300, 900, 1000, 600, 200, 700, 700, 200, 200, 200};
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
private int currentLetterIndex;
private long start; //for logging
public void startColoring() {
start = System.currentTimeMillis(); //for logging
int startTime = TIMES[0];
for (int i = 0; i < WORDS.length; i++) {
scheduler.schedule(colorWord(i, TIMES[i + 1]), startTime, TimeUnit.MILLISECONDS);
startTime += TIMES[i+1];
}
scheduler.schedule(new Runnable() {
@Override
public void run() {
scheduler.shutdownNow();
}
}, startTime, TimeUnit.MILLISECONDS);
}
//Color the given word, one letter at a time, for the given duration
private Runnable colorWord(final int wordIndex, final int duration) {
final int durationPerLetter = duration / WORDS[wordIndex].length();
final int wordStartIndex = currentLetterIndex;
currentLetterIndex += WORDS[wordIndex].length() + 1;
return new Runnable() {
@Override
public void run() {
System.out.println((System.currentTimeMillis() - start) + " ms - Word: " + WORDS[wordIndex] + " - duration = " + duration + "ms");
for (int i = 0; i < WORDS[wordIndex].length(); i++) {
scheduler.schedule(colorLetter(wordStartIndex + i), i * durationPerLetter, TimeUnit.MILLISECONDS);
}
}
};
}
//Color the letter on the EDT
private Runnable colorLetter(final int letterIndex) {
return new Runnable() {
@Override
public void run() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
System.out.println("\t" + (System.currentTimeMillis() - start) + " ms - letter: " + TEXT.charAt(letterIndex));
doc.setCharacterAttributes(letterIndex, 1, textpane.getStyle("Red"), true);
}
});
}
};
}
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.invokeLater(new Runnable() {
@Override
public void run() {
Reminder reminder = new Reminder();
reminder.initUI();
reminder.startColoring();
}
});
}
}
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, 1000, 1000, 1000, 1000, 1000, 1000};//word/letters timings
private String[] individualWordsToHighlight = {" \nHello\n", " world\n", " Hello", " world", " Hello", " world", " Hello", " world", " Hello", " 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();
}
});
}
}
//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();