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

¿Bucle While no funciona?

Buenas tardes compañeros, estoy intentando hacer un contador pero por alguna razón me da null...

package AutoClick;

import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JLabel;
import java.awt.Point;

@SuppressWarnings("serial")
public class TiempoSleep extends JFrame {
    AutoClick AC = new AutoClick();
    private JPanel contentPane;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    TiempoSleep frame = new TiempoSleep();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public TiempoSleep() {
        setLocation(new Point(200, 200));
        setLocationRelativeTo(null);
        setResizable(false);
        byte tiempo = 5;

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 212, 164);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(null);

        JLabel Sleep = new JLabel();
        Sleep.setFocusable(false);
        Sleep.setBounds(58, 11, 81, 54);
        contentPane.add(Sleep);

        JLabel lblPosicioneElPuntero = new JLabel("Posicione el puntero de su rat\u00F3n");
        lblPosicioneElPuntero.setBounds(10, 76, 191, 14);
        contentPane.add(lblPosicioneElPuntero);
        String sleepTime = Integer.toString(tiempo);
        while (tiempo > 0){
            tiempo-=1;
            Sleep.setText(sleepTime);
            if (tiempo == 0){
                System.out.println("Time!");
                /*try {
                    AC.Timer3();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }*/
            }
        }
    }
}

Por alguna razón, no se actualiza nunca el JLabel con el resutado del while...pero el caso es que llega al Time! que le tengo puesto en imprimir pantalla...

0voto

Yesod comentado

He dado con el error, pero no se como "solucionarlo", el problema que solo se muestra el resultado final en el JTextField, no todo el bucle como pretendo, es decir, que en el JTextField se muestre: 5,4,3,2,1,0...

2 Respuestas

2votos

Leonardo-Tadei Puntos227010

Hola,

para mostrar los valores acumulados, usá una variable string para ir concatenando el resultado del bucle en cada iteración, y luego mostrá el valor de esta variable.

Cada asignación del tiempo al JTextField te pondrá ese valor, no la acumulación de los resultados.

Esto mostrará los resultados todos juntos al final. Si querés ver los resultados a medida que el bucle se ejecuta, tenés que refrescar el componente luego de la asignación.

Saludos!

0voto

Yesod comentado

Realmente creo que si se lo paso, he estado revisando el código porque me hice un lío.

package AutoClick;

import java.awt.EventQueue;
import java.awt.Font;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;

import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.Timer;

@SuppressWarnings("serial")
public class TiempoSleep extends JFrame {
    AutoClick AC = new AutoClick();
    private JLabel PosicioneElPuntero;
    private JTextField Sleep;
    public int segundos = 5;
    String tiempo;

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    TiempoSleep frame = new TiempoSleep();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public TiempoSleep() throws InterruptedException {
        initcomponents();
        CountDown.start();
    }

    public void initcomponents() throws InterruptedException {
        // Propiedades del JFrame
        setLocation(new Point(200, 200));
        setLocationRelativeTo(null);
        setResizable(false);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 212, 164);
        getContentPane().setLayout(null);

        Sleep = new JTextField();
        Sleep.setEditable(false);
        Sleep.setEnabled(false);
        Sleep.setFocusable(false);
        Sleep.setBorder(null);
        Sleep.setFont(new Font("Tahoma", Font.BOLD, 30));
        Sleep.setBounds(84, 11, 112, 54);
        getContentPane().add(Sleep);

        PosicioneElPuntero = new JLabel("Posicione el puntero de su rat\u00F3n");
        PosicioneElPuntero.setBounds(10, 76, 191, 14);
        getContentPane().add(PosicioneElPuntero);
    }
    // Declaramos un timer que nos actualice el JTextField cada segundo
    Timer CountDown = new Timer(1000, new ActionListener() {
        // Declaramos el método para la cuenta atrás
        public void actionPerformed(ActionEvent e) {
            try {
                // Tiempo para crónometro
                tiempo = Integer.toString(cronometro.SleepTime(segundos));
                Sleep.setText(tiempo);
                if (cronometro.SleepTime(segundos)==0){
                    System.out.println("Tiempo");
                    CountDown.stop();
                }
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }
    });
}

