Chauncey Lee
Chauncey Lee

Reputation: 95

How to make an animated number counter using Java Swing?

I want to make an animated numeric counter, like this one:

https://i.sstatic.net/qiA5t.gif

I want to be able to input the value and have the counter update with animation.

I can find how to do this on Android from Google, but I cannot find any information on how to make it in Java Swing. How would I make something like this in Swing?

Upvotes: 3

Views: 853

Answers (2)

Suchin Madusha
Suchin Madusha

Reputation: 130

import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Point;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Animation {
    boolean loop=true;//true                            //loop
    static int start=1;//1                              //start
    static int end=10+1;//20                            // end + 1
    int delay1=1000;//1s                                // delay
    int delay2=1;//1ms                                  // delay
    Font font=new Font("Helvetica",Font.BOLD,25);       //Font
    
    Timer timer=new Timer(delay1, e -> move());JPanel panel = new JPanel();int[] size = {50,100};Point point = new Point(210,size[1]);
    Timer timer1=null;int value=start-1;int i;
    public static void main(String[] args) {if (start!=end) {new Animation();}}
    public void move() {
        timer.stop();value ++;
        if (!loop && value==end) {timer.stop();}i=0;
        timer1 = new Timer(delay2, e -> {
            if (i==100) {
                timer1.stop();
                timer.start();
            }
            point.setLocation(point.getX(), point.getY()-1);
            panel.setLocation(point);
            panel.revalidate();
            i++;
        });timer1.start();
        if (loop && value==end-1) {point.setLocation(point.getX(),size[1]+size[1]);value = start-1;}else if (value==end-1 && !loop){System.exit(0);}
    }
    public Animation() {
        JFrame frame = new JFrame();frame.setSize(500,300);frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.add(panel);frame.setLocationRelativeTo(null);
        panel.setLocation(point);frame.setLayout(null);frame.revalidate();panel.setSize(new Dimension(size[0],size[1]*Math.abs(end-(start-1))));
        panel.setLayout(new GridLayout(Math.abs(end-start)+start,1));if (!(end-start<0)) {for (int i=start;i!=(end-start)+start;i++) {JLabel la = new JLabel(String.valueOf(i));la.setFont(font);panel.add(la);
        }}timer.start();frame.revalidate();frame.setVisible(true);
    }
}

Upvotes: 1

Gilbert Le Blanc
Gilbert Le Blanc

Reputation: 51567

This isn't a complete answer, but this is a working example of a sliding JPanel. This code could be modified to create the display in the question.

Here's the complete runnable example.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class SlidingDigitGUI implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new SlidingDigitGUI());
    }
    
    private SlidingPanel secondPanel;

    @Override
    public void run() {
        JFrame frame = new JFrame("Sliding Digit");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        frame.add(createSlidingPanel(), BorderLayout.CENTER);
        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
        
        Animation animation = new Animation();
        new Thread(animation).start();
    }
    
    public JPanel createSlidingPanel() {
        String[] digitValues = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
        
        JPanel panel = new JPanel();
        panel.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 4, false));
        panel.setPreferredSize(new Dimension(300, 100));
        
        Font font = panel.getFont();
        Font derivedFont = font.deriveFont(Font.BOLD, 48F);
        
        secondPanel = new SlidingPanel(digitValues, derivedFont);
        secondPanel.setPanelValue("0");
        panel.add(secondPanel);
        
        return panel;
    }
    
    public class SlidingPanel extends JPanel {

        private static final long serialVersionUID = 661553022861652947L;

        private static final int MARGIN = 4;

        private int imageY;

        private BufferedImage slidingImage;

        private Dimension characterDimension;

        private final Font font;

        private String currentValue;

        private final String[] panelValues;

        public SlidingPanel(String[] panelValues, Font font) {
            this.panelValues = panelValues;
            this.font = font;
            this.characterDimension = calculateFontSize();
            this.slidingImage = generateSlidingImage();
            this.setPreferredSize(characterDimension);
        }

        private Dimension calculateFontSize() {
            int maxWidth = 0;
            int maxHeight = 0;
            FontRenderContext frc = new FontRenderContext(null, true, true);
            for (String s : panelValues) {
                Rectangle2D r2D = font.getStringBounds(s, frc);
                int rWidth = (int) Math.round(r2D.getWidth());
                int rHeight = (int) Math.round(r2D.getHeight());
                maxWidth = Math.max(maxWidth, rWidth);
                maxHeight = Math.max(maxHeight, rHeight);
            }

            return new Dimension(maxWidth, maxHeight);
        }

        private BufferedImage generateSlidingImage() {
            int height = calculateStringHeight() * (panelValues.length + 1);
            BufferedImage slidingImage = new BufferedImage(characterDimension.width, 
                    height, BufferedImage.TYPE_INT_RGB);
            Graphics g = slidingImage.getGraphics();
            g.setColor(Color.WHITE);
            g.fillRect(0, 0, characterDimension.width, height);
            g.setColor(Color.BLACK);
            g.setFont(font);

            int y = characterDimension.height - MARGIN;

            for (String s : panelValues) {
                g.drawString(s, 0, y);
                y += calculateStringHeight();
            }

            g.drawString(panelValues[0], 0, y);
            g.dispose();
            return slidingImage;
        }

        public void setPanelValue(String value) {
            int index = getValueIndex(value);
            this.currentValue = value;
            this.imageY = calculateStringHeight() * index;
            repaint();
        }

        public void updatePanelValue(String value) {
            if (!currentValue.equals(value)) {
                int index = getValueIndex(value);
                int finalY = calculateStringHeight() * index;
                SliderAnimation sliderAnimation = new SliderAnimation(imageY, finalY);
                new Thread(sliderAnimation).start();
                this.currentValue = value;
            }
        }

        private int getValueIndex(String value) {
            for (int index = 0; index < panelValues.length; index++) {
                if (value.equals(panelValues[index])) {
                    return index;
                }
            }

            return -1;
        }

        private int calculateStringHeight() {
            return characterDimension.height + MARGIN;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            BufferedImage subImage = slidingImage.getSubimage(0, imageY, 
                    characterDimension.width,
                    characterDimension.height);
            g.drawImage(subImage, 0, 0, this);
        }

        public class SliderAnimation implements Runnable {
            private int originalY;
            private int finalY;

            public SliderAnimation(int originalY, int finalY) {
                this.originalY = originalY;
                this.finalY = finalY;
            }

            @Override
            public void run() {
                int differenceY = finalY - originalY;
                if (finalY == 0) {
                    differenceY = characterDimension.height + MARGIN;
                }

                int steps = 10;
                double difference = (double) differenceY / steps;
                for (int index = 1; index <= steps; index++) {
                    imageY = (int) Math.round(difference * index + originalY);
                    update();
                    sleep(120L);
                }

                if (finalY == 0) {
                    imageY = 0;
                    update();
                } else {
                    imageY = finalY;
                }
            }

            private void update() {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        SlidingPanel.this.repaint();
                    }
                });
            }

            private void sleep(long duration) {
                try {
                    Thread.sleep(duration);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    public class Animation implements Runnable {
        
        @Override
        public void run() {
            while (true) {
                update("3");
                sleep(2000L);
                update("8");
                sleep(2000L);
            }
        }
        
        private void update(final String value) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    secondPanel.updatePanelValue(value);
                }
            });
        }

        private void sleep(long duration) {
            try {
                Thread.sleep(duration);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
    }

}

Upvotes: 6

Related Questions