Simple animations in Java - java

I'm attempting to code a simple animation or physics example in a Java Swing application. I have the actual windows application open and working, but I can't figure out how to actually draw my shapes, and how I'd format the code for calculations between frames, that sort of stuff.
I've read some stuff about over riding a paint method, but I don't know what that means, and I don't believe I'm using it in the code I'm using right now. This is my code:
public class Physics extends JFrame{
public Physics() {
initUI();
}
private void initUI() {
JPanel panel = new JPanel();
getContentPane().add(panel);
panel.setLayout(null);
final JLabel label = new JLabel("Hi, press the button to do something");
label.setBounds(20, 0, 2000, 60);
final JButton submitButton = new JButton("Start");
submitButton.setBounds(20, 150, 80, 20);
submitButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//Put button code here later
}
});
panel.add(label);
panel.add(submitButton);
setTitle("Program");
setSize(300, 250);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Physics ex = new Physics();
ex.setVisible(true);
}
});
}
}
So I have some blank space above my button where I'd like to draw maybe a square or circle moving across the screen to start off with, once I get that down I can start getting into the more advanced stuff. Any hints on how to do that would be appriciated :D
Thanks!

"I've read some stuff about over riding a paint method, but I don't know what that means"
So you've overridden actionPerformed, so you know what an #Override is. As you'll notice from the ActionListener, you never actually explicitly call actionPerformed, but whatever you put in the there, still get's used. That's because the ActionListener implicitly call it for you.
The same is true with painting. In the Swing painting process, there is a paint chain that Swing uses to paint components. Along the way paint is called somewhere. So just like actionPerformed, you can override paint and it will get implicitly called for you.
#Override
public void paint(Graphics g) {
super.paint(g);
}
The Graphics object passed to the method is the graphics context that Swing will use for the painting. You can look at the Graphics API to see the methods you can use. You can use drawOval to draw a circle
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawOval(x, y, width, height);
}
Now here's the thing. You don't actually want to override paint. In the tutorials linked above, some of the examples will use applets and override paint, but you shouldn'y paint on top level containers like JFrame or JApplet. Instead paint on a JPanel or JComponent and just add it the JFrame. When you do paint on JPanel or JComponent, you'll instead override paintComponent (which also gets called along the paint chain), instead of paint
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(x, y, width, height);
}
You see how I used variables for the drawOval method. The x is the x location from the top-let of the screen, and y and the y point. width and height are width and height of the circle. The great thing about using variables is that their values can be changed at runtime.
That's where the animation comes to play. As pointed out, you an use a javax.swing.Timer
The basic construct is
public Timer(int delay, ActionListener listener) {
}
The delay is the milliseconds to delay each call to the listener. The listener will have your actionPerformed call back that will do what's inside, every delay milliseconds. So what you can do, is just change the x from the drawOval and repaint(), and it will animate. Something like
Timer timer = new Timer(40, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
x += 5;
repaint();
}
});
timer.start();
The timer code you can just put in the constructor. That's probably simplest explanation I can give. Hope it helps.
Don't forget the to see Custom Painting and Grapics2D for more advance topics on graphics. Also see some example of timers and animation here and here and here and here and here
Also avoid using null layouts. See Laying out Components Within a Container to learn how to use layout managers, as should be done with Swing apps.

Take a look at the Swing tutorial on Custom Painting.
The example shows you how to do painting. If you want animation, then you would use a Swing Timer to schedule the animation. The tutorial also has a section on How to use a Swing Timer.
Put the two tutorial together and you have a solution.

There are any number of ways to achieve this.
Start by taking a look at:
Performing Custom Painting
2D Graphics
For details about how painting in Swing is done.
Animation is not as simple as just pausing a small period of time and then repainting, theres acceleration and deceleration and other concepts that need to be considered.
While you could write your own, that's not a small task, a better solution might be to use a pre-existing engine, for example...
Then take a look at:
Timing Framework
Trident
java-universal-tween-engine
Which are all examples of animation engines in Swing. While I prefer the Timing Framework as it provides me with a lower level API, this is a personal opinion. Both Trident and the JUWE seem to be geared more towards component/property based animation (which the Timing Framework can do if you want to build some of the feature sets up)

I created a simple animation with two rockets blasting off. The full eclipse project is here: https://github.com/CoachEd/JavaExamples/tree/master/RaceToSpace. Here's a screenshot:

Related

Java - Add new image to Jframe using JComponent on click

