2012-09-22 40 views
5

Así que estoy creando una aplicación básica que quiero tener un JLabel en la parte inferior de la pantalla que comienza en la esquina inferior izquierda y se mueve, estilo de animación, a la esquina inferior derecha en un tiempo establecido, y una imagen estática en el centro. Para hacer esto, creé un JFrame con un JPanel usando BorderLayout. Hay un JLabel con un ImageIcon agregado a BorderLayout.CENTER y un JPanel en BorderLayout.SOUTH. Mi código, mientras escrita apresuradamente y lejos de bonita, es:Java Animate JLabel

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.Timer; 
import javax.swing.BorderFactory; 

public class GameWindow extends JPanel{ 

private static JLabel mainWindow, arrowLabel, arrowBox; 
protected static JFrame frame; 
protected static JPanel arrows; 

public static int x = 600; 

public GameWindow(){ 
    mainWindow = new JLabel("Center"); 
    arrowLabel = new JLabel("Moving"); 
    arrows = new JPanel(); 
    arrows.setSize(600, 100); 
    arrows.setLayout(null); 
    arrowBox = new JLabel(""); 
    arrowBox.setBounds(0, 0, 150, 100); 
    arrowBox.setPreferredSize(new Dimension(150, 100)); 
    arrowBox.setBorder(BorderFactory.createLineBorder(Color.black)); 
    arrows.add(arrowBox); 
    this.setSize(600,600); 
    this.setLayout(new BorderLayout()); 
    this.add(mainWindow, BorderLayout.CENTER); 
    this.add(arrows, BorderLayout.SOUTH); 
} 

public static void main(String[] args) 
{ 
    GameWindow g = new GameWindow(); 
    frame = new JFrame("Sword Sword Revolution"); 
    frame.add(g); 
    frame.setSize(600,600); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.setVisible(true); 

    Timer t = new Timer(1000, new ActionListener(){ 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      arrows.add(arrowLabel); 
      arrowLabel.setBounds(x, 100, 100, 100); 
      x-=50; 
      arrows.repaint(); 
      frame.repaint(); 
     } 

    }); 
    t.start(); 
} 

}

El ImageIcon en el centro JLabel parece bien, y el JLabel vacío con un borde aparece en la parte inferior, pero no puede conseguir el segundo JLabel con la imagen de la flecha para aparecer en la pantalla. Eventualmente cambiaré a scheduleAtFixedRate para mover continuamente el JLabel, pero en este momento no puedo ni siquiera hacer que la imagen aparezca en la pantalla.

También entiendo que lo más probable es que no pueda usar FlowLayout para esto, ya que entiendo que no le permite establecer la ubicación de sus componentes. Intenté usar el diseño nulo, pero con el diseño nulo, el JLabel vacío con un borde no aparece. Apenas puedo distinguir la parte superior del borde en el borde inferior del marco, pero incluso con setLocation no puedo hacer que aparezca donde quiero.

Obviamente, mi proceso de pensamiento es defectuoso, por lo que cualquier ayuda sería apreciada.

Respuesta

15

Su uso del enhebrado es incorrecto para las aplicaciones Swing. No debería tratar de agregar o quitar componentes en un hilo de fondo, sino que debe usar un temporizador de oscilación para hacer esto en el hilo del evento Swing.

Además, ¿qué quiere decir por:

Quiero tener un JLabel desplazamiento en la parte inferior de la pantalla

Por favor, aclarar el efecto que está tratando de lograr.

También con respecto a,

También entiendo que lo más probable es que no sea capaz de usar FlowLayout para esto, ya que entiendo que no permite establecer la ubicación de sus componentes. Intenté usar el diseño nulo, pero con el diseño nulo, el JLabel vacío con un borde no aparece. Apenas puedo distinguir la parte superior del borde en el borde inferior del marco, pero incluso con setLocation no puedo hacer que aparezca donde quiero.

No, no utilice el diseño nulo para esta situación. Hay administradores de disposición mucho mejores que pueden ayudarlo a construir su aplicación de una manera más limpia e independiente de la plataforma.

Datos 3
Con respecto a:

Para aclarar, en la parte inferior de la pantalla quiero un JLabel en la esquina de la derecha, a continuación, en el temporizador de golpe, el JLabel se moverá gradualmente a la izquierda hasta que sale de la pantalla. Si pudiera hacer que setLocation funcione, la premisa básica sería tener una variable x establecida en 600, y luego cada segundo disminuir x por ejemplo 50 y luego volver a dibujar JLabel en la nueva ubicación en la pantalla. Animación básica

