Java Animate JLabel
Поэтому я создаю базовое приложение, в котором я хочу иметь JLabel в нижней части экрана, который начинается в левом нижнем углу и перемещается, стиль анимации, в правый нижний угол за определенное время и статическое изображение в центре , Для этого я создал JFrame с JPanel, используя BorderLayout. Существует JLabel с ImageIcon, добавленным в BorderLayout.CENTER и JPanel на BorderLayout.SOUTH. Мой код, в то время как поспешно написанный и далеко не красивый,
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(); }
}
ImageIcon в центре JLabel выглядит отлично, а пустой JLabel с рамкой появляется внизу, но я не могу получить вторую JLabel с изображением стрелки, которое будет отображаться на экране. В конце концов я перейду на scheduleAtFixedRate, чтобы постоянно перемещать JLabel, но сейчас я даже не могу заставить изображение появляться на экране.
- Лучший таймер для использования в службе Windows
- Самый точный таймер в .NET?
- Как использовать таймер в C ++ для принудительного ввода в заданное время?
- Лучший метод синхронизации в C?
- Печать «привет мир» каждые X секунд
Я также понимаю, что я, скорее всего, не смогу использовать FlowLayout для этого, поскольку я понимаю, что он не позволяет вам устанавливать местоположение ваших компонентов. Я попытался использовать нулевой макет, но с нулевым макетом пустой JLabel с рамкой не появляется. Я едва могу разглядеть верхнюю границу границы в нижнем краю frameworks, но даже с setLocation я не могу заставить ее отображаться там, где я ее хочу.
Очевидно, что мой мыслительный процесс испорчен, поэтому любая помощь будет оценена.
- Пауза / остановка и запуск / возобновление Java TimerTask непрерывно?
- Как установить таймер в Java?
- System.Timers.Timer vs System.Threading.Timer
- Остановить секундомер
- Java Timer vs ExecutorService?
- Почему System.Timers.Timer выживает GC, но не System.Threading.Timer?
- Обновление пользовательского интерфейса в C # с использованием таймера
- Как запустить метод каждые X секунд
Использование Swing-приложений для использования Swing-приложений неверно. Вы не должны пытаться добавлять или удалять компоненты в фоновом streamе, но вместо этого следует использовать таймер Swing для этого в streamе событий Swing.
Кроме того, что вы подразумеваете под:
Я хочу прокрутить JLabel в нижней части экрана
Просьба уточнить эффект, который вы пытаетесь достичь.
Кроме того,
Я также понимаю, что я, скорее всего, не смогу использовать FlowLayout для этого, поскольку я понимаю, что он не позволяет вам устанавливать местоположение ваших компонентов. Я попытался использовать нулевой макет, но с нулевым макетом пустой JLabel с рамкой не появляется. Я едва могу разглядеть верхнюю границу границы в нижнем краю frameworks, но даже с setLocation я не могу заставить ее отображаться там, где я ее хочу.
Нет, не используйте нулевой макет для этой ситуации. Есть намного лучшие менеджеры макетов, которые могут помочь вам создать ваше приложение в более чистом, более независимом от платформы образом.
Редактировать 3
Что касается:
Чтобы уточнить, внизу экрана я хочу JLabel в дальнем правом углу, затем в таймере поворота JLabel будет постепенно перемещаться влево, пока не покинет экран. Если бы я мог заставить setLocation работать, основная предпосылка заключалась бы в том, чтобы переменная x установлена в 600, а затем каждый второй декремент x, скажем 50, а затем перерисовывал JLabel в новом месте на экране. Основная анимация.
Я бы создал JPanel для нижней части экрана для того, чтобы либо держать ваш JLabel, либо отображать изображение без JLabel, переопределив свой метод paintComponent(...)
. Если вы используете его как контейнер, то да, его макет должен быть нулевым, но в остальной части графического интерфейса не должно использоваться нулевой макет. Таймер Swing просто изменил местоположение JLabel, а затем repaint()
на его JPanel / container. Если вы g.drawImage(myImage, x, y)
последний маршрут, вы нарисуете изображение в методе paintComponent(...)
JPanel, используя g.drawImage(myImage, x, y)
, и ваш таймер изменит x и / или y и переадресует вызов repaint()
на рисунок JPanel.
Кроме того, вы, вероятно, не хотите добавлять JLabel в свой таймер, а просто перемещать JLabel, который уже отображается в графическом интерфейсе.
Кроме того, чтобы избежать проблем с фокусом, не используйте KeyListener для ввода ввода клавиш, а используйте Key Bindings. Google направит вас к большому учебнику по этой конструкции.
Редактировать 4
Например:
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(); } }); } }
Что создаст этот графический интерфейс:
Три возможности:
-
Вы можете использовать библиотеку типа SlidingLayout для создания такого перехода с очень небольшим количеством строк кода. Вы не сможете настроить анимацию, но ваша жизнь будет проще.
-
Вы можете использовать движок анимации, такой как Universal Tween Engine, чтобы настроить все вручную и настроить анимацию столько, сколько хотите (первый lib использует этот под капотом). Используя такой движок, вы можете анимировать то, что хотите: позиции, цвета, размер шрифта, …
-
Вы можете закодировать все вручную и охватить ад, который является миром анимации 🙂
В конце концов, вы сможете быстро создавать такие анимации (это инструмент, над которым я сейчас работаю, используемый для настройки проектов eclipse для Android-разработчиков с использованием игровой среды LibGDX):
Я сделал эти библиотеки для облегчения боли, которая является анимацией пользовательского интерфейса (я люблю дизайн пользовательского интерфейса: p). Я выпустил их с открытым исходным кодом (бесплатный для использования, лицензия apache-2), надеясь, что они могут помочь некоторым людям.
Если вам нужна помощь, для каждой библиотеки есть специальный справочный форум.
Очень просто, посмотрите на это:
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);