Control animation speed using the JSlider component

1

Well, I'm developing a project that simulates the controlled environment of train tracks, where I have 3 trains running clockwise, where the three pass through the same place in certain sections. I'm having trouble implementing the train speed dynamically using the JSlider component. I was able to create the 3 components, but I still could not associate them with my trains.

Follow the code:

public class Trens {

private static final double QUADROS_POR_SEGUNDO = 20.0;

public static void preparar() {
    JFrame t = new JFrame();
    t.setLayout(null);
    t.setSize(1200, 900);
    t.setTitle("Semáforo");
    t.setLocationRelativeTo(null); 
    t.setResizable(false);
    t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Trilho t1 = new Trilho(300, 100, 300, 170);
    Trilho t2 = new Trilho(600, 100, 300, 170);
    Trilho t3 = new Trilho(450, 270, 300, 170);
    Jslider slider = new Jslider(30, 150, 300, 170);
    Jslider slider2 = new Jslider(900, 150, 300, 170);
    Jslider slider3 = new Jslider(150, 330, 300, 170);

    Trem a = new Trem(t1, Color.BLUE, 350, 100, 100.0);
    Trem b = new Trem(t2, Color.GREEN, 650, 100, 100.0);
    Trem c = new Trem(t3, Color.RED, 450, 335, 100.0);
    t.add(a);
    t.add(b);
    t.add(c);
    t.add(t1);
    t.add(t2);
    t.add(t3);
    t.add(slider);
    t.add(slider2);
    t.add(slider3);
    Runnable moverTudo = () -> {
        EventQueue.invokeLater(() -> {
            a.mover(1 / QUADROS_POR_SEGUNDO);
            b.mover(1 / QUADROS_POR_SEGUNDO);
            c.mover(1 / QUADROS_POR_SEGUNDO);
        });
    };
    Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(moverTudo, 0, (int) (1000 / QUADROS_POR_SEGUNDO), TimeUnit.MILLISECONDS);
    t.setVisible(true);
}

public static void main(String[] args) {
    EventQueue.invokeLater(Trens::preparar);
}

public static class Trilho extends JComponent {
    public Trilho(int x, int y, int width, int height) {
        this.setBounds(x, y, width, height);
        this.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    }
}

public static class Trem extends JComponent {
    private Color cor;
    private Trilho trilho;
    private int x;
    private int y;
    private double velocidade; // pixels por segundo
    private double restante; // Frações de pixels que faltou andar.

    public Trem(Trilho trilho, Color cor, int x, int y, double velocidade) {
        this.trilho = trilho;
        this.cor = cor;
        this.x = x;
        this.y = y;
        this.velocidade = velocidade;
        this.setBounds(x - 5, y - 5, 10, 10);

    }

    @Override
    public void paintComponent(Graphics g) {
        g.setColor(cor);
        g.fillRect(0, 0, getWidth(), getHeight());
    }

    public void mover(double deltaT) {
        if (velocidade == 0) return;
        boolean sentidoHorario = velocidade > 0;
        double distancia = Math.abs(restante + velocidade * deltaT);
        int tLeft = trilho.getX();
        int tTop = trilho.getY();
        int tRight = tLeft + trilho.getWidth();
        int tBottom = tTop + trilho.getHeight();

        for (int i = 0; i < (int) distancia; i++) {
            // Se deve ir à esquerda:
            if (x > tLeft && y == (sentidoHorario ? tBottom : tTop)) {
                x--;
            // Se deve ir à direita:
            } else if (x < tRight && y == (sentidoHorario ? tTop : tBottom)) {
                x++;
            // Se deve ir para cima:
            } else if (y > tTop && x == (sentidoHorario ? tLeft : tRight)) {
                y--;
            // Se deve ir para baixo:
            } else if (y < tBottom && x == (sentidoHorario ? tRight : tLeft)) {
                y++;
            // Se não for nenhum dos anteriores, o trem está descarrilhado. Coloca de novo no trilho.
            } else {
                x = tLeft;
                y = tTop;
            }
        }
        restante = distancia % 1;
        setLocation(x - 5, y - 5);
    }
}

public static class Jslider extends JPanel{

    private Jslider(int x, int y, int width, int height){
        this.setBounds(x, y, width, height);
        JSlider control = new JSlider(0,100,25);
        control.setMajorTickSpacing(50);
        control.setMinorTickSpacing(10);
        control.setPaintTicks(true);
        control.setFont(new Font("Serfi", Font.ITALIC, 12));
        control.setPaintLabels(true);
        control.setSnapToTicks(true);
        add(control);

    }
}

public class EventoSlider implements ChangeListener{


    @Override
    public void stateChanged(ChangeEvent e) {
         JSlider source = (JSlider) e.getSource();
         int fps = (int) source.getValue();
        System.out.println(fps);
    }

}
}
    
asked by anonymous 04.08.2017 / 19:21

1 answer

2

I managed, until it was simple:

package trens;

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;

public class Trens {

    private static final double QUADROS_POR_SEGUNDO = 20.0;

    public static void preparar() {
        JFrame t = new JFrame();
        t.setLayout(null);
        t.setSize(1200, 900);
        t.setTitle("Semáforo");
        t.setLocationRelativeTo(null); 
        t.setResizable(false);
        t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Trilho t1 = new Trilho(300, 100, 300, 170);
        Trilho t2 = new Trilho(600, 100, 300, 170);
        Trilho t3 = new Trilho(450, 270, 300, 170);

        Trem a = new Trem(t1, Color.BLUE, 350, 100, 100.0);
        Trem b = new Trem(t2, Color.GREEN, 650, 100, 100.0);
        Trem c = new Trem(t3, Color.RED, 450, 335, 100.0);
        VelocityControl slider = new VelocityControl(a, 30, 150, 300, 170);
        VelocityControl slider2 = new VelocityControl(b, 900, 150, 300, 170);
        VelocityControl slider3 = new VelocityControl(c, 150, 330, 300, 170);
        t.add(a);
        t.add(b);
        t.add(c);
        t.add(t1);
        t.add(t2);
        t.add(t3);
        t.add(slider);
        t.add(slider2);
        t.add(slider3);
        Runnable moverTudo = () -> {
            EventQueue.invokeLater(() -> {
                a.mover(1 / QUADROS_POR_SEGUNDO);
                b.mover(1 / QUADROS_POR_SEGUNDO);
                c.mover(1 / QUADROS_POR_SEGUNDO);
            });
        };
        Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(moverTudo, 0, (int) (1000 / QUADROS_POR_SEGUNDO), TimeUnit.MILLISECONDS);
        t.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(Trens::preparar);
    }

    public static class Trilho extends JComponent {
        public Trilho(int x, int y, int width, int height) {
            this.setBounds(x, y, width, height);
            this.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        }
    }

    public static class Trem extends JComponent {
        private Color cor;
        private Trilho trilho;
        private int x;
        private int y;
        private double velocidade; // pixels por segundo
        private double restante; // Frações de pixels que faltou andar.

        public Trem(Trilho trilho, Color cor, int x, int y, double velocidade) {
            this.trilho = trilho;
            this.cor = cor;
            this.x = x;
            this.y = y;
            this.velocidade = velocidade;
            this.setBounds(x - 5, y - 5, 10, 10);
        }

        @Override
        public void paintComponent(Graphics g) {
            g.setColor(cor);
            g.fillRect(0, 0, getWidth(), getHeight());
        }

        public void setVelocidade(double novaVelocidade) {
            this.velocidade = novaVelocidade;
        }

        public void mover(double deltaT) {
            if (velocidade == 0) return;
            boolean sentidoHorario = velocidade > 0;
            double distancia = Math.abs(restante + velocidade * deltaT);
            int tLeft = trilho.getX();
            int tTop = trilho.getY();
            int tRight = tLeft + trilho.getWidth();
            int tBottom = tTop + trilho.getHeight();

            for (int i = 0; i < (int) distancia; i++) {
                // Se deve ir à esquerda:
                if (x > tLeft && y == (sentidoHorario ? tBottom : tTop)) {
                    x--;
                // Se deve ir à direita:
                } else if (x < tRight && y == (sentidoHorario ? tTop : tBottom)) {
                    x++;
                // Se deve ir para cima:
                } else if (y > tTop && x == (sentidoHorario ? tLeft : tRight)) {
                    y--;
                // Se deve ir para baixo:
                } else if (y < tBottom && x == (sentidoHorario ? tRight : tLeft)) {
                    y++;
                // Se não for nenhum dos anteriores, o trem está descarrilhado. Coloca de novo no trilho.
                } else {
                    x = tLeft;
                    y = tTop;
                }
            }
            restante = distancia % 1;
            setLocation(x - 5, y - 5);
        }
    }

    public static class VelocityControl extends JPanel {
        private VelocityControl(Trem trem, int x, int y, int width, int height) {
            this.setBounds(x, y, width, height);
            JSlider control = new JSlider(0, 100, 25);
            control.setMajorTickSpacing(50);
            control.setMinorTickSpacing(10);
            control.setPaintTicks(true);
            control.setFont(new Font("Serif", Font.ITALIC, 12));
            control.setPaintLabels(true);
            control.setSnapToTicks(true);
            this.add(control);
            control.addChangeListener(e -> trem.setVelocidade(control.getValue()));
        }
    }
}

I changed the name of the class Jslider to VelocityControl so as not to confuse with the JSlider (note that one has a capital S and the other lowercase S).

The trick to make the chosen value reflect at speed is control.addChangeListener(e -> trem.setVelocidade(control.getValue())); with lambda syntax, this is very simple and clean.

To connect the trains to the controls, just pass the train as one more parameter to the VelocityControl constructor.

One final thing is that you used "Serfi" instead of "Serif" in the source name, a typo.

    
04.08.2017 / 22:31