为了SwingTimer
准确起见,我喜欢@Tony Docherty On CR 提出的逻辑和示例。这是链接。
为了一次又一次地突出给定的单词,总是会有几微秒的延迟。如果我要突出显示的话:“你好,怎么样”并且每个词的值分别是(延迟):200,300,400 ms,那么计时器所花费的实际时间总是更多。说不是 200 毫秒,而是 216 毫秒。像这样,如果我有很多话..最后,额外的延迟是显而易见的。
我必须突出显示每个字母说:'h''e''l''l''0' 每个应该得到 200/length(ie 5) = 40 ms 大约。在每个字母之后设置延迟。
我的逻辑是,以当前时间为例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 秒,因此每个字母突出显示 250 毫秒。以您最初的方式做事,确实意味着您为每个字母设置了一个 250 毫秒的计时器,但如果每个周期实际上花费了 260 毫秒,并且假设“e”周期花费了 400 毫秒(可能是由于 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 键时,当前单词会突出显示,并且当前单词所花费的时间单词存储在一个数组中。我继续存储时间。当用户结束时,现在我想根据设定的时间突出显示单词。所以在这里,用户的时机很重要。如果时间很快,单词的突出显示也是如此,或者如果很慢,反之亦然。
新更新:进度
下面的答案有不同的逻辑,但令我惊讶的是,它们或多或少是相同的。我发现所有逻辑(包括我的逻辑)的一个非常非常奇怪的问题是,它们似乎在几行代码中都能完美运行,但在那之后它们的速度也不是很慢,而是有很大的不同。
此外,如果您认为我应该以不同的方式思考,我们非常感谢您的建议。