La variable segundos, la tengo inicializada en 5, y se la paso cuando hago: tiempo = Integer.toString(cronometro.SleepTime(segundos)); que a su vez (creo), que transformo en String para poder mostrarlo en pantalla...

La otra parte realmente (creo), que, cuando yo le paso el valor de segundos y lo guardo en secaux, ya se debería quedar guardada en esa variable, que es la que uso para hacer el contador, ¿no?

Creo que puedes verme que me estoy liando bastante, debería ser mas sencillo...y me estoy haciendo un lío demasiado gordo.

0voto

Leonardo-Tadei comentado

Hola yesod,

ese es justamente el error de concepto que te estaba indicando!

Estás inicializando segundos = 5 y llamás a tu clase con tiempo = Integer.toString(cronometro.SleepTime(segundos));

Tu implementación de SleepTime() pone a la variable de control afuera del método, por lo que si no volvés a asignar a la variable segundos el valor devuelto por SleepTime() nunca va a recibir un valor distinto de 5!!! El atributo público segundos nunca toma un nuevo valor.

Tenés que hacer algo como:

...
this.segundos = cronometro.SleepTime(this.segundos);
tiempo = Integer.toString(this.segundos);
...

o alternativamente usar this.segundos dentro de SleepTime() para que le vaya cambiando el valor.

0voto

Yesod comentado

Vale, entonces, ahora tengo esto:

package AutoClick;

import java.awt.EventQueue;
import java.awt.Font;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;

import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.Timer;

@SuppressWarnings("serial")
public class TiempoSleep extends JFrame {
    AutoClick AC = new AutoClick();
    private JLabel PosicioneElPuntero;
    private JTextField Sleep;
    public int segundos = 5;
    String tiempo;

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    TiempoSleep frame = new TiempoSleep();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public TiempoSleep() throws InterruptedException {
        initcomponents();
        CountDown.start();
    }

    public void initcomponents() throws InterruptedException {
        // Propiedades del JFrame
        setLocation(new Point(200, 200));
        setLocationRelativeTo(null);
        setResizable(false);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 212, 164);
        getContentPane().setLayout(null);

        Sleep = new JTextField();
        Sleep.setEditable(false);
        Sleep.setEnabled(false);
        Sleep.setFocusable(false);
        Sleep.setBorder(null);
        Sleep.setFont(new Font("Tahoma", Font.BOLD, 30));
        Sleep.setBounds(84, 11, 112, 54);
        getContentPane().add(Sleep);

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

    public TiempoSleep(int segundos) throws InterruptedException {
        this.segundos = cronometro.SleepTime(this.segundos);
        tiempo = Integer.toString(this.segundos);
    }

