【发布时间】:2013-02-09 01:30:52
【问题描述】:
为了使SwingTimer准确,我喜欢@Tony Docherty 提出的逻辑和示例
在 CR 上。这是Link。
为了突出显示给定的单词,一次又一次,总是有几微秒的延迟。如果我要突出显示的话:“你好,怎么样”并且每个词的值分别是(延迟):200,300,400 毫秒,那么计时器所花费的实际时间总是更多。说不是 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 秒,因此每个字母都会高亮显示 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 键时,当前单词会突出显示,并且当前单词所花费的时间单词存储在一个数组中。我继续存储时间。当用户结束时,现在我想根据设定的时间突出显示单词。所以在这里,用户的时机很重要。如果时间快,则突出显示单词,如果慢,反之亦然。
新更新:进展
下面的答案有不同的逻辑,但令我惊讶的是,它们或多或少是相同的。我发现所有逻辑(包括我的)的一个非常非常奇怪的问题是,它们似乎在几行代码中都能完美运行,但之后它们的速度提高了,这也不是很慢,而是有很大的不同。
此外,如果您认为我应该以不同的方式思考,我们非常感谢您的建议。
【问题讨论】:
-
在 EDT 上调用的 while 循环对我来说看起来很可疑。让我重新阅读您的要求...
-
@HovercraftFullOfEels while 循环没有冻结任何东西,直到现在。我正在尝试检查摆动计时器从突出显示的东西开始所采取的额外延迟。将进行更新让它更清楚。
-
我仍然不完全理解您的问题是什么:有一次,我看到在停止计时器后并非所有字母都是红色的 - 这是问题的一部分吗?并且:您所说的准确性究竟是什么意思,任何硬数字,如果是这样,您是如何计算它们的,或者是什么硬件(?)事件产生的?无论如何,您可能不会低于典型粗略硬件计时器产生的 15 毫秒,而且您的操作本身需要一些时间。
-
@kleopatra 1) 并不是所有的字母都是红色的:那是因为同步。我可能会放弃 hhighlighting 中间的几个字母但不会松散同步。当我看到该过程所花费的时间是更多,我跳过那封信。 2)不,不是问题的一部分,你的逻辑可能不同。 3)准确性-我希望它们根据背景声音/音乐/歌曲突出显示(与 Kataoke 应用程序中的同步相同,因为它们同步非常好)。是的,确实,可能会有 CPU 延迟,但有些要克服的逻辑,如果不是 100,那么准确率为 92%。
-
继续...我已经尝试了很多东西,也是@Hovercraft Full Of Eels 的答案。我没有更多的想法,希望能得到一些好的帮助。跨度>
标签: java swing timer event-dispatch-thread