Issues: Creating a very accurate Swing Timer

前端 未结 4 541
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-31 12:27

In order to make SwingTimer accurate, I like the logic and example suggested by @Tony Docherty On CR. Here is the Link.

In order to highlight the given

4条回答
  •  灰色年华
    2020-12-31 13:20

    ScheduledExecutorService tends to be more accurate than Swing's Timer, and it offers the benefit of running more than one thread. In particular, if one tasks gets delayed, it does not affect the starting time of the next tasks (to some extent).

    Obviously if the tasks take too long on the EDT, this is going to be your limiting factor.

    See below a proposed SSCCE based on yours - I have also slightly refactored the startColoring method and split it in several methods. I have also added some "logging" to get a feedback on the timing of the operations. Don't forget to shutdown the executor when you are done or it might prevent your program from exiting.

    Each words starts colouring with a slight delay (between 5 and 20ms on my machine), but the delays are not cumulative. You could actually measure the scheduling overhead and adjust accordingly.

    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();
                }
            });
        }
    }
    

提交回复
热议问题