    // Declaramos un timer que nos actualice el JTextField cada segundo
    Timer CountDown = new Timer(1000, new ActionListener() {
        // Declaramos el método para la cuenta atrás
        public void actionPerformed(ActionEvent e) {
            // Tiempo para crónometro
            try {
                // Paso el parámetro segundos al método "SleepTime" dentro de la clase "Cronómetro"
                // Luego lo paso a String para poder utilizarlo en el JTextField
                tiempo = Integer.toString(cronometro.SleepTime(segundos));
                Sleep.setText(tiempo);
                if (cronometro.SleepTime(segundos)==0){
                    System.out.println("Tiempo");
                    CountDown.stop();
                }
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }
    });
}

He implementado lo que me has dicho, pero sigue sin funcionar...también he probado a poner el valor de la variable sexaux como variable glogal y, el tema es que me sigue haciendo lo mismo, solo me saca el valor cuando llega a 0.

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package AutoClick;

/**
 *
 * @author Jorge Félix
 */
public class cronometro {
    static int secaux;
    public static String cronometroT(int segundos){
        int minutos=0;
        int horas=0;
        while (segundos>59){
            segundos-=60;
            minutos++;
            if (minutos>59){
                minutos-=60;
                horas++;
                }
        }
        return (horas+":"+minutos+":"+segundos);
    }
    public static int SleepTime(int segundos) throws InterruptedException{
        secaux = segundos;
        while (secaux>0){
            try {
                Thread.sleep(1000);
                secaux-=1;
            }finally{}
        }
        return secaux;
    }
}

Me han dicho que también puedo usar un switch o varios else if (algunos programadores amigos mios), pero no quiero hacerlo tan guarro...

La salida que me da es la siguiente:

TIempo después4
TIempo después3
TIempo después2
TIempo después1
TIempo después0
TIempo después4
TIempo después3
TIempo después2
TIempo después1
TIempo después0
Tiempo

Gracias por todo amigo :D

PD: Te agradecería si me puedes poner la solución directa a este problema :D


EDITO: Lo he planteado de otra forma y funciona, pero el caso es que no se como cerrar el hilo desde la clase principal, tengo hecho esto:

public void quitarAlways(boolean valor){
        this.setAlwaysOnTop(valor);
    }
public void Button_EjecutarActionPerformed(java.awt.event.ActionEvent evt) throws InterruptedException {
    quitarAlways(false);
    Hilo.start();
}

Con esto Inicio el Hilo para el contador, pero el problema es que... a la hora de hacer esto:

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

Si pongo, Hilo.close(); me sale como deprecated...y no tengo ni idea de como cerrar el Hilo entonces.

En el Hilo tengo esto:

package AutoClick;

import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JLabel;

@SuppressWarnings("serial")
public class Contador extends JFrame implements Runnable, ActionListener {
    AutoClick AC = new AutoClick();

    static int t=6;
    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);
    }

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

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

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

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

    }
}

¿Que se os ocurre?

0voto

Leonardo-Tadei comentado

"Gracias por todo amigo :D
PD: Te agradecería si me puedes poner la solución directa a este problema :D"

Sería un muy mal amigo si te escribiese la solución: un buen amigo te ayudaría a entender qué es lo que pasa para que aprendas a resolver estas cuestiones para siempre.

Si querés usar una solución que funciona sin entenderla, usá la de @xabe que está muy bien pensada, pero de una forma muy distinta a como estás queriendo solucionar este problema.

Saludos cordiales!

PD: te sugiero plantear la cuestión de cómo cerrar el thread en una pregunta aparte y de ser posible con un título más descriptivo que esta, ya que tu problema poco tenía que ver con un bucle while.

0voto

xabe comentado

Hola

Como bien dice @Leonardo-Tadei tendria que darte una explicación de mi código no solo dartelo y no explicar porque lo hecho así, Cuando arrancamos una aplicación de escritorio java tenemos un hilo principal (en realidad hay másde uno pero para nosotros es como si fuera uno) que es el encargado crear nuestra interfaz y de escuchar los eventos que se produce en ella y notificar esos eventos a nuestra clase java que implementan la interfaz ActionListener. En nuestro caso queremos mostrar un contador en nuestra aplicación, para realizar esta tarea, tenemos que hacer alguien cada cierto tiempo va cambiando el valor de nuestro contador. Ese alguien va ser un thread que cada segundo va actualizar el valor de nuestro contador. Los thread nos puede ayudar en un montón de casos pero tambien nos puede dar mucho dolor de cabeza (multi hilos, concurrencia, etc..).

Como vien sabe el método principal de thread es "run" hay donde tenemos que implemetar toda nuestra lógica.
En la mayoría de los casos queremos tener control sobre el hilo de cuando arrancar, parar y pausar. Para eso tengo una clase base de un thread que es la siguiente:

public class MyThread implements Runnable {

    private volatile boolean isRunning = true;
    private volatile boolean isPausing = false;

