gpt4 book ai didi

java - 发行: Creating a very accurate Swing Timer

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:08:45 27 4
gpt4 key购买 nike

为了使SwingTimer准确,我喜欢@Tony Docherty建议的逻辑和示例
在CR。这是Link

为了突出显示给定的单词,一次又一次地总是有几微秒的延迟。如果我要突出显示一些单词:“hello how are”,并且每个单词的值分别(延迟)为:200,300,400 ms,则计时器实际花费的时间总是更多。说而不是200毫秒,而是216毫秒。像这样,如果我有很多话……最后,额外的延迟是显而易见的。

我必须突出显示每个字母说:'h'e'l'l'0'每个字母应获得200/length(即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秒钟,因此每个字母都突出显示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();
}
});
}
}

我的电脑上的输出是:

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



因此,我的结论是Swing计时器的运行速度实际上比我们预期的要快,因为 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毫秒):

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

关于java - 发行: Creating a very accurate Swing Timer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15040989/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com