为了SwingTimer
准确起见,我喜欢@Tony Docherty On
CR建议的逻辑和示例。这是链接。
为了突出显示给定的单词,一次又一次地总是有几微秒的延迟。如果我要突出显示一些单词:“ hello how
are”,并且每个单词的值分别(延迟)为:200,300,400
ms,那么计时器实际花费的时间总是更多。说而不是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();
}
});
}
}
更新:
为了更好的理解:
@Tony Docherty给出的EG:
让我们以单词“
Test”为例,说它需要突出显示1秒钟,因此每个字母都突出显示250ms。以您原来的方式做事,确实意味着您为每个字母设置了250ms的计时器,但是如果每个周期实际上花费了260ms,并且可以说“
e”周期花费了400ms(可能是由于GC或其他使用CPU周期的原因),结束时,您需要多花180毫秒。该错误将继续为每个单词生成,直到该错误太大为止,突出显示不再在视觉上同步。
我正在尝试的方法,不是重复说该字母需要突出显示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个字母)的情况,但至少我会保持大致同步。
编辑的SSCCE
更新2
在第一阶段,我会为每个单词安排时间。也就是说,当用户按下ESC键时,将存储一个特定单词的时间(在后台播放歌曲时,他会这样做。)按下ESC键时,当前单词会突出显示,并且当前单词所花费的时间单词存储在数组中。我继续存储时间。当用户结束时,现在我想按照设置的时间突出显示单词。因此,在这里,用户的时间安排很重要。如果时间安排得很快,那么单词的突出显示也可以,反之亦然。
新更新:进度
以下答案具有不同的逻辑,但令我惊讶的是,它们的工作原理大致相同。我在所有逻辑(包括我的逻辑)中发现的一个非常非常奇怪的问题是,它们似乎只适用于几行,但是在获得速度之后,这也不算慢,但有很大的不同。
另外,如果您认为我应该以不同的方式思考,您的建议将受到高度赞赏。
好的,所以我一直在看一些代码(我在上一个关于卡拉OK计时器的问题中发布的代码)
使用该代码,我建立了一些测量系统,System.nanoTime()
通过System.out.println()
它可以帮助我们了解正在发生的事情:
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();
}
});
}
}
我的电脑上的输出是:
开始于:10289712615974
字符应花费的时间:166
花费时间:165
差异1
…
字符应花费的时间:166
花费时间:155
差异11
…
字符应花费的时间:166
花费时间:5
差异161
停止:10299835063084
总耗时:9960
使用每个字母所用时间的累加器所花费的时间:5542
差异:4418
使用差异所花费的时间(endTime-startTime):10122
差异:-162
因此,我的结论是Swing
Timer实际上运行的速度比我们预期的要快,因为Timer
s中的代码actionPerformed
不一定要花预期的字母突出显示时间的时间,这当然会引起雪崩效应,即,计时器运行的越快/越慢,则运行时间越大/差异将变小,下次执行的计时器restart(..)
将在不同的时间进行,即更快或更慢。
在代码中执行以下操作:
//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的最大延迟是每个字母快4毫秒):
开始:10813491256556
字符应花费的时间:166
花费时间:164
差异2
…
字符应花费的时间:166
花费时间:164
差异2
…
字符应花费的时间:166
花费时间:162
差异4
停止:10823452105363
总耗时:9960
使用每个字母所用时间的累加器所花费的时间:9806
差异:154
使用差异所花费的时间(endTime-startTime):9960
差异:0
为了使准确,我喜欢@Tony Docherty On CR建议的逻辑和示例。这是链接。 为了一次又一次地突出显示给定的单词,总是会有几微秒的延迟。如果我有要突出显示的单词,比如说:“你好,你好”,每个单词的值分别是(延迟):200300400毫秒,那么计时器实际花费的时间总是更多。比如说,如果我有很多单词的话,需要216毫秒,而不是200毫秒。。最后,额外的延迟是显而易见的。 我必须突出显示每个字
问题内容: 我需要创建一个简单但准确的计时器。 这是我的代码: 恰好在3600秒后,它将打印约3500秒。 为什么不准确? 如何创建准确的计时器? 问题答案: 为什么不准确? 因为您正在使用setTimeout()或setInterval()。他们不能被信任,没有针对他们的准确性保证。它们被允许 任意滞后,并且它们不能保持恒定的步伐而是趋向于漂移(如您所观察到的)。 如何创建准确的计时器? 使用该
问题内容: 对于这个问题,我很抱歉,但是我已经阅读了很多东西,而且看来我还不懂如何做一个计时器。所以我发布我的代码: 我正在尝试使该对象每200毫秒朝目标移动一次。我没有自我尝试过,它给了我同样的错误: 我不知道如何将计时器连接到带有参数的函数。我以为我没有正确使用SLOT参数,但这给了我这些错误。我想这都是错的。我将不胜感激:) 问题答案: 使用新样式的信号,它们更容易理解。 交换- 与- 一个
我在我的查询中添加了一个投影,它创建了一个像。。。 参见链接 和相同的错误y8_,y5_意味着所有关闭它给了一个错误。 我把它改成了。。。 它起作用了。但是我不知道如何在HQL修改它?
问题内容: 我创建了一个计时器,该计时器在按下按钮时启动,上面是运行的代码。谁能帮我创建一个计数为30的计时器?现在,当我运行它时,在标签中设置文本“ 30”,但我希望它从0开始并一直计数到30。 问题答案: 每次您的计时器运行时,它都会执行从0到30的循环,因此仅在循环结束时才刷新UI。您需要将i保留为成员,并在每次这样调用该方法时对其进行更新: 当然,一旦达到i = 30,您就应该取消时间,否
timeLabel应该从60倒数到0,但我还没有实现一个持续时间。例如这样它就像一个真正的倒数计时器。我该怎么做。另一个问题是运行此代码时游戏不会在模拟器中启动。我得到一个错误,我被重定向到AppDelegate.swift文件: