entre Desarrolladores

Recibe ayuda de expertos

Registrate y pregunta

Es gratis y fácil

Recibe respuestas

Respuestas, votos y comentarios

Vota y selecciona respuestas

Recibe puntos, vota y da la solución

Pregunta

2votos

Cerrar un hilo desde otra clase

Buenas tardes compañeros, después de mi última consulta de cual tuve mucha ayuda :D Tengo un problema surgido desde ahí y abro otra consulta como me dijeron :)

El problema que tengo ahora es que, al crear un hilo para la Cuenta Atrás de 5 segundos, necesito que, al llegar al segundo 0 o 1, se pare el hilo asi mismo o lo pare la clase principal.

El código es el siguiente:

        Ejecutar = new JButton();
        Ejecutar.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                quitarAlways(false);
                C = new Contador();
                Hilo = new Thread(C);
                Hilo.start();
            }
        });
        Ejecutar.setText("Ejecutar");
        Ejecutar.setBounds(20, 230, 96, 23);
        contentPane.add(Ejecutar);

Esta es la clase donde tengo el contador, en el cual, tengo que conseguir que, al finalizar la cuentra atrás, se cierre el hilo y vuelva a estar la main en Alwaysontop

   package AutoClick2;

import java.awt.Dimension;

@SuppressWarnings("serial")
public class Contador extends JFrame implements Runnable, ActionListener {
    private boolean continuar = true;
    int t=5;
    private JLabel PosicioneElPuntero;
    private JLabel c;
    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        /*Contador c = new Contador();
        Thread Hilo = new Thread(c);
        Hilo.start();*/
    }
    /**
     * Create the frame.
     */
    public Contador() {
        this.objs();
        // Propiedades del JFrame
        this.setTitle("Contador");
        this.setLocation(new Point(580, 280));
        this.setSize(new Dimension(209,110));
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setResizable(false);
        this.getContentPane().setLayout(null);
    }

    public void objs() {
        c = new JLabel(""+t);
        c.setBounds(100,11,60,20);
        getContentPane().add(c);

        PosicioneElPuntero = new JLabel("Posicione el puntero de su ratón");
        PosicioneElPuntero.setBounds(10, 42, 191, 14);
        getContentPane().add(PosicioneElPuntero);
    }

    public void detenElHilo() throws InterruptedException{
        continuar=false;
        dispose();
    }

    public void run (){
        try {
            while (continuar==true){
                t-=1;
                c.setText(""+t);
                Thread.sleep(1000);
                if (t==0){
                    detenElHilo();
                }
            }
        }catch (Exception e){}
    }
    public void actionPerformed(ActionEvent arg0) {
    }
}

Y aqui, es donde llamo desde el Hilo para ejecutar los timer.

   public void Timer3() throws InterruptedException {
       try {
           timer2.start();
           quitarAlways(true);
       } finally {}
    }
   public void quitarAlways(boolean valor){
       this.setAlwaysOnTop(valor);
   }

El problema, es que después de acabar el Hilo de la cuenta atrás, no se pone la aplicación en Alwaysontop de nuevo como debería.

¿Que se os ocurre?

PD: He estado mirando para poder "destruir" el hilo y he encontrado información en este link: http://www.chuidiang.com/java/hilos/hilos_java.php No se si es información correcta, pero es lo que he encontrado, el problema aun parando el bucle, sigue siendo el mismo, si yo pongo desde el hilo a ejecutarse un metodo public que me ejecute un timer a la vez que ponga alwaysontop(true) de nuevo, no hace nada y no se el porqué...

PD 2: He estado mirando por la red de nuevo y bueno, el planteamiento que tenia no era del todo exacto, me explico, trataba de hacer que desde el hilo ejecutase una parte de la main de nuevo y tal...pero no es asi, ahora he hecho 2 hilos, uno para el main, para que no se "muera" y otro, para la cuenta atras. Lo que necesito ahora es saber como, cuando yo le dé al botón ejecutar, el hilo principal se quede a la espera con un wait(), y luego a través de un notify() se ponga en funcionamiento un timer de la clase principal, explico mejor: Cuando yo ejecuto el botón "Ejecutar" llamo a un JFrame que puse como Hilo y bien, éste hace una cuenta atrás de 5 segundos, cuando llegue a 0, necesito que la cuenta atrás se pare y, desaparezca esta ventana (esto ya lo consegui) y luego, ejecute un método que ponga Alwaysontop la aplicación principal de nuevo y, me ejecute un timer. Lo que pasa, que esto último no se como hacerlo. Es decir, no se como decirle a hilo (Cuando termine la cuenta atrás, ejecutes tal método de tu clase),

0voto

Leonardo-Tadei comentado

Vamos a ver si @xabe te puede dar una mano, que en este tema tiene mucha más experiencia que yo...

0voto

Yesod comentado

He estado viendo algunos métodos y he encontrado lo siguiente: La idea es dejar la aplicación main en espera de repuesta con un isRunning() para que cuando pare la ejecución del hilo, automaticamente llame al timer para que haga su ejecución.

El problema que tengo es que no se como se implementa de forma practica, la teoría de como funciona la sé, pero nada mas :)

Espero vuestra respuesta y mil gracias :)

2 Respuestas

0voto

Yesod Puntos3550

Ya di con la respuesta y al menos, la comprendo bien :D

Aqui la parte del botón:

    // Añadimos los botones de interacción que podrá usar el usuario
    Ejecutar = new JButton();
    Ejecutar.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            quitarAlways(false);
            /*Se lanza todo en un hilo para evitar bloquear el hilo de despacho de eventos de java (EDT).
            Si no se hace así, no se verá progresar el dialogo contador y se quedara bloqueada
            toda la interfaz de usuario hasta que termine el contador.*/

            // Creo un Hilo para proceder a crear dentro la instancia del contador
            // Todo debe estar en el método run() para forzar su ejecución
              Thread hiloQueEvitaBloquearEDT = new Thread() {
                  public void run() {
                      // Instancio e inicio Contador dentro de un Hilo para no congelar su ejecución
                      Contador dialogoContador = new Contador(AutoClick.this);
                      Thread hilo = new Thread(dialogoContador);
                      hilo.start();
                      // Espera a que termine el hilo contador
                      try {
                          hilo.join();
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      // Codigo que no se ejecuta hasta que se termine el contador
                      quitarAlways(true);
                      timer2.start();
                      //System.out.println("Sigue la ejecucion");
                  }
               };
               hiloQueEvitaBloquearEDT.start();
        }
    });
    Ejecutar.setText("Ejecutar");
    Ejecutar.setBounds(10, 230, 82, 23);
    contentPane.add(Ejecutar);

Y aqui la parte del contador:

package AutoClick2;

import java.awt.Frame;

public class Contador extends JDialog implements Runnable {
   private static final long serialVersionUID = 4898321869557863294L;
   private JLabel label = new JLabel();
   private int contador = 25;
   private final JLabel lblNewLabel = new JLabel("Posicione el puntero del rat\u00F3n");

   public Contador(Frame parent) {
      // Pasando el frame principal como parent, se evita que el dialogo
      // contador se vaya detras de la ventana principal.
      super(parent);
      getContentPane().setPreferredSize(new Dimension(180, 50));
      setVisible(true);
      this.setLocationRelativeTo(null);
      this.setResizable(false);
      this.setLocation(new Point(600, 300));
      getContentPane().setLayout(null);
      label.setFont(new Font("Tempus Sans ITC", Font.BOLD, 16));
      label.setBounds(65, 0, 64, 28);
      label.setText(Integer.toString(contador));
      getContentPane().add(label);
      lblNewLabel.setBounds(0, 25, 190, 14);
      getContentPane().add(lblNewLabel);
      pack();
   }

   public void run() {
      setVisible(true);

      // Bucle contador
      while (contador > 0) {
         try {
            Thread.sleep(1000);
            contador--;
            label.setText(Integer.toString(contador));
         } catch (InterruptedException e) {
            e.printStackTrace();
         }

      }

      setVisible(false);
   }
}

Solo daros las gracias a todos por la ayuda recibida :D

2votos

xabe Puntos2180

Hola

Aqui tiene un ejemplo muy sencillo de como pulsar un boton que se muestre un Jframe y que se muestre un label con un contador y cuando llega a 0 cierra la ventana.

Aquí tienes la clase que implementa la interfaz Runnable, la encargada de cada segundo actulizar la jlabel de Jframe.

public class ContadorThread implements Runnable {

    private volatile boolean isRunning = true;
    private int tiempo;
    private final ContadorFrame frame;

    public ContadorThread(ContadorFrame frame, int tiempo) {
        this.tiempo = tiempo;
        this.frame = frame;
    }

    public void run() {
        while (isRunning && !Thread.currentThread().isInterrupted() ) {
            try
            {
                tiempo -= 1;
                frame.getLabel().setText("" + tiempo);
                Thread.sleep(1000);
                if (tiempo==1)
                {
                    kill();
                    this.frame.finish();
                    this.frame.dispose();
                }
            }catch(Exception e){}
        }
        System.out.println("Termina el Hilo");
    }

    public void kill() {
        isRunning = false;
    }
}

Como ves tiene una referencia a la clase ContadorFrame que se pasa por el constructor y cuando termina llama al metodo finish de frame para avisar que ha terminado. Lo siguiente es ver el código del frame que tiene solo una label que es donde se muestras los valores.

@SuppressWarnings("serial")
public class ContadorFrame extends JFrame {

    private JLabel PosicioneElPuntero;
    private JLabel label;
    private ContadorThread contadorThread;
    private Main main;

    public ContadorFrame(Main main) {
        this.main = main;
        this.objs();       
        this.setTitle("Contador");
        this.setLocationRelativeTo(null);
        this.setSize(new Dimension(209,110));
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setResizable(false);
        Thread thread = new Thread(contadorThread);
        thread.start();
    }    

    public void objs() {
        getContentPane().setLayout(null);

        label = new JLabel("");
        label.setBounds(100,11,60,20);
        getContentPane().add(label);

        PosicioneElPuntero = new JLabel("Posicione el puntero de su rat\u00F3n");
        PosicioneElPuntero.setBounds(10, 42, 191, 14);
        getContentPane().add(PosicioneElPuntero);

        contadorThread = new ContadorThread(this, 4);
    }

    public JLabel getLabel() {
        return label;
    }

    public void finish(){
        main.finish();
    }
}

Como ves es una clase muy sencilla que solo tiene un label y cuando se crea la ventana instancia nuestro hilo para que empieze a pintar en nuestro label y tambien tiene una referencia a nuestro frame principal para avisarle cuando ha terminado nuestro contador. Lo siguiente es ver el código del frame principal que invoca nuestro frame cuando pulsa a un botón.

public class Main extends JFrame {
    private static final long serialVersionUID = 1L;
    private JLabel label;
    private JButton button;
    private Main instance;

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    new Main();

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public Main() {
        this.instance =  this;
        this.objs();       
        // Propiedades del JFrame
        this.setTitle("Contador");
        this.setLocation(new Point(580, 280));
        this.setSize(new Dimension(209,110));
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setResizable(false);

    }

    public void objs() {
        getContentPane().setLayout(null);

        label = new JLabel("Pulsa el boton para mostrar contador");
        label.setBounds(100,11,60,20);
        getContentPane().add(label);

        button = new JButton();
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                new ContadorFrame(instance);
            }
        });
        button.setText("Ejecutar");
        button.setBounds(10, 42, 191, 14);
        getContentPane().add(button);
    }

    public void finish(){
        System.out.println("Se ha terminado el contador");
    }
}

Espero que esto te ayude.

0voto

Yesod comentado

Vale, entiendo como va, pero no se como implementarlo en lo que yo tengo:

Tengo la MAIN, con "implement Runnable" para hacerlo hilo y luego, tengo este código para que se pare mientras el otro hilo esta en ejecución.

// Añadimos los botones de interacción que podrá usar el usuario
        Ejecutar = new JButton();
        Ejecutar.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                quitarAlways(false);
                System.out.println("Running");
                // Instancio la clase "Contador" como nuevo hilo para controlar su funcionamiento
                C = new Contador() {
                    private static final long serialVersionUID = -1975397236546297348L;
                    public void run() {
                        try {
                            // Mientras "Contador" esté funcionando, esta clase esta a la espera de que termine
                            while (C.isRunning()){
                                System.out.println("dentro");
                            }
                            timer2.start();
                        } catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                };
                Hilo = new Thread(C);
                Hilo.start();
            }

En el otro hilo tengo esto:

package AutoClick2;

import java.awt.Dimension;

@SuppressWarnings("serial")
public class Contador extends JFrame implements Runnable, ActionListener {
    private boolean continuar = true;
    //public boolean  mRun=true;
    int t=5;
    private JLabel PosicioneElPuntero;
    private JLabel c;
    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        /*Contador c = new Contador();
        Thread Hilo = new Thread(c);
        Hilo.start();*/
    }
    /**
     * Create the frame.
     */
    public Contador() {
        this.objs();
        // Propiedades del JFrame
        this.setTitle("Contador");
        this.setLocation(new Point(580, 280));
        this.setSize(new Dimension(209,110));
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setResizable(false);
        this.getContentPane().setLayout(null);
    }

    public void objs() {
        c = new JLabel(""+t);
        c.setBounds(100,11,60,20);
        getContentPane().add(c);

        PosicioneElPuntero = new JLabel("Posicione el puntero de su ratón");
        PosicioneElPuntero.setBounds(10, 42, 191, 14);
        getContentPane().add(PosicioneElPuntero);
    }

    public void detenElHilo() throws InterruptedException{
        continuar=false;
        //mRun = false;
        dispose();
    }

    /*public boolean isRunning(){
        return mRun;
    }*/
    public void run (){
        try {
            while (continuar==true){
                t-=1;
                c.setText(""+t);
                Thread.sleep(1000);
                if (t==0){
                    detenElHilo();
                }
            }
        }catch (Exception e){}
    }
    public void actionPerformed(ActionEvent arg0) {
    }
}

Entonces, con este código, realmente no se como implementar lo que me pusiste :(

0voto

xabe comentado

Hola

Los cambios que tienes que hacer son los siguientes:

La clase Contador tienes que tener una referencia al a la clase Main para invocar a una método para decir que ya ha terminado el contador aqui tienes el código que he modificado, tienes que poner el nombre de la clase Main a la variable y pasarlo por el constructor de Contador

@SuppressWarnings("serial")
public class Contador extends JFrame implements Runnable, ActionListener {
    private boolean continuar = true;
    int t=5;
    private JLabel PosicioneElPuntero;
    private JLabel c;
    private Main frame;

    /**
     * Create the frame.
     */
    public Contador(Main frame) {
        this.objs();
        this.frame = frame;
        // Propiedades del JFrame
        this.setTitle("Contador");
        this.setLocation(new Point(580, 280));
        this.setSize(new Dimension(209,110));
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setResizable(false);
        this.getContentPane().setLayout(null);
    }

    public void objs() {
        c = new JLabel();
        c.setBounds(100,11,60,20);
        getContentPane().add(c);

        PosicioneElPuntero = new JLabel("Posicione el puntero de su ratón");
        PosicioneElPuntero.setBounds(10, 42, 191, 14);
        getContentPane().add(PosicioneElPuntero);
    }

    public void detenElHilo(){
        continuar=false;
    }

    public void run (){
        try {
            while (continuar){
                t-=1;
                c.setText(""+t);
                Thread.sleep(1000);
                if (t==0){
                    detenElHilo();
                }
            }
            this.frame.terminado();
            this.dispose();
        }catch (Exception e){}
    }

    public void actionPerformed(ActionEvent arg0) {
    }
}

Como ves en el método run al final hay una llamada a un método terminado() que tienes que implementar en la clase Main y hay pones todo el código que quieras que haga cuando termina el Contador.

Aqui tienes el código para invocar desde Main a la clase Contador

Ejecutar.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                quitarAlways(false);
                System.out.println("Running");
                // Instancio la clase "Contador" como nuevo hilo para controlar su funcionamiento
                Contador C = new Contador(this) ;
                Thread Hilo = new Thread(C);
                Hilo.start();
            }

        }

Que no sé te olvide implementar el método finalizar para la clase Main, sí tienes alguna duda preguntamente, encantado de resolver tus dudas.

Saludos

Editado: movido a comentario de la respuesta original, para poder seguir el hilo de la conversación.

0voto

Yesod comentado

Veo un problema en la clase main, yo le tengo implementado un isRunning para comprobar cuanto tiempo esta en funcionamiento.
Mientras lo tengo asi:

    // Añadimos los botones de interacción que podrá usar el usuario
    Ejecutar = new JButton();
    Ejecutar.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            quitarAlways(false);
            System.out.println("Running");
            // Instancio la clase "Contador" como nuevo hilo para controlar su funcionamiento
             C = new Contador();
             HiloC = new Thread(C) {
                public void run() {
                    try {
                        // Mientras "Contador" esté funcionando, esta clase esta a la espera de que termine
                        while (C.isRunning()){
                            System.out.println("dentro");
                        }
                        timer2.start();
                    } catch (Exception e){
                        e.printStackTrace();
                    }
                }
            };
            HiloC = new Thread(C);
            HiloC.start();
        }
    });
    Ejecutar.setText("Ejecutar");
    Ejecutar.setBounds(10, 230, 82, 23);
    contentPane.add(Ejecutar);

El contador funciona, ahora en cuanto lo cambio a:

// Añadimos los botones de interacción que podrá usar el usuario
        Ejecutar = new JButton();
        Ejecutar.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                quitarAlways(false);
                System.out.println("Running");
                // Instancio la clase "Contador" como nuevo hilo para controlar su funcionamiento
                Contador C = new Contador();
                HiloC = new Thread(C) {
                    public void run() {
                        try {
                            HiloC.start();
                            // Mientras "Contador" esté funcionando, esta clase esta a la espera de que termine
                            while (HiloC.isAlive()){
                                System.out.println("vivo");
                            }
                            timer2.start();
                        } catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                };
            }
        });
        Ejecutar.setText("Ejecutar");
        Ejecutar.setBounds(10, 230, 82, 23);
        contentPane.add(Ejecutar);

El contador deja de funcionar...si alguien me lo puede resolver se lo agradece

package AutoClick2;

import java.awt.Dimension;

@SuppressWarnings("serial")
public class Contador extends JFrame implements Runnable, ActionListener {
    private boolean continuar = true;
    private volatile boolean  mRun=true;
    int t=5;
    private JLabel PosicioneElPuntero;
    private JLabel c;
    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        /*Contador c = new Contador();
        Thread Hilo = new Thread(c);
        Hilo.start();*/
    }
    /**
     * Create the frame.
     */
    public Contador() {
        this.objs();
        // Propiedades del JFrame
        this.setTitle("Contador");
        this.setLocation(new Point(580, 280));
        this.setSize(new Dimension(209,110));
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setResizable(false);
        this.getContentPane().setLayout(null);
    }

    public void objs() {
        c = new JLabel(""+t);
        c.setBounds(100,11,60,20);
        getContentPane().add(c);

        PosicioneElPuntero = new JLabel("Posicione el puntero de su ratón");
        PosicioneElPuntero.setBounds(10, 42, 191, 14);
        getContentPane().add(PosicioneElPuntero);
    }

    public void detenElHilo() throws InterruptedException{
        continuar=false;
        mRun = false;
        dispose();
    }

    public boolean isRunning(){
        return mRun;
    }

    public void run (){
        try {
            while (continuar==true){
                t-=1;
                c.setText(""+t);
                Thread.sleep(1000);
                if (t==0){
                    detenElHilo();
                }
            }
        }catch (Exception e){}
    }
    public void actionPerformed(ActionEvent arg0) {
    }
}

Me esta volviendo loco el tema este XDDD

Por favor, accede o regístrate para responder a esta pregunta.

Otras Preguntas y Respuestas


...

Bienvenido a entre Desarrolladores, donde puedes realizar preguntas y recibir respuestas de otros miembros de la comunidad.

Conecta