2012-09-22 14 views
5

Also ich eine grundlegende Anwendung erstellen, die ich eine JLabel am unteren Rand des Bildschirms, die in der linken unteren Ecke beginnt und bewegt, Animationsstil, in der rechten unteren Ecke in einer festgelegten Zeit, und möchte ein statisches Bild in der Mitte. Um dies zu tun, habe ich einen JFrame mit einem JPanel mit BorderLayout erstellt. Es gibt ein JLabel mit einem ImageIcon, das zu BorderLayout.CENTER und einem JPanel bei BorderLayout.SOUTH hinzugefügt wird. Mein Code, während hastig geschrieben und weit von hübsch, ist:Java animieren 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(); 
} 

}

Die ImageIcon im Zentrum JLabel fein erscheint, und die leere JLabel mit einer Grenze erscheint am unteren Rand, aber ich kann nicht bekommen das zweite JLabel mit dem Pfeilbild, das auf dem Bildschirm erscheint. Schließlich werde ich zu scheduleAtFixedRate wechseln, um das JLabel kontinuierlich zu bewegen, aber im Moment kann ich nicht einmal das Bild auf dem Bildschirm erscheinen.

Ich verstehe auch, dass ich wahrscheinlich nicht in der Lage sein wird, FlowLayout dafür zu verwenden, da ich weiß, dass es Ihnen nicht erlaubt, den Standort Ihrer Komponenten festzulegen. Ich habe versucht, Null-Layout zu verwenden, aber mit Null-Layout wird das leere JLabel mit einem Rahmen nicht angezeigt. Ich kann den oberen Rand des Randes am unteren Rand des Rahmens kaum ausmachen, aber selbst mit setLocation kann ich nicht erreichen, dass er dort erscheint, wo ich es möchte.

Offensichtlich ist mein Denkprozess fehlerhaft, so würde jede Hilfe geschätzt werden.

Antwort

15

Die Verwendung von Threading ist bei Swing-Anwendungen falsch. Sie sollten nicht versuchen, Komponenten in einem Hintergrund-Thread hinzuzufügen oder zu entfernen, sondern stattdessen einen Swing-Timer für den Swing-Ereignis-Thread verwenden.

Auch, was meinen Sie:

ich Sie versuchen zu erreichen, ein Scrollen JLabel am unteren Rand des Bildschirms

Bitte klären Sie die Wirkung haben soll.

Auch in Bezug auf,

Ich verstehe auch, dass ich höchstwahrscheinlich nicht in der Lage sein, dies zu verwenden Flowlayout für, wie ich es verstehe nicht zulässt, dass Sie die Position Ihrer Komponenten einzustellen. Ich habe versucht, Null-Layout zu verwenden, aber mit Null-Layout wird das leere JLabel mit einem Rahmen nicht angezeigt. Ich kann den oberen Rand des Randes am unteren Rand des Rahmens kaum ausmachen, aber selbst mit setLocation kann ich nicht erreichen, dass er dort erscheint, wo ich es möchte.

Nein, verwenden Sie für diese Situation kein Null-Layout. Es gibt viel bessere Layout-Manager, die Ihnen helfen können, Ihre Anwendung auf eine plattformunabhängigere Weise zu erstellen.

bearbeiten 3
In Bezug auf:

Um zu klären, am unteren Rand des Bildschirms möchte ich ein JLabel auf der rechten Ecke, dann in den Swing-Timer wird die JLabel allmählich auf die bewegen verlassen, bis es den Bildschirm verlässt. Wenn ich setLocation zum Arbeiten bringen könnte, wäre die Grundvoraussetzung, eine Variable x auf 600 und dann jede zweite Dekrementierung x auf etwa 50 zu setzen und dann JLabel an der neuen Position auf dem Bildschirm neu zu zeichnen. Grundlegende Animation

