Java Animate Jlabel

Java Animate JLabel

Your use of threading is all wrong for Swing applications. You should not be trying to add or remove components in a background thread but instead should use a Swing Timer to do this on the Swing event thread.

Also, what do you mean by:

I want to have a scrolling JLabel at the bottom of the screen

Please clarify the effect you're trying to achieve.

Also regarding,

I also understand that I will most likely not be able to use FlowLayout for this, as I understand it does not allow you to set the location of your components. I tried using null layout, but with null layout the empty JLabel with a border does not appear. I can barely make out the top of the border at the bottom edge of the frame, but even with setLocation I cannot get it to appear where I want it to.

No, don't use null layout for this situation. There are much better layout managers that can help you build your application in a cleaner more platform-independent manner.

Edit 3
Regarding:

To clarify, at the bottom of the screen I want a JLabel at the far right corner, then in the swing timer, the JLabel will gradually move to the left until it leaves the screen. If I could get setLocation to work, the basic premise would be to have a variable x set to 600, and then every second decrement x by say 50 and then redraw the JLabel at the new location on the screen. Basic animation.

I would create a JPanel for the bottom of the screen for the purposes of either holding your JLabel or displaying the image without a JLabel by overriding its paintComponent(...) method. If you use it as a container, then yes, its layout should be null, but the rest of the GUI should not be using null layout. The Swing Timer would simply change the JLabel's location and then call repaint() on its JPanel/container. If you go the latter route, you would draw the image in the JPanel's paintComponent(...) method using g.drawImage(myImage, x, y), and your timer would change x and/or y and call repaint() on the drawing JPanel.

Also, you likely do not want to keep adding a JLabel in your timer but rather simply moving the JLabel that's already displayed in the GUI.

Also, to avoid focus issues, don't use a KeyListener to capture keystroke input but rather use Key Bindings. Google will direct you to a great tutorial on this construct.

Edit 4
For example:

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

Which will create this GUI:

Sample Image

How to animate jLabel from one side to another side of Jframe using netbeans

Sample Image

To keep things simple, you may use the Swing timer for the animation. However, if I were you I wouldn't move a JLabel. But instead I will draw directly onto the JPanel and keep a set of positions (x and y for the image). In the timer, update the position and repaint it.

Since you wanted to move a JLabel across the screen, you can do something like this:

class DrawingSpace extends JPanel{

private JLabel label;
private JButton button;
private Timer timer;

public DrawingSpace(){
setPreferredSize(new Dimension(200, 300));
initComponents();
add(label);
add(button);
}

public void initComponents(){
label = new JLabel("I am a JLabel !");
label.setBackground(Color.YELLOW);
label.setOpaque(true);
button = new JButton("Move");

//Move every (approx) 5 milliseconds
timer = new Timer(5, new ActionListener(){
@Override
public void actionPerformed(ActionEvent e){
//Move 1 px everytime
label.setLocation(label.getLocation().x, label.getLocation().y+1);
}
});
button.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e){
if(!timer.isRunning())
timer.start();
else
timer.stop();
}
});
}
}

Then the class to run the program:

class Mover{
public static void main(String[] args){

SwingUtilities.invokeLater(new Runnable() { // Run the GUI codes on the EDT
@Override
public void run() {
JFrame frame = new JFrame("Some Basic Animation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new DrawingSpace());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}

If you plan to implement using paint(), I would say you probably should be overriding paintComponents(Graphics g) instead of paint(Graphics g) from the Java Components.
Also do not clutter your paint method with things like Thread.sleep() it may freeze your UI. The paint method should only contain codes needed for painting and nothing else.

JLabel animation in JPanel

I noticed that in order to animate
JLabels across the screen I need to
setlayout(null); and setbounds of the
component and then to animate
eventually setlocation(x,y);. Is this
a best practice or a terrible way to
animate a component?

Well, this is not entirely true. You can just play with the location and the label will move around the screen. However, if you ever resize the frame or anything then the layout manager will be invoked and the label will be repositioned and the location defined by the layout manager which in the case of a FlowLayout will be the top/left of the panel. Animation will then continue from that location. So in reality, yes, this is exactly what you need to do.

I find it the easiest way to do animation since Swing will automatically repaint the "last" location of the component (to restore the background) as well as paint the new location of the component. This is all achieved by a single setLocation() method.

Some people like to do custom painting by drawing the image directly on the panel, but then you are responsible for clearing the old location of the image so the background is redrawn and then draw the image in the new location. I find this too much work.

Java Swing - How do I add an appearing effect for JLabel?

I'm not exactly sure what you mean with "appearring effect", but if you want to create some color effects, you could extend the JLabel class and add some custom Color/Image Effects. Maybe this example for creating a JLabel with various effects gets you started.

See also How to animate a JLabel

Java move jlabel in animation every 0.5 second

Instead of using Java Timer try with Swing Timer that is more suitable for Swing application.

Please have a look at How to Use Swing Timers

Find a sample code How to fix animation lags in Java?



Related Topics



Leave a reply



Submit