me gustaría crear un JPanel para la parte inferior de la pantalla a los efectos de la celebración de su bien JLabel o mostrar la imagen sin un JLabel anulando su método paintComponent(...). Si lo usa como un contenedor, entonces sí, su diseño debe ser nulo, pero el resto de la GUI no debe usar un diseño nulo. El Swing Timer simplemente cambiaría la ubicación de JLabel y luego llamaría al repaint() en su JPanel/contenedor. Si realiza la última ruta, dibujaría la imagen en el método paintComponent(...) de JPanel usando g.drawImage(myImage, x, y), y su temporizador cambiaría x y/o y llamaría al repaint() en el documento JPanel.

Además, es probable que no desee seguir agregando un JLabel en su temporizador, sino simplemente mover el JLabel que ya se muestra en la GUI.

Además, para evitar problemas de enfoque, no utilice un KeyListener para capturar la entrada de pulsaciones de teclas, sino más bien use Key Bindings. Google lo dirigirá a un gran tutorial sobre este constructo.

Editar 4
Por ejemplo:

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Font; 
import java.awt.FontMetrics; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.RenderingHints; 
import java.awt.event.*; 
import java.awt.image.BufferedImage; 
import java.io.IOException; 
import java.net.MalformedURLException; 
import java.net.URL; 
import java.util.EnumMap; 

import javax.imageio.ImageIO; 
import javax.swing.*; 

@SuppressWarnings("serial") 
public class AnimateExample extends JPanel { 
    public static final String DUKE_IMG_PATH = 
     "https://duke.kenai.com/iconSized/duke.gif"; 
    private static final int PREF_W = 800; 
    private static final int PREF_H = 800; 
    private static final int TIMER_DELAY = 20; 
    private static final String KEY_DOWN = "key down"; 
    private static final String KEY_RELEASE = "key release"; 
    public static final int TRANSLATE_SCALE = 3; 
    private static final String BACKGROUND_STRING = "Use Arrow Keys to Move Image"; 
    private static final Font BG_STRING_FONT = new Font(Font.SANS_SERIF, 
     Font.BOLD, 32); 
    private EnumMap<Direction, Boolean> dirMap = 
     new EnumMap<AnimateExample.Direction, Boolean>(Direction.class); 
    private BufferedImage image = null; 
    private int imgX = 0; 
    private int imgY = 0; 
    private int bgStringX; 
    private int bgStringY; 

    public AnimateExample() { 
     for (Direction dir : Direction.values()) { 
     dirMap.put(dir, Boolean.FALSE); 
     } 
     try { 
     URL imgUrl = new URL(DUKE_IMG_PATH); 
     image = ImageIO.read(imgUrl); 
     } catch (MalformedURLException e) { 
     e.printStackTrace(); 
     } catch (IOException e) { 
     e.printStackTrace(); 
     } 

     new Timer(TIMER_DELAY, new TimerListener()).start(); 

     // here we set up our key bindings 
     int condition = JComponent.WHEN_IN_FOCUSED_WINDOW; 
     InputMap inputMap = getInputMap(condition); 
     ActionMap actionMap = getActionMap(); 
     for (final Direction dir : Direction.values()) { 

     // for the key down key stroke 
     KeyStroke keyStroke = KeyStroke.getKeyStroke(dir.getKeyCode(), 0, 
       false); 
     inputMap.put(keyStroke, dir.name() + KEY_DOWN); 
     actionMap.put(dir.name() + KEY_DOWN, new AbstractAction() { 

      @Override 
      public void actionPerformed(ActionEvent arg0) { 
       dirMap.put(dir, true); 
      } 
     }); 

     // for the key release key stroke 
     keyStroke = KeyStroke.getKeyStroke(dir.getKeyCode(), 0, true); 
     inputMap.put(keyStroke, dir.name() + KEY_RELEASE); 
     actionMap.put(dir.name() + KEY_RELEASE, new AbstractAction() { 

      @Override 
      public void actionPerformed(ActionEvent arg0) { 
       dirMap.put(dir, false); 
      } 
     }); 
     } 

     FontMetrics fontMetrics = getFontMetrics(BG_STRING_FONT); 
     int w = fontMetrics.stringWidth(BACKGROUND_STRING); 
     int h = fontMetrics.getHeight(); 

     bgStringX = (PREF_W - w)/2; 
     bgStringY = (PREF_H - h)/2; 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(PREF_W, PREF_H); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     Graphics2D g2 = (Graphics2D) g; 
     g.setFont(BG_STRING_FONT); 
     g.setColor(Color.LIGHT_GRAY); 
     g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, 
      RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 
     g.drawString(BACKGROUND_STRING, bgStringX, bgStringY); 

     if (image != null) { 
     g.drawImage(image, imgX, imgY, this); 
     } 
    } 