würde ich ein JPanel für den unteren Rand des Bildschirms für die Zwecke erstellen entweder Ihre JLabel halten oder ohne JLabel Anzeige des Bildes durch Überschreiben seine paintComponent(...) Methode. Wenn Sie es als Container verwenden, dann sollte sein Layout ja null sein, aber der Rest der GUI sollte kein Null-Layout verwenden. Der Swing-Timer würde einfach die Position von JLabel ändern und dann repaint() auf seinem JPanel/Container aufrufen. Wenn Sie die letztere Route gehen, würden Sie das Bild in der paintComponent(...) Methode von JPanel zeichnen, die g.drawImage(myImage, x, y) verwendet, und Ihr Timer würde X und/oder Y ändern und repaint() auf der Zeichnung JPanel aufrufen.

Außerdem möchten Sie wahrscheinlich kein JLabel in Ihrem Timer hinzufügen, sondern einfach das JLabel, das bereits in der GUI angezeigt wird, verschieben.

Um Fokusprobleme zu vermeiden, verwenden Sie keinen KeyListener, um die Tasteneingabe zu erfassen, sondern Key Bindings. Google leitet Sie zu einem großartigen Tutorial zu diesem Konstrukt.

bearbeiten 4
Zum Beispiel:

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(); 
     } 
     }); 
    } 
} 

Welche dieser GUI schaffen:

enter image description here

+1

+1. Das Festlegen des Standorts bei Verwendung eines LayoutManagers hat keine Auswirkungen. Es ist der LayoutManager, der den Ort bestimmt – Robin

+0

Ich hatte tatsächlich den Timer vor, aber jemand sagte mir, es wäre besser, ScheduledExecutorService zu verwenden.Es ist kein Problem, es wieder mit dem Swing-Timer zu verwenden. Ich bearbeite die Frage – awestover89

+0

Wenn immer noch nicht funktioniert, dann erstellen Sie ein einfaches kompilierbares und lauffähiges Programm, das Ihr Problem demonstriert und Online-Bilder für alle verwendet, ein [sscce] (http://sscce.org). –

8

drei Möglichkeiten:

  • Sie können entweder eine Bibliothek wie SlidingLayout verwenden, um einen solchen Übergang mit sehr wenigen Codezeilen zu erstellen. Sie werden nicht in der Lage sein, die Animation zu optimieren, aber Ihr Leben wird einfacher.

  • Sie können eine Animations-Engine wie die Universal Tween Engine verwenden, um alles von Hand zu konfigurieren und die Animation so viel wie Sie wollen (die erste Lib verwendet diese unter der Haube) zu optimieren. Unter Verwendung eines solchen Motors, können Sie animieren, was Sie wollen: Positionen, Farben, Schriftgröße, ...

  • Sie können alles von Hand-Code und die Hölle umarmen, dass die Animation Welt :)

am Ende werden Sie in der Lage sein, schnell wie diese Animationen zu erstellen (es ist ein Werkzeug, das ich gerade arbeite, verwendet eclipse-Projekte für android Entwickler konfigurieren mit dem Libgdx Spiele-Framework):
enter image description hereenter image description here

I machte diese Bibliotheken, um den Schmerz zu lindern ist UI-Animation (Ich liebe UI-Design: p). Ich veröffentlichte sie als Open-Source (frei zu benutzen, lizenziere Apache-2), in der Hoffnung, dass sie auch einigen Leuten helfen könnten.

Wenn Sie Hilfe benötigen, gibt es für jede Bibliothek ein eigenes Hilfeforum.

+1

wow. ziemlich glatt! 1+ –

+3

Ich werde das untersuchen. Als ich noch Student war, hasste ich die Idee, externe Bibliotheken zu benutzen. Etwas mit Stolz zu tun und zu sagen, dass ich alles selbst gemacht habe. Ich habe jedoch gelernt, bestehende Bibliotheken in meiner beruflichen Laufbahn zu umarmen, das Rad nicht neu zu erfinden. Ich werde dich wissen lassen, danke – awestover89

+0

Du hast meinen Tag gemacht. – Rempelos

1

Sehr einfach, schau dir das an:

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);