Search code examples
javamultithreadingswinganimationrunnable

(Java Swing) My animating threads are not running parallely


What I am trying to do in this snippet of code is moving (animating) to images at the same time. However, only one image moves, and the other one just stays still. While I checked on this using print commands I found that the first thread was the only thread functioning most of the time while the second one created in the for loop functioned for maybe only a fraction of that time. I would really appreciate help on how to approach this problem and make both threads function parallelly.

private static void createPan() {
    for(int i = 0; i < listSize; i++) {
        //System.out.println("="+i);

        ImageList.add(new JLabel(images.getImage()));
        ImageList.get(i).setBounds(0,0,10,10);

        List.add(new Motion(x,y));
        thrdList.add(new Thread(new threadFunc(i)));
        //System.out.println(threadList.size());

        dispPane.add(ImageList.get(i));
        thrdList.get(i).start();
    }
}

private static class threadFunc implements Runnable {
    private static int indexNo;
    private static Timer t = new Timer(10, new AnimationListener(indexNo));

    public threadFunc(int index) {
        indexNo = index;
    }

    @Override
    public void run() {
        //System.out.println("-"+indexNo);
        setLocation(indexNo);
        System.out.println("end");
    }

    private static void setLocation(int indexNo) {
        // System.out.println("+"+indexNo);
        //System.out.println(c + "," + d);

        //System.out.println("+"+indexNo);
        ImageList.get(indexNo).setBounds(List.get(indexNo).getX(), List.get(indexNo).getY(), 10, 10);
        t.start();
    }

    private static class AnimationListener implements ActionListener {
        private static int indexNo;

        public AnimationListener(int index) {
            indexNo = index;
        }

        public void actionPerformed(ActionEvent e) {
            //System.out.println(indexNo);
            //System.out.println("-"+indexNo);
            List.get(indexNo).setX(List.get(indexNo).getX()+List.get(indexNo).getVelocityX());
            List.get(indexNo).setY(List.get(indexNo).getY()+List.get(indexNo).getVelocityY());
            setLocation(indexNo);
        }
    }
}

Solution

  • private static int indexNo;
    private static Timer t = new Timer(10, new AnimationListener(indexNo));
    
    public threadFunc(int index) {
        indexNo = index;
    }
    

    and

    private static class AnimationListener implements ActionListener {
        private static int indexNo;
    
        public AnimationListener(int index) {
            indexNo = index;
        }
    

    Don't use static variables.

    A static variable means it is shared by all instances of the class. So when you create the second instance of the same class the value of the variable is reset to the value of the last parameter. So you only get animation on a single object.

    However, I would also agree with the suggestion to use a single Timer. In this design you keep an ArrayList of objects you want to animate and then iterate through the ArrayList to reset the location of each object.

    See: get width and height of JPanel outside of the class for a working example. The example can handle hundreds of moving objects. It would not be practical to have hundreds of individual Timers animating each object separately.