    private class TimerListener implements ActionListener { 
     public void actionPerformed(java.awt.event.ActionEvent e) { 
     for (Direction dir : Direction.values()) { 
      if (dirMap.get(dir)) { 
       imgX += dir.getX() * TRANSLATE_SCALE; 
       imgY += dir.getY() * TRANSLATE_SCALE; 
      } 
     } 
     repaint(); 
     }; 
    } 

    enum Direction { 
     Up(KeyEvent.VK_UP, 0, -1), Down(KeyEvent.VK_DOWN, 0, 1), Left(
      KeyEvent.VK_LEFT, -1, 0), Right(KeyEvent.VK_RIGHT, 1, 0); 

     private int keyCode; 
     private int x; 
     private int y; 

     private Direction(int keyCode, int x, int y) { 
     this.keyCode = keyCode; 
     this.x = x; 
     this.y = y; 
     } 

     public int getKeyCode() { 
     return keyCode; 
     } 

     public int getX() { 
     return x; 
     } 

     public int getY() { 
     return y; 
     } 

    } 

    private static void createAndShowGui() { 
     AnimateExample mainPanel = new AnimateExample(); 

     JFrame frame = new JFrame("Animate Example"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(mainPanel); 
     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      createAndShowGui(); 
     } 
     }); 
    } 
} 

que creará esta interfaz gráfica de usuario:

enter image description here

+1

+1. Y establecer la ubicación mientras se usa un LayoutManager no tiene ningún efecto. Es el LayoutManager el que determina la ubicación – Robin

+0

En realidad tenía el Timer antes, pero alguien me dijo que era mejor usar ScheduledExecutorService.Volver a usar el temporizador Swing no es un problema, voy a editar la pregunta – awestover89

+0

Si aún no funciona, cree un programa simple compilable y ejecutable que demuestre su problema y use imágenes en línea disponibles para todos, un [sscce] (http://sscce.org). –

8

tres posibilidades:

  • Puede usar una biblioteca como SlidingLayout para crear dicha transición con muy pocas líneas de código. No podrás modificar la animación, pero tu vida será más fácil.

  • Puede usar un motor de animación como Universal Tween Engine para configurar todo a mano y ajustar la animación tanto como desee (la primera lib usa esta debajo del capó). El uso de tales motores, puede animar lo que quiere: posiciones, colores, tamaño de fuente, ...

  • Puede codificar todo a mano y abrazar el infierno que es el mundo de la animación :)

al final, usted será capaz de crear rápidamente animaciones como estos (que es una herramienta Actualmente estoy trabajando en, utilizado para configurar Eclipse para proyectos dev androide utilizando el marco de juego libgdx):
enter image description hereenter image description here

I hizo estas bibliotecas para aliviar el dolor que es la animación de la interfaz de usuario (me encanta el diseño de la interfaz de usuario: p). Los liberé de código abierto (de uso gratuito, licencia de apache-2), con la esperanza de que también puedan ayudar a algunas personas.

Si necesita ayuda, hay un foro de ayuda dedicado para cada biblioteca.

+1

wow. bastante resbaladizo! 1+ –

+3

Voy a analizar eso. Cuando era estudiante odiaba la idea de usar bibliotecas externas. Algo relacionado con el orgullo y el deseo de decir que lo hice todo yo mismo. Sin embargo, aprendí a abrazar las bibliotecas existentes en mi carrera profesional, sin reinventar la rueda. Te lo haré saber, gracias – awestover89

+0

Has hecho mi día. – Rempelos

1

Muy simple, mira esto:

javax.swing.JLabel lb = new javax.swing.JLabel(); 
Image image = Toolkit.getDefaultToolkit().createImage("Your animated GIF"); 
ImageIcon xIcon = new ImageIcon(image); 
xIcon.setImageObserver(this); 
lb.setIcon(xIcon);