style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">

Incremento exponencial en lugar de lineal

Buenas, amigos de Java; mi duda es la que sigue:

Escribí un programa que dibuja un globito (un círculo sencillo en un panel con Graphics) y le coloqué un temporizador para que subiera diez pixeles cada segundo.

El problema es que, el primer segundo sube como debe, 10 px, el segundo sube 20px, esto lo pude comprobar colocando un JTextField que muestra el valor de Y cada vez que se vuelve a dibujar el globo y va incrementando el valor que resta a la posición Y de mi dibujo, lo correcto para este programa es que el primer dibujo se realizara en 235, el segundo en 225, el tercero en 215 y así, anexo el código para que lo examinen y me puedan decir porqué está funcionando de esa manera incorrecta, gracias de antemano a todos.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class GlobitoVolador extends JFrame implements ActionListener{
   
  private int posicionY = 245;
  private JPanel panel;
  private JButton boton;
  private Timer temporizador;
  private JTextField valorY;
 
  public static void main (String args[]){
      GlobitoVolador demo = new GlobitoVolador();
      demo.setTitle("Globito que vuela");
      demo.setSize(400, 400);
      demo.creaGUI();
      demo.setVisible(true);
 
  }//Fin de main
   
  private void creaGUI(){
      setDefaultCloseOperation(EXIT_ON_CLOSE);
      Container ventana = getContentPane();
      ventana.setLayout(new FlowLayout());
     
      panel = new JPanel();
      panel.setBackground(Color.white);
      panel.setPreferredSize(new Dimension(300, 300));
      ventana.add(panel);
     
      boton = new JButton("Despegue");
      boton.addActionListener(this);
      ventana.add(boton);
           
      valorY = new JTextField(5);
      ventana.add(valorY);
     
  }//Fin de creaGUI
 
  public void actionPerformed(ActionEvent event){
                 
      Graphics papel = panel.getGraphics();
      papel.setColor(Color.white);
      papel.fillRect(0, 0, 300, 300);
 
      temporizador = new Timer(1000, this);
      temporizador.start();
     
      papel.setColor(Color.BLACK);
      papel.drawOval(120, posicionY, 50, 50);
      posicionY = posicionY - 10;
     
      valorY.setText(Integer.toString(posicionY));
     
  }//Fin de aP
   
   
}//Fin de la clase GlobitoVolador

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.

Podrías usar un wait

Hola, viendo tu programa creo que podrías hacer uso de un wait dentro del método actionPerformed, sería como temporizador.wait(1000); (encerrándolo en un bloque try-catch junto con todo lo demás para que se pinte el globo, abarcando desde Graphics papel...). Eso haría yo.

Lo intentaré

Ah, muchas gracias, voy a intentarlo y avisaré del resultado :D

Tal vez pudieras resolverlo de otra forma

Mira te dejo este código, aunque no se si te sirva, lo que hago es tener una clase que herede java.util.Observable y ahí realizo todo el trabajo.

Lo que logré es tener la vista en una clase, después al botón le implemente un actionlistener para que escuche el evento al ser pulsado y, cuando esto sucede, se ejecuta el timer y se pone en marcha todo lo demás.

Main

public class Principal {

    public static void main(String[] args) {
        VistaGlobo vista = new VistaGlobo();
        vista.arrancarVista();
    }

}