I created a Jframe using netbeans drag-n-drop designer. After asking here , I can make the color changing works after changing the color of some item from recList and paint(g) on a new thread of my Draw class.
Now I want to add another JComponent like DrawCar that will add the car image to the Jframe. I want this new JComponent because I don't want to re-render the "car" if the squares in the background change color.
So I created the DrawCar with paint() method like below:
public void paint(Graphics g) {
//This to make the (0,0) at the bottom-left not top-left as default.
Graphics2D g2 = (Graphics2D)g;
AffineTransform at = g2.getTransform();
at.translate(0, getHeight());
at.scale(1, -1);
g2.setTransform(at);
//Below is to draw the car
try {
image = ImageIO.read(new File("car.png"));
} catch (IOException ex) {
Logger.getLogger(Car.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
g.drawImage(image, 245, 0, null);
}
If I put these code to render the car in the paint() method of Draw class, it works, so no problem with this code!
In the Container (the class with the GUI) class, I have a button handler. I want the car appear when I click that button, so I tried to add to the event handler with
private void starter_btnActionPerformed(java.awt.event.ActionEvent evt) {
Thread reDraw = new Thread(new Runnable() {
#Override
public void run() {
//draw1 below is the instance of "Draw" class
//draw1.paint2(draw1.getGraphics()); //This code works with repainting the square with new color as mentioned before
DrawCar draw2 = new DrawCar();
repaint();
revalidate();
}
});
reDraw.start();
}
but it won't work, I don't know what I missed here. Maybe some ways to add the DrawCar to the current JFrame?
Thank you for your time!
EDIT:
I just make a simple project to make it clear. I created a JFrame named Test and drop in it a button that will show the picture when I click on it. It's all auto-generated codes.
Now I create a new class call MyClass
public class MyClass extends JComponent{
private BufferedImage image;
MyClass(){
try {
image = ImageIO.read(new File("D://pic.jpg"));
} catch (IOException ex) {
Logger.getLogger(this.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(image, 50, 50, null);
}
}
And in the Test, the event handler of the button is like this:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
MyClass mc = new MyClass();
add(mc);
repaint();
revalidate();
}
I clicked it and nothing happens. The picture is supposed to shows up on click. How do I make it happens? Thank you
EDIT 2:
This is the image of what I want to achieve, it's the little green car on the bottom, it should appears only when I click "Start!"
I see quite a few general problems with your code, including:
Never override the paint method, but rather a JPanel or JComponent's paintComponent method.
Almost always call the super's method.
Never read in a file from within a painting method.
Your code flagrantly violates Swing threading rules -- most all Swing calls should be made on the Swing event thread, not off of it as you're doing.
Better to create and post your Minimal, Complete, and Verifiable example or sscce as this way we can run your actually functioning code.
As for your specific problem, you're creating a DrawCar component instance, but you never appear to add it to your GUI, and so it will never show since it is never part of a top-level window such as a JFrame or JApplet or JDialog.
re comments:
Just though paint() and paintComponent() are the same, just one calls another...
No they're not. The paint(...) method is the more "primitive" of the two as it's based in the old AWT code base. It does not automatically do double buffering (unlike paintComponent) and is responsible for painting the component, the component's borders, and any child components held by the component. For the latter reason, you want to avoid overriding it since if you mess it up, you risk mispainting more than just the component.
Back to my problem, I make it like this DrawCar draw2 = new DrawCar(); add(draw2); draw2.setVisible(true); revalidate(); repaint(); I don't know if I missed the "prefix" before add, the code is auto-generated so I can't find any JFrame frame = new JFrame(); to make frame.add(draw2) like others do with their code Any chance that we will find some logical problem?
You've got major structural problems as your new DrawCar class again is nowhere to be seen in the main GUI.
So I'm guessing that your main GUI already has a DrawCar component held within it, and that you're goal is to get this to draw a car on button push (you never say!). If so, then why not have the DrawCar hold a JPanel and simply set its Icon with your image. Myself, I'd read the image in at program start up, and also flip it at at that time, if that were my goal.
Again, if you're still having problems, then isolate the problem down to the smallest compilable runnable code, your mcve and let us test it.

Rendering a 2d image in java

I am fairly new to java programming and I am trying to make a simple game however, I need to render my image I have made here is the code I put in eclipse:
public class MainMenu extends JFrame{
public static void main(String[] args){
new MainMenu();
}
public MainMenu(){
this.setSize(300, 450);
this.setLocationRelativeTo(null);
this.setResizable(true);
Toolkit tk = Toolkit.getDefaultToolkit();
Dimension dim = tk.getScreenSize();
int xPos = (dim.width / 2) - (this.getWidth() / 2);
int yPos = (dim.height / 2) - (this.getHeight() / 2);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocation(xPos, yPos);
this.setTitle("Frame For Flamedash Testing");
this.setVisible(true);
}
public void paint(Graphics g){
Image img1 = Toolkit.getDefaultToolkit().getImage("mainmenuscreen.png");
g.drawImage(img1, 20, 20, null);
} // public void paint(Graphics g)
public void putit() {
boolean MainMenu = true;
while (MainMenu == true){
repaint();
}
}
}
When I put that it is all fine and it does not give me any errors what so ever then I run it and it shows the frame but shows no picture than I full screen it because I set re-sizable true and it shows the default color in one spot with the size I set the frame too and another one identical but on the corner and black everywhere else. Any help to rendering this .png image will help, thank you in advance.
Don't override paint() in a JFrame.
The easiest way to display an image is to use a JLabel with an Icon.
Read the section from the Swing tutorial on How to Use Icons for more information and examples. The tutorial will show you how to better structure your code.
The tutorial also has a section on Custom Painting, if you really want to paint the image yourself. Custom painting is done by overriding the paintComponent() of a JPanel and then you add the panel to the frame.
First of all, in your paint method you should always call super.paint, else you break the paint chaining.
As for your issue,
You can call the repaint to force the painting. Keep a variable to hold the instance in your main and call repaint :
public MainMenu() {
...
repaint();
}
Note that loading an image from the paint method is a really bad idea as it will be loaded each time the frame is painted.
You've got several problems in that code including:
Drawing directly within the JFrame, something that can have unpleasant side effects
Trying to read in an image from within a painting method.
Your actual problem is often due to specifying the wrong path to the image, and to solve this you need to identify the actual user's directory that Java is looking at as the base of the path. This can be found by calling
System.out.println(System.getProperty("user.dir"));

Java swing animate swing components without performance loss

Solution:
Yes it is wrong. Never, never, never, NEVER read in files/images within a painting method. This method must be blindingly fast and must involve painting only, and doing this, reading in a file, will needlessly slow down your GUI to a crawl. And why do this? You can read the image in once in a constructor or method and then reuse the image object in paintComponent as many times as needed.
As an aside, you're probably better off obtaining the image as a resource and not a file.
Thanks, Hovercraft Full Of Eels
I am creating a very simple version of 'Fruit Ninja'. A game where some fruit flies onto the screen and the user has to cut it in two.
I am using a JLabel with ImageIcon for the fruit. I use a swing Timer for movement.
It works great, with animations too, but here is the tricky part. When I add a background image, the animations are verry laggy.
The question is: How can I add a background image, while the swing animations won't lose performance?
I added some code below.
Tim
My JPanel where I draw my background image:
public class PlayingField extends javax.swing.JPanel {
public PlayingField()
{
this.setBounds(0, 50, 500, 500);
this.setLayout(null);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
BufferedImage img = null;
try {
img = ImageIO.read(new File(System.getProperty("user.dir")+"/assets/background.png"));
} catch (IOException e)
{
}
g.drawImage(img, 0, 0, null);
}
}
The objects I'm drawing on them are just simple JLabels with ImageIcons.
I have a timer that handles the animation:
public class GameTimer extends javax.swing.Timer implements ActionListener {
GameController gameController;
public GameTimer(GameController gameController) {
super(delay, null);
this.addActionListener(this);
this.gameController = gameController;
}
#Override
public void actionPerformed(ActionEvent e)
{
gameController.moveObject();
}
}
and last but not least the code that moves the object:
public void moveObject()
{
activeObject.setPositionY((activeObjectView.getPositionY()+1));
playingField.repaint();
}
Yes it is wrong. Never, never, never, NEVER read in files/images within a painting method. This method must be blindingly fast and must involve painting only, and doing this, reading in a file, will needlessly slow down your GUI to a crawl. And why do this? You can read the image in once in a constructor or method and then reuse the image object in paintComponent as many times as needed.
As an aside, you're probably better off obtaining the image as a resource and not a file.

Calling the paint() method from another class?

I am trying to call the paint() method from another class, but it just doesn't work.
Here is the code:
Main.java:
public class Main extends JFrame {
private static final long serialVersionUID = 1L;
private int WIDTH = 600;
private int HEIGHT = 400;
private String NAME = "Dark Ages";
private String VERSION = "0.0.1 Pre-Alpha";
static boolean running = false;
private Image dbImage;
private Graphics dbg;
public Main() {
//Initialize window
JFrame frame = new JFrame();
frame.setTitle(NAME + " - " + VERSION);
frame.setSize(WIDTH, HEIGHT);
frame.setVisible(true);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
//Running
running = true;
}
public void paint(Graphics g) {
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
public void paintComponent(Graphics g) {
// Draw Images
repaint();
}
public static void main(String args[]) {
new Main();
Player player = new Player();
}
}
Player.java:
public class Player {
public void paint(Graphics g) {
g.drawRect(100, 100, 100, 100);
}
}
How do I call the paint() method from another class in java?
In brief, you don't. And in fact, you shouldn't call it directly from the same class either. Instead you should change the state of the class (change its fields), and then call repaint() on it, which will suggest to the JVM that the component should be painted.
Other issues and suggestions:
An obvious issue I see immediately in your code is that your class has a Graphics field, something that is dangerous to do. I suggest that you get rid of that field so that you're not tempted to use it.
Do not draw directly within a JFrame, JDialog or other top-level window. These windows have too many roles to play behind the scenes that you don't really want to mess with how they render themselves or their children (unless you really know what you're doing and have definite need).
Better to draw in the paintComponent(...) method override of a JPanel or other JComponents.
In your paintComponent(...) override, don't forget to call the super's method: super.paintComponent(g);. This will allow Swing to do housekeeping drawing, such as erasing old out of date or deleted images, before you do your drawing.
Run, don't walk to your nearest Swing painting tutorial.
Your current Player class extends no Swing component and is added to no top level window, so its code will do nothing useful. Again, read the tutorials.
Never call repaint() from within paint(...) or paintComponent(...).
Please post modified code if possible.: please don't ask us to create code for you as that's your job. Please understand that the more code you create, the better a coder you'll be, and because of this, most of us don't feel that we should cheat you out of the opportunity to create your own code.
Useful Java Tutorials:
The Really Big Index: The main tutorial where you should start.
Using Swing Components: How to create Swing GUI's
Lesson: Performing Custom Painting: Introductory tutorial to Swing graphics
Painting in AWT and Swing: Advanced tutorial on Swing graphics

Java: Safe Animations with Swing

I am creating a program that uses JFrame, JPanel, JLabel and all other sorts of swing components.
What I want to do is create a 2D animation on a separate JPanel that is dedicated to this animation. So I will be overriding the paintComponent (Graphics g) method.
I have experience making animations with for loops + Threads, but I am hearing that threads are not safe with swing.
Due to this, is it safe for me to make an animation with the use of the Runnable interface? If not what shall I use (e.g. Timer) and please give a small example on how to best use it (or a link to a web page).
EDIT:
Thanks to Jeff, I will be using Timer to create the animation. For future viewers of this question, here is a quick program I coded in about 5 minutes, excuse the dirty code.
I have also added some quick comments.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class JFrameAnimation extends JFrame implements ActionListener
{
JPanel panel;
Timer timer;
int x, y;
public JFrameAnimation ()
{
super ();
setDefaultCloseOperation (EXIT_ON_CLOSE);
timer = new Timer (15, this); //# First param is the delay (in milliseconds) therefore this animation is updated every 15 ms. The shorter the delay, the faster the animation.
//This class iplements ActionListener, and that is where the animation variables are updated. Timer passes an ActionEvent after each 15 ms.
}
public void run ()
{
panel = new JPanel ()
{
public void paintComponent (Graphics g) //The JPanel paint method we are overriding.
{
g.setColor (Color.white);
g.fillRect (0, 0, 500, 500); //Setting panel background (white in this case);
//g.fillRect (-1 + x, -1 + y, 50, 50); //This is to erase the black remains of the animation. (not used because the background is always redrawn.
g.setColor (Color.black);
g.fillRect (0 + x, 0 + y, 50, 50); //This is the animation.
}
}
;
panel.setPreferredSize (new Dimension (500, 500)); //Setting the panel size
getContentPane ().add (panel); //Adding panel to frame.
pack ();
setVisible (true);
timer.start (); //This starts the animation.
}
public void actionPerformed (ActionEvent e)
{
x++;
y++;
if (x == 250)
timer.stop (); //This stops the animation once it reaches a certain distance.
panel.repaint (); //This is what paints the animation again (IMPORTANT: won't work without this).
panel.revalidate (); //This isn't necessary, I like having it just in case.
}
public static void main (String[] args)
{
new JFrameAnimation ().run (); //Start our new application.
}
}
Jimmy, I think you are misunderstanding how threads work in Swing. You must use a specific thread called the Event Dispatch Thread to do any updating on swing components (with a few specific exceptions I won't discuss here). You can use a swing timer to set a recurring task to run on the event dispatch thread. See this example of how to use Swing timers. http://download.oracle.com/javase/tutorial/uiswing/misc/timer.html
You should also read up on the Event Dispatch Thread so you understand its place in Swing http://download.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html
Java also provides a variety of methods for working with Swing in the SwingUtilities class, notably invokeLater and invokeAndWait which will run code on the event dispatch thread.
While is good to understand the EDT and SwingUtilities (everybody doing Swing should do so) if you're going to be doing a lot of animation I would recommend to use the TimingFramework. This will allow you to concentrate a little more on design and will give you a better control on "rate". Inherently the timing framework uses a Swing timer so the callbacks are on the EDT. Part of the Filthy-rich clients collection, the author made the chapter available.
Have fun!

Categories