Java Animate JLabel

Quindi sto creando un’applicazione di base che voglio avere una JLabel nella parte inferiore dello schermo che inizia nell’angolo in basso a sinistra e si sposta, lo stile dell’animazione, nell’angolo in basso a destra in un tempo prestabilito, e un’immagine statica nel centro . Per fare questo, ho creato una JFrame con JPanel usando BorderLayout. C’è una JLabel con ImageIcon aggiunto a BorderLayout.CENTER e un JPanel a BorderLayout.SOUTH. Il mio codice, scritto in modo frettoloso e tutt’altro che carino, è:

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 actionPerformsd(ActionEvent e) { arrows.add(arrowLabel); arrowLabel.setBounds(x, 100, 100, 100); x-=50; arrows.repaint(); frame.repaint(); } }); t.start(); } 

}

L’ImageIcon nel centro JLabel sembra soddisfacente, e la JLabel vuota con un bordo appare in basso, ma non riesco a far apparire la seconda JLabel con l’immagine della freccia sullo schermo. Alla fine cambierò in scheduleAtFixedRate per spostare continuamente la JLabel, ma al momento non riesco nemmeno a far apparire l’immagine sullo schermo.

Capisco anche che molto probabilmente non sarò in grado di usare FlowLayout per questo, poiché capisco che non ti permette di impostare la posizione dei tuoi componenti. Ho provato ad usare layout nullo, ma con layout nullo la JLabel vuota con un bordo non appare. Riesco a malapena a distinguere la parte superiore del bordo sul bordo inferiore della cornice, ma anche con setLocation non riesco a farla apparire dove voglio.

Ovviamente, il mio processo di pensiero è imperfetto, quindi qualsiasi aiuto sarebbe apprezzato.

L’uso del threading è completamente sbagliato per le applicazioni Swing. Non dovresti provare ad aggiungere o rimuovere componenti in un thread in background, ma dovresti usare un timer Swing per farlo sul thread dell’evento Swing.

Inoltre, cosa intendi con:

Voglio avere una JLabel scorrevole nella parte inferiore dello schermo

Per favore chiarisci l’effetto che stai cercando di raggiungere.

Anche riguardo,

Capisco anche che molto probabilmente non sarò in grado di usare FlowLayout per questo, poiché capisco che non ti permette di impostare la posizione dei tuoi componenti. Ho provato ad usare layout nullo, ma con layout nullo la JLabel vuota con un bordo non appare. Riesco a malapena a distinguere la parte superiore del bordo sul bordo inferiore della cornice, ma anche con setLocation non riesco a farla apparire dove voglio.

No, non utilizzare layout nullo per questa situazione. Ci sono manager di layout molto migliori che possono aiutarti a build la tua applicazione in un modo più pulito e indipendente dalla piattaforma.

Modifica 3
Per quanto riguarda:

Per chiarire, nella parte inferiore dello schermo voglio una JLabel nell’angolo all’estrema destra, quindi nel cronometro, la JLabel si sposterà gradualmente verso sinistra finché non lascerà lo schermo. Se potessi far funzionare setLocation, la premessa di base sarebbe quella di avere una variabile x impostata su 600, e quindi ogni secondo decremento x di dire 50 e quindi ridisegnare la JLabel nella nuova posizione sullo schermo. Animazione di base.

Vorrei creare un JPanel per la parte inferiore dello schermo allo scopo di mantenere la tua JLabel o visualizzare l’immagine senza una JLabel paintComponent(...) suo paintComponent(...) . Se lo usi come contenitore, allora sì, il suo layout dovrebbe essere nullo, ma il resto della GUI non dovrebbe usare layout nullo. Lo Swing Timer cambia semplicemente la posizione di JLabel e quindi chiama repaint() sul suo JPanel / container. Se segui la seconda strada, devi disegnare l’immagine nel metodo paintComponent(...) g.drawImage(myImage, x, y) usando g.drawImage(myImage, x, y) , e il tuo timer cambierebbe x e / o y e chiamerà repaint() su il disegno JPanel.

Inoltre, probabilmente non si desidera continuare ad aggiungere una JLabel nel proprio timer, ma piuttosto semplicemente spostando la JLabel già visualizzata nella GUI.

Inoltre, per evitare problemi di messa a fuoco, non utilizzare un KeyListener per acquisire l’input della sequenza di tasti, ma piuttosto utilizzare i collegamenti chiave. Google ti indirizzerà a un ottimo tutorial su questo costrutto.

Modifica 4
Per esempio:

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

Quale creerà questa GUI:

inserisci la descrizione dell'immagine qui

Tre possibilità:

  • È ansible utilizzare una libreria come SlidingLayout per creare tale transizione con poche righe di codice. Non sarai in grado di modificare l’animazione ma la tua vita sarà più facile.

  • Puoi utilizzare un motore di animazione come Universal Tween Engine per configurare tutto a mano e modificare l’animazione quanto vuoi (la prima lib usa questo sotto il cofano). Usando questo motore, puoi animare quello che vuoi: posizioni, colors, dimensione del carattere, …

  • Puoi codificare tutto a mano e abbracciare l’inferno che è il mondo dell’animazione 🙂

Alla fine, sarai in grado di creare rapidamente animazioni come queste (è uno strumento su cui sto lavorando attualmente, usato per configurare i progetti di eclipse per Android Dev usando il framework di gioco LibGDX):
inserisci la descrizione dell'immagine quiinserisci la descrizione dell'immagine qui

Ho creato queste librerie per alleviare il dolore che è l’animazione dell’interfaccia utente (I love UI design: p). Li ho rilasciati open-source (libero da usare, licenza apache-2), sperando che possano aiutare anche alcune persone.

Se hai bisogno di aiuto, c’è un forum di aiuto dedicato per ogni biblioteca.

Molto semplice, guarda questo:

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