Vista

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class VistaGlobo {

    private JFrame framePrincipal;
    private JPanel pnlGlobo;
    private JButton btnDespegue;
    private JTextField txtValorY;

    public VistaGlobo() {

        framePrincipal = new JFrame();
        pnlGlobo = new JPanel();
        btnDespegue = new JButton();
        txtValorY = new JTextField();

        framePrincipal.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        framePrincipal.setLayout(new FlowLayout());
        pnlGlobo.setBackground(Color.WHITE);
        pnlGlobo.setPreferredSize(new Dimension(300, 300));
        btnDespegue.setText("Despegar");
        btnDespegue.setActionCommand("DESPEGAR");
        btnDespegue.addActionListener(new Controlador(this));
        txtValorY.setPreferredSize(new Dimension(100, 25));

        framePrincipal.add(pnlGlobo);
        framePrincipal.add(btnDespegue);
        framePrincipal.add(txtValorY);

    }

    public void arrancarVista() {
        getFramePrincipal().setTitle("Globo que vuela");
        getFramePrincipal().setSize(400, 400);
        getFramePrincipal().setLocationRelativeTo(null);
        getFramePrincipal().setResizable(false);
        getFramePrincipal().setVisible(true);
    }

    public JButton getBtnDespegue() {
        return btnDespegue;
    }

    public JFrame getFramePrincipal() {
        return framePrincipal;
    }

    public JPanel getPnlGlobo() {
        return pnlGlobo;
    }

    public JTextField getTxtValorY() {
        return txtValorY;
    }

    public void setTxtValorPosicion(int valorPosicionGlobo) {
        getTxtValorY().setText(String.valueOf(valorPosicionGlobo));
    }

}

Controlador

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

public class Controlador implements ActionListener {

    private VistaGlobo vistaGlobo;

    public Controlador(VistaGlobo vistaGlobo) {
        this.vistaGlobo = vistaGlobo;
    }

    @Override
    public void actionPerformed(ActionEvent evt) {
        if (evt.getActionCommand().equals("DESPEGAR")) {
            getVistaGlobo().getBtnDespegue().setEnabled(false);
            new TimerGlobo(getVistaGlobo());
        }
    }

    public VistaGlobo getVistaGlobo() {
        return vistaGlobo;
    }

}

Timer

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Observable;

import javax.swing.Timer;

public class TimerGlobo extends Observable {

    private VistaGlobo vistaGlobo;
    private Graphics graficoPanel;
    private Timer timer;
    private int posicionGlobo = 245;

    public TimerGlobo(VistaGlobo vistaGlobo) {
        this.vistaGlobo = vistaGlobo;

        timer = new Timer(1000, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent evt) {
                getVistaGlobo().setTxtValorPosicion(getPosicionGlobo());
                graficoPanel = getVistaGlobo().getPnlGlobo().getGraphics();
                graficoPanel.setColor(Color.WHITE);
                graficoPanel.fillRect(0, 0, 300, 300);
                graficoPanel.setColor(Color.BLACK);
                graficoPanel.drawOval(120, getPosicionGlobo(), 50, 50);
                setPosicionGlobo(getPosicionGlobo() - 10);

                if (getPosicionGlobo() < 0) {
                    getVistaGlobo().getBtnDespegue().setEnabled(true);
                    getVistaGlobo().getTxtValorY().setText("");
                    timer.stop();
                }
            }
        });
        timer.start();
    }

    public int getPosicionGlobo() {
        return posicionGlobo;
    }

    public VistaGlobo getVistaGlobo() {
        return vistaGlobo;
    }

    public void setPosicionGlobo(int posicionGlobo) {
        this.posicionGlobo = posicionGlobo;
    }

}

Saludos

Inicialízalo en la declaración...

Oye si todavía es oportuno, solo tienes que inicializarlo en la declaracion, en ves de hacerlo en el actionPerformed, de esta manera realiza el incremento lineal como lo quieres...

private Timer temporizador = new Timer(1000, this);

lo demás lo dejas igual...

Ya te respondió Arturo. Pero

Ya te respondió Arturo.

Pero ahí va otra explicación, si comentas la línea donde limpias el dibujo:

      //papel.fillRect(0, 0, 300, 300);

Te darás cuenta de que sí está haciendo el dibujo cada vez con y - 10, lo que pasa es que cada vez que lo haces, llamas al método actionPerformed(ActionEvent) que a su vez crea otro timer the hace lo mismo, el resultado es que cada vez es más rápido y solo puedes ver como se decrementa exponencialmente.

style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">