Java Animiere JLabel

Also erstelle ich eine Basisanwendung, die ein JLabel am unteren Rand des Bildschirms haben soll, das in der linken unteren Ecke beginnt und sich im Animationsformat in der rechten unteren Ecke in einer festgelegten Zeit und einem statischen Bild in der Mitte bewegt . 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, der hastig geschrieben wurde und alles andere als schön ist, ist:

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

}

Der ImageIcon in der Mitte von JLabel erscheint gut, und das leere JLabel mit einem Rand erscheint unten, aber ich kann das zweite JLabel mit dem Pfeilbild nicht auf dem Bildschirm sehen. 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 FlowLayout wahrscheinlich nicht dafür verwenden kann, 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 errorshaft, daher würde jede Hilfe geschätzt werden.

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 meinst du mit:

Ich möchte ein scrollendes JLabel am unteren Bildschirmrand haben

Bitte klären Sie den Effekt, den Sie erreichen möchten.

Auch in Bezug auf,

Ich verstehe auch, dass ich FlowLayout wahrscheinlich nicht dafür verwenden kann, 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.

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

Bearbeiten 3
Bezüglich:

Um zu verdeutlichen, dass ich am unteren Bildschirmrand ein JLabel ganz rechts in der Ecke haben möchte, bewegt sich das JLabel im Swing-Timer langsam nach links, 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

Ich würde ein JPanel für den unteren Teil des Bildschirms erstellen, um entweder JLabel zu halten oder das Bild ohne JLabel anzuzeigen, indem die paintComponent(...) -Methode überschrieben wird. 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 den zweiten Weg gehen, würden Sie das Bild in der paintComponent paintComponent(...) -Methode von g.drawImage(myImage, x, y) mit g.drawImage(myImage, x, y) , und Ihr Timer würde x und / oder y ändern und repaint() aufrufen die Zeichnung JPanel.

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 eine Tastatureingabe zu erfassen, sondern Key Bindings. Google leitet Sie zu einem großartigen Tutorial zu diesem Konstrukt.

Bearbeiten 4
Beispielsweise:

 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 dirMap = new EnumMap(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(); } }); } } 

Welches wird diese GUI erstellen:

Bildbeschreibung hier eingeben

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 zu optimieren, wie Sie möchten (die erste Lib verwendet diese unter der Haube). Mit dieser Engine können Sie animieren, was Sie wollen: Positionen, colors, Schriftgröße, …

  • Sie können alles mit der Hand programmieren und die Hölle, die die Welt der Animation ist, umarmen 🙂

Am Ende werden Sie in der Lage sein, schnell Animationen wie diese zu erstellen (es ist ein Werkzeug, an dem ich gerade arbeite, das verwendet wird, um Eclipse-Projekte für Android Dev mit dem LibGDX-Spiel-Framework zu konfigurieren):
Bildbeschreibung hier eingebenBildbeschreibung hier eingeben

Ich habe diese Bibliotheken gemacht, um den Schmerz zu lindern, der UI-Animation ist (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.

Sehr einfach, sieh 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);