javax.swing.Timer slowdown in Java7u40

后端 未结 2 1386
盖世英雄少女心
盖世英雄少女心 2021-01-14 15:06

Invoke javax.swing.Timer#start() same time,

7u25 is not problem.

\"enter

相关标签:
2条回答
  • 2021-01-14 15:40

    Finally I write DIY repaint management class .. :(

    import java.awt.event.*;
    import java.util.*;
    
    import javax.swing.*;
    import javax.swing.Timer;
    
    /**
     * EffectTimer
     */
    public class EffectTimer {
    
        /**
         * All of effect timers in instance of this class.
         */
        static class GlobalTimer implements ActionListener {
    
            List<EffectTimer> registeredEffects = new ArrayList<>();
    
            Timer timer = new Timer(16, this);
    
            public void start(final EffectTimer t) {
                SwingUtilities.invokeLater(new Runnable() {
    
                    @Override
                    public void run() {
                        internalStart(t);
                    }
    
                });
            }
    
            void internalStart(EffectTimer t) {
                int initialDelay = Math.max(0, (int) (t.getEffectStartTime() - System.currentTimeMillis()));
                if(timer.getInitialDelay() >= initialDelay) {
                    timer.setInitialDelay(initialDelay);
                }
                if(!registeredEffects.contains(t)) {
                    registeredEffects.add(t);
                    if(registeredEffects.size() == 1) {
                        timer.start();
                    }
                }
            }
    
            void stop(final EffectTimer t) {
                SwingUtilities.invokeLater(new Runnable() {
    
                    @Override
                    public void run() {
                        registeredEffects.remove(t);
                        checkStop();
                    }
    
                });
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                long now = e.getWhen();
    
                Iterator<EffectTimer> iter = registeredEffects.iterator();
                while(iter.hasNext()) {
                    EffectTimer t = iter.next();
                    long elapsedMs = now - t.getEffectStartTime();
    
                    if(elapsedMs > 0) {
                        float p = elapsedMs / (float)t.getEffectLengthMs();
                        if(p >= 1.0f) {
                            iter.remove();
                            t.stop();
                        } else {
                            if(t.isReversed()) {
                                p = 1.0f - p;
                            }
                            t.progressChanged(p);
                        }
                    }
                }
    
                checkStop();
            }
    
            void checkStop() {
                if(registeredEffects.isEmpty()) {
                    timer.stop();
                }
            }
    
            public int getRunningTimerCount() {
                return registeredEffects.size();
            }
    
            public void stopAll() {
                SwingUtilities.invokeLater(new Runnable() {
    
                    @Override
                    public void run() {
                        registeredEffects.clear();
                        checkStop();
                    }
    
                });
            }
    
        }
    
        static final GlobalTimer GTIMER = new GlobalTimer();
    
        int effectLengthMs = -1;
    
        long effectStartMs = -1;
    
        float progress = 0.0f;
    
        boolean reversed = true;
    
        public long getEffectStartTime() {
            return effectStartMs;
        }
    
        public int getEffectLengthMs() {
            return effectLengthMs;
        }
    
        public void start(int lengthMs) {
            start(lengthMs, System.currentTimeMillis());
        }
    
        public void start(int lengthMs, long startMs) {
            effectLengthMs = lengthMs;
            effectStartMs = startMs;
    
            reversed = false;
            progress = 0.0f;
            GTIMER.start(this);
        }
    
        public boolean isReversed() {
            return reversed;
        }
    
        public void reverse(final int lengthMs) {
            SwingUtilities.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    internalReverse(lengthMs);
                }
    
            });
        }
    
        void internalReverse(int lengthMs) {
            reversed = !reversed;
    
            effectLengthMs = lengthMs;
            int adjust = reversed ? (int)(lengthMs * (1.0f - progress)) : (int)(lengthMs * progress);
            effectStartMs = System.currentTimeMillis() - adjust;
    
            GTIMER.start(this);
        }
    
        final public void progressChanged(float p) {
            progress = p;
            run(p);
        }
    
        /**
         * 0.0f to 1.0f effect progress.
         * <code>Float.compare(progress, 1.0f) >= 0</code> to end progress.
         */
        protected void run(float p) {}
    
        public void stop() {
            progress = reversed ? 0.0f : 1.0f;
            GTIMER.stop(this);
        }
    
        public boolean isRunning() {
            return 0.0f < progress && progress < 1.0f;
        }
    
        public float getProgress() {
            return progress;
        }
    
        public static int getRunningTimerCount() {
            return GTIMER.getRunningTimerCount();
        }
    
        public static void stopAll() {
            GTIMER.stopAll();
        }
    
    }
    
    0 讨论(0)
  • 2021-01-14 16:01

    Several issues arise in your example:

    • Swing GUI objects should be constructed and manipulated only on the event dispatch thread.

    • All Swing Timer instances share a common thread, which is being saturated.

    Depending on the goal, some alternatives are possible:

    • Use a single Timer instance, and select some fraction for update at a proportionally higher rate. The example below randomly selects N of the components and updates them every 100 ms.

    • Use TexturePaint, as shown here.

    image

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.Random;
    import javax.swing.*;
    
    /** @see https://stackoverflow.com/a/18936444/230513 */
    public class BlinkenLights {
    
        private static final int S = 24;
        private static final int N = 10;
        private static final Random r = new Random();
        private static final List<MyComponent> list = new ArrayList<MyComponent>();
    
        private static final class MyComponent extends JComponent {
    
            public MyComponent() {
                this.setOpaque(true);
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(S, S);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                g.setColor(Color.getHSBColor(r.nextFloat() / 6, 1, 1));
                g.fillRect(0, 0, getWidth(), getHeight());
            }
        }
    
        private static JPanel createPanel() {
            final JPanel p = new JPanel();
            p.setLayout(new GridLayout(N, N));
            for (int i = 0; i < N * N; i++) {
                MyComponent c = new MyComponent();
                p.add(c);
                list.add(c);
            }
            Timer t = new Timer(1000 / N, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Collections.shuffle(list, r);
                    for (int i = 0; i < N; i++) {
                        list.get(i).repaint();
                    }
                }
            });
            t.start();
            return p;
        }
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    JFrame f = new JFrame();
                    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    f.add(createPanel());
                    f.pack();
                    f.setLocationRelativeTo(null);
                    f.setVisible(true);
                }
            });
        }
    }
    
    0 讨论(0)
提交回复
热议问题