    public void run() {
        while (isRunning && !Thread.currentThread().isInterrupted() ) {
            if(!isPausing)
            {
                //Done
            }
        }
    }

    public void kill() {
        isRunning = false;
    }

    public void pause() {
        isPausing = true;
    }

    public void resume() {
        isPausing = false;
    }
}

Como ves tenemos los metodos para para y pausar el hilo. Para nuestro problema seria implemetar la logia de actulizar la etiqueta cada segundo seria algo parecido a esto.

public class ContadorThread implements Runnable {

    private volatile boolean isRunning = true;
    private int tiempo;
    private final JLabel etiqueta;

    public ContadorThread(JLabel etiqueta, int tiempo) {
        this.tiempo = tiempo;
        this.etiqueta = etiqueta;
    }

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

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

Ahora solo falta el codigo de nuestra clase principal donde va crear la clase ContadorThread y arrancar nuestro hilo.

@SuppressWarnings("serial")
public class Contador extends JFrame implements ActionListener {

    private JLabel PosicioneElPuntero;
    private JLabel c;
    private ContadorThread contadorThread;
    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        new Contador();
    }
    /**
     * 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);
        Thread thread = new Thread(contadorThread);
        thread.start();
    }

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

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

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

        contadorThread = new ContadorThread(c, 6);
    }

    public void actionPerformed(ActionEvent arg0) {

    }
}

A ver si esto ya soluciona tu problema, espero que tambien te haya quedado claro el tema de los hilos, la solución primera que dí se basa en la misma teoría, solo que utiliza una clase más preparada SwingWorker que tambien son hilos.

Saludos

2votos

xabe Puntos2180

Hola

A ver sí me enterado del problema lo que quieres es ir mostrado por pantalla una secuencia de valores, es decir un contrador?? Si es así a lo mejor este código te puede ayudar.

import java.awt.EventQueue;
import java.awt.Point;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;

@SuppressWarnings("serial")
public class TiempoSleep extends JFrame {
    //AutoClick AC = new AutoClick();
    private JPanel contentPane;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    TiempoSleep frame = new TiempoSleep();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public TiempoSleep() {
        setLocation(new Point(200, 200));
        setLocationRelativeTo(null);
        setResizable(false);
        final byte tiempo = 5;

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 212, 164);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(null);

        JLabel Sleep = new JLabel();
        Sleep.setFocusable(false);
        Sleep.setBounds(58, 11, 81, 54);
        contentPane.add(Sleep);

        JLabel lblPosicioneElPuntero = new JLabel("Posicione el puntero de su rat\u00F3n");
        lblPosicioneElPuntero.setBounds(10, 76, 191, 14);
        contentPane.add(lblPosicioneElPuntero);

        final TareaContador task = new TareaContador(tiempo, Sleep);        
        task.execute();

    }

    class TareaContador extends SwingWorker<Void, Integer> {
      private static final int DELAY = 1000;
      private int tiempo;
      private JLabel tiempoEtiqueta;

      public TareaContador(int tiempo, JLabel tiempoEtiqueta) {
        this.tiempo = tiempo;
        this.tiempoEtiqueta = tiempoEtiqueta;
      }

      @Override
      protected Void doInBackground() throws Exception {
        int i = 0;
        while (!isCancelled() && i < tiempo) {
          i++;
          publish( i);
          setProgress(i);
          Thread.sleep(DELAY);
        }
        return null;
      }   

      protected void process(List<Integer> values) {
        tiempoEtiqueta.setText(values.get(values.size() - 1).toString());
      }

      @Override
      protected void done() {
        if (isCancelled())
          System.out.println("Cancelado !");
        else
          System.out.println("Teminado !");
      }
    }
}

Lo que hago es utilizar la la clase SwingWorker que sirve para hacer tareas pesadas y dejar el hilo principal de swing libre, es decir que no sé quede bloqueado hasta que termine la tarea.

Saludos

0voto

Yesod comentado

Voy a mirarme tu código porque hay cosas que no entiendo a simple vista...

Gracias :D

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