Big image on smaller JFrame/Applet - java

I have a pretty big image that I want to display on my JFrame and applet, the JFrame/Applet is 765x503 in size but the image is way larger. I need a way to display the image in real size. How can I make it so I can move the screen around to display some of the image and be able to move around the image?
I want to be able to drag the screen around, not use Scrollbars.

JScrollPane might be the one you need.. add both vertical and horizontal scrolls

The basic idea is you need to provide some kind of offset that should be applied to the image to be drawn.
When the user presses the mouse button at a point on the image, you record the click point. When the drag the mouse, you delta the difference. This gives you the amount the offset is to be moved. Based on the original position, you simply add this difference to the and generate a new offset.
There are other ways to do it, but generally, this is the method I use.
I've also added code to check to see if the drag would put the image out of bounds of the viewable area, you'll have to decide if you want to use it...
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class BigImage {
public static void main(String[] args) {
new BigImage();
}
public BigImage() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage bg;
private Point offset = new Point(0, 0);
public TestPane() {
try {
bg = ImageIO.read(new File("/path/to/image"));
} catch (IOException ex) {
ex.printStackTrace();
}
MouseAdapter ma = new MouseAdapter() {
private Point clickPoint;
private Point origin;
#Override
public void mousePressed(MouseEvent e) {
setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
clickPoint = e.getPoint();
origin = new Point(offset);
}
#Override
public void mouseReleased(MouseEvent e) {
setCursor(Cursor.getDefaultCursor());
clickPoint = null;
}
#Override
public void mouseDragged(MouseEvent e) {
int x = e.getPoint().x - clickPoint.x;
int y = e.getPoint().y - clickPoint.y;
offset.x = origin.x + x;
offset.y = origin.y + y;
if (offset.x > 0) {
offset.x = 0;
}
if (offset.x + bg.getWidth() < getWidth()) {
offset.x = -bg.getWidth() + getWidth();
}
if (offset.y > 0) {
offset.y = 0;
}
if (offset.y + bg.getHeight() < getHeight()) {
offset.y = -bg.getHeight() + getHeight();
}
repaint();
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (bg != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(bg, offset.x, offset.y, this);
g2d.dispose();
}
}
}
}

Related

Moving an image to the position of the cursor where is clicked on a JFrame

i need some help here with an exercise of my Java class. What i'm trying to do is that when i click on any part of the JFrame, an image moves closer to the pointer. Right now i have done the part that once i click on the JFrame the image is in the same position as the pointer but it does like it's "teleporting" and i'm trying to make it more like a constant movement to the pointer position.
So far this is my code i have atm:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ControlaRaton extends MouseAdapter {
JLabel label;
public ControlaRaton(JLabel label){
this.label = label;
}
public void mouseClicked(MouseEvent evt){
Point pos = evt.getPoint();
System.out.println(pos.x+" "+pos.y);
//System.out.println("Boton: "+evt.getButton());
label.setLocation(pos.x-20,pos.y-50);
}
}
Any ideas on how to do it that way? I was thinking maybe using a Thread but i don't know exactly how to implement it here :s
This is pretty simple approach, basically all this does is uses a Swing Timer to move an entity towards the last known click point
Have a look at
Concurrency in Swing
How to use Swing Timers
How to Write a Mouse Listener
for more details
Swing is NOT thread safe, when performing these types of operations, it's important to take this into consideration. The Swing API provides several ways to work threads, in this case, I've used a simple Timer as it generates updates at a regular interval and triggers updates from within the EDT, making it safe to update the UI from within
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MoveTowards {
public static void main(String[] args) {
new MoveTowards();
}
public MoveTowards() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MoveTowardsPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
class MoveTowardsPane extends JPanel {
private final BufferedImage image;
private Point imagePosition = new Point(150, 150);
private Point mousePoint;
private double imageAngleRad = 0;
public MoveTowardsPane() {
BufferedImage i = null;
try {
i = ImageIO.read(getClass().getResource("/sprite.png"));
} catch (IOException e) {
e.printStackTrace();
}
image = i;
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
mousePoint = e.getPoint();
double dx = e.getX() - imagePosition.getX();
double dy = e.getY() - imagePosition.getY();
imageAngleRad = Math.atan2(dy, dx);
repaint();
}
});
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (mousePoint != null) {
int centerX = imagePosition.x + (image.getWidth() / 2);
int centerY = imagePosition.y + (image.getHeight() / 2);
if (mousePoint.x != centerX) {
imagePosition.x += mousePoint.x < centerX ? -1 : 1;
}
if (mousePoint.y != centerY) {
imagePosition.y += mousePoint.y < centerY ? -1 : 1;
}
repaint();
}
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics gr) {
super.paintComponent(gr);
Graphics2D g = (Graphics2D) gr.create();
g.setRenderingHint(
RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
int cx = image.getWidth() / 2;
int cy = image.getHeight() / 2;
AffineTransform oldAT = g.getTransform();
g.translate(cx + imagePosition.x, cy + imagePosition.y);
g.rotate(imageAngleRad);
g.translate(-cx, -cy);
g.drawImage(image, 0, 0, null);
g.setTransform(oldAT);
g.dispose();
}
}
}
Why doesn't this use a JLabel? A lot of reasons, JLabel isn't really well fitted for the task, as it needs to take into account a lot of other information. This example also "turns" the sprite towards the click point, something which isn't easily achieved with a JLabel.
In principle, the theory is still the same for moving a component.
See
Painting in AWT and Swing
Performing Custom Painting
for more details about how this approach works
Redraw your circle on mouse move
void mouseMoved(MouseEvent evt){
Point pos = evt.getPoint();
System.out.println(pos.x+" "+pos.y);
//System.out.println("Boton: "+evt.getButton());
label.setLocation(pos.x-20,pos.y-50);
}
});
If you want to move the label just a bit with each click you could do the following:
public void mouseClicked(MouseEvent evt){
Point clickedPos = evt.getPoint();
Point newPosForLabel = calculateNewPos(clickedPos, labelPos);
label.setLocation(newPosForLabel);
}
private Point calculateNewPos(Point clickedPos, Point labelPos) {
// calculate newPos based on labelPos and clickedPos
return newPos;
}
else use the timer from Hannes or from the link given by MadProgrammer:

Trouble with for loop

I have a for loop that iterates within an actionPerformed method. Basically, I have a car game. I have a panel where car images travel from side to side in a JPanel. I am trying to have the cars stop at the finish line (I am doing that by sleeping when the image reaches a certain x value) display the race results, leave the screen and race again. I need to do that four times until we have a winner.
private class RaceDisplay extends JPanel implements ActionListener{
private Image img1,img2;
private int velX1,velX2;
private int x1,x2;
private Timer tm;
private JTextArea text1 = new JTextArea();
public RaceDisplay(){
tm = new Timer(30,this);
x1=0;
x2=0;
velX1=2;
velX2 =2;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
ImageIcon car1 = new ImageIcon("...");
ImageIcon car2 = new ImageIcon("...");
img1 = car1.getImage();
img2 = car2.getImage();
g.drawImage(img1,x1,100,null);
g.drawImage(img2,x2,200,null);
tm.start();
}
public void actionPerformed(ActionEvent e) {
x1=x1+velX1;
velX2= x2+velX2;
repaint();
for(int count = 0;count<=4;count++){//<-----loop with issues.
if(count == 1){
text1.setText(result());
}
if(x1>=650 && x2>=650){ //does this when both cars reach the line
velX1=0;
velX2=0;
try {
Thread.sleep(2500);
} catch (InterruptedException ex) {
Logger.getLogger(Display.class.getName()).log(Level.SEVERE, null, ex);
}
x1=0;
x2=0;
repaint();
velX1= x1+velX1;
velX2= x2+velX2;
}
}
repaint();
}
I created the for loop that should check the if statements when it reaches the last counter it displays the winner(method for winner in the code). I was expecting the images to travel from side to four times and display the results four times.
But it only display anything if i set the if(counter==1) to (counter==0).
Can anyone help?
Thanks.
Don't call tm.start(); from within the paintComponent method, this is just asking for trouble. Painting may occur for any number of reasons, many of which you don't control or have knowledge about
Don't call Thread.sleep from within the context of the Event Dispatching Thread. This isn't stopping the Timer, but is prevent the EDT from processing the Event Queue, which includes things like repaint events and timer events...
Instead, once you've detected that a car has passed the finish line, you can either, stop updating that car's position and/or stop the Timer
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Map<BufferedImage, Rectangle> carBounds;
private BufferedImage blueCar;
private BufferedImage redCar;
public TestPane() {
carBounds = new HashMap<>(25);
try {
blueCar = ImageIO.read(getClass().getResource("/BlueCar.png"));
redCar = ImageIO.read(getClass().getResource("/RedCar.png"));
int x = 0;
int y = (200 / 2 ) - blueCar.getHeight();
carBounds.put(blueCar, new Rectangle(x, y, blueCar.getWidth(), blueCar.getHeight()));
y = (200 / 2);
carBounds.put(redCar, new Rectangle(x, y, redCar.getWidth(), redCar.getHeight()));
} catch (IOException ex) {
ex.printStackTrace();
}
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (BufferedImage img : carBounds.keySet()) {
Rectangle bounds = carBounds.get(img);
int xDelta = (int)Math.round((Math.random() * 7) + 1);
bounds.x += xDelta;
if (bounds.x + bounds.width > getWidth()) {
bounds.x = getWidth() - bounds.width;
((Timer)e.getSource()).stop();
}
}
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (BufferedImage img : carBounds.keySet()) {
Rectangle bounds = carBounds.get(img);
g2d.drawImage(img, bounds.x, bounds.y, this);
}
g2d.dispose();
}
}
}
Take a closer look at Concurrency in Swing for more details

How can I drag images with the mouse cursor in Java GUI?

// my code that calls upon n images in a directory to be placed on the JPanel
public void imageAdder(int n, String name){
BufferedImage myPic = null;
for (int i = 0; i <= n; i++){
try {
myPic = ImageIO.read(new File("Images/" + name + i + ".jpg"));
} catch (Exception e){
System.out.println("no file man cmon");
}
JLabel picLabel = new JLabel(new ImageIcon(myPic));
// picLabel.setBounds(mouseX, mouseY, 100, 50);
// picLabel.addMouseMotionListener(this);
// picLabel.addMouseListener(this);
canvas.add(picLabel);
}}
I read about the class DragSource and how there's a method that drags things of type image, but I'm not sure if that's applicable given my code. What should I do if I wanted to freely drag the images with my mouse?
There are a number of ways you might achieve this...for example, you could use custom painting to paint the individual images yourself. Each time the mouse is pressed/dragged, you would need to calculate which image was been dragged.
A slightly simpler solution might be to use a JLayeredPane and continue using JLabels to render the images, you could then use a MouseListener and MouseMoitionListener to detect when a label was pressed and/or dragged and update it's position accordingly...
See How to Write a Mouse Listener and How to Use Layered Panes for more details.
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestDrag {
public static void main(String[] args) {
new TestDrag();
}
public TestDrag() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JLayeredPane {
public TestPane() {
File[] images = new File("C:\\hold\\thumbnails").listFiles(new FileFilter() {
#Override
public boolean accept(File pathname) {
String name = pathname.getName().toLowerCase();
return name.endsWith(".png") ||
name.endsWith(".jpg") ||
name.endsWith(".bmp") ||
name.endsWith(".gif");
}
});
int x = 0;
int y = 0;
for (File imgFile : images) {
try {
BufferedImage img = ImageIO.read(imgFile);
JLabel label = new JLabel(new ImageIcon(img));
label.setSize(label.getPreferredSize());
label.setLocation(x, y);
MouseHandler mh = new MouseHandler();
label.addMouseListener(mh);
label.addMouseMotionListener(mh);
add(label);
x += 20;
y += 20;
} catch (IOException exp) {
exp.printStackTrace();
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 800);
}
public class MouseHandler extends MouseAdapter {
private Point offset;
#Override
public void mousePressed(MouseEvent e) {
JLabel label = (JLabel) e.getComponent();
moveToFront(label);
offset = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e) {
int x = e.getPoint().x - offset.x;
int y = e.getPoint().y - offset.y;
Component component = e.getComponent();
Point location = component.getLocation();
location.x += x;
location.y += y;
component.setLocation(location);
}
}
}
}
Look at custom classes in Java Swing, possibly useful links to get you started:
Java2s - DragandDropSupportforImages
DragImage.java DropImage.java DragImageEvent.java

How do i temporarily store an image of the JPanel or PaintComponent in Java?

I'm trying to make a paint program, and this class is the main area where you drag your mouse to paint. The problem is the clip has to be rectangular, so any other lines within that rectangle of the clip (the clip gets bigger the faster you move) will get covered by the new clip, however the new clip isn't all needed.
My ideas of solutions are:
To somehow set the clip to a line (but I think that clip would have to be set in the repaint method, not the setClip() in paint component)
To save the image currently on the paint component and set it to the backgroud
Possibly set the ocupancy of the clip lower in the areas without the line?
Thank you for looking at it, here is the code (with some parts left out for simpler reading) and if you know a solution I would love to hear it. Thanks!
public class Canvas extends JPanel implements MouseMotionListener, MouseListener{
int sizeX, sizeY;
String title;
int[] backColor = new int[3];
int brushSize=20;
Point currentP = new Point();
Point pastP = new Point();
Point paintP = new Point();
int diffX, diffY;
boolean initialize=true;
boolean initClip=true;
Canvas(){
backColor[0] = newProject.colorA;
backColor[1] = newProject.colorB;
backColor[2] = newProject.colorC;
if(backColor[0]>=255){
backColor[0]=255;
}
if(backColor[1]>=255){
backColor[1]=255;
}
if(backColor[2]>=255){
backColor[2]=255;
}
sizeX = newProject.sizeX;
sizeY = newProject.sizeY;
//System.out.println(sizeX + " " + sizeY);
setSize(sizeX,sizeY);
setBackground(Color.white);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(brushSize));
if(initialize){
g.setColor(new Color(backColor[0], backColor[1], backColor[2]));
g.fillRect(0, 0, sizeX, sizeY);
g.setColor(Color.red);
g.drawRect(0,0,50,50);
System.out.println("Initialize");
}
else{
g2.drawLine(currentP.x, currentP.y, pastP.x,pastP.y);
}
//System.out.println("Paint");
}
#Override
public void mouseDragged(MouseEvent e) {
if(initClip) //if mouse has been released since last dragged
currentP = e.getPoint(); //This causes PastP and CurrentP to be equal
initClip=false; //since pastP is set equal to CurrentP afterward
pastP = currentP;
currentP = e.getPoint();
diffX=Math.abs(currentP.x-pastP.x); //find the differences to find how big of
diffY=Math.abs(currentP.y-pastP.y); //a clip it needs
if(diffX==0){ //if no movement, set it to brush size so the
diffX=brushSize; //clip shows up
}
if(diffY==0){
diffY=brushSize;
}
initialize=false;
if(currentP.x-pastP.x>0){ //figures out which direction it moved
paintP.x=pastP.x; //sets the clip variable to the correct corner
}
else{
paintP.x=currentP.x;
}
if(currentP.y-pastP.y>0){
paintP.y=pastP.y;
}
else{
paintP.y=currentP.y;
}
System.out.println(paintP);
repaint(paintP.x, paintP.y, diffX, diffY); //repaint with point PaintP and the
//difference it moved
}
#Override
public void mouseReleased(MouseEvent arg0) {
initClip=true;
}
I'm not sure why you would bother. Each time paintComponent is called by the paint system, you are expected to repaint the entire component anyway.
Instead, simply paint what you need to paint, then paint the selection on top of it...
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DrawSelection {
public static void main(String[] args) {
new DrawSelection();
}
public DrawSelection() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage background;
private Rectangle clipRect;
public TestPane() {
try {
background = ImageIO.read(new File("/path/to/your/image"));
} catch (IOException ex) {
ex.printStackTrace();
}
MouseAdapter ma = new MouseAdapter() {
private Point cp;
#Override
public void mousePressed(MouseEvent e) {
cp = e.getPoint();
clipRect = null;
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
cp = null;
}
#Override
public void mouseDragged(MouseEvent e) {
Point p = e.getPoint();
int x = Math.min(p.x, cp.x);
int y = Math.min(p.y, cp.y);
int width = Math.max(p.x, cp.x) - x;
int height = Math.max(p.y, cp.y) - y;
clipRect = new Rectangle(x, y, width, height);
repaint();
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
}
#Override
public Dimension getPreferredSize() {
return background == null ? new Dimension(200, 200) : new Dimension(background.getWidth(), background.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (background != null) {
int x = (getWidth() - background.getWidth()) / 2;
int y = (getHeight() - background.getHeight()) / 2;
g2d.drawImage(background, x, y, this);
}
if (clipRect != null) {
g2d.setColor(UIManager.getColor("List.selectionBackground"));
g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
g2d.fill(clipRect);
}
g2d.dispose();
}
}
}
If you want to optimise the paint process, why not draw the parts of the image to a backing buffer and simply paint the buffer, then paint the selection or other dynamic parts on top of it within the paintComponent?

Image animation not getting displayed

I have the following code.I want to display the images in my chick array on the screen after some time delay.The coordinates have to be shifted by 10px each x direction when the new
image is loaded.I would like to know what additional code snippets can i add in this code to have an animation on my Frame with the two images i have .Below is my code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
public class Chicken extends Frame implements Runnable{
Thread animation;
long frameDelay = 3000;
Image chick[] = new Image[2];
int numFrames = chick.length;
Toolkit tk = getToolkit();
public Chicken()
{
setSize(new Dimension(300,300));
setVisible(true);
setBackground(Color.BLACK);
animation = new Thread(this);
chick[0] = tk.createImage("stand.png");
chick[1] = tk.createImage("walk.png");
animation.start();
//setVisible(false);
}
public void paint(Graphics g)
{
g.drawImage(chick[0],100,100,null );
}
#Override
public void run() {
// TODO Auto-generated method stub
repaint();
try {
Thread.sleep(frameDelay);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String args[])
{
Chicken instance = new Chicken();
}
}
So, the first problem you have is a resource issue.
Resources stored "within" the application (typically known as embedded resources) can't be loaded like external resources.
chick[0] = tk.createImage("stand.png");
Is expecting a file "./stand.png" which doesn't exist. Instead, you need to load the resource through the Class#getResource API...
chick[0] = tk.createImage(getClass().getResource("/stand.png"));
The second problem you will face is the fact that you are overriding paint of a top level container. This really shouldn't be done. Let's start with the fact it's not double buffered and end with the fact that frames have decorations which sit inside the viewable area. This means that the decorations will overlap what ever you paint to the surface...not pretty...
The third problem is you are not telling the image where it should move to. It's static.
You need some kind of x/y value that tells the image where it should be painted. You would modify these values by a given x/y delta within you thread before you called repaint...
The forth problem you might have is the fact that you are using AWT...which is kind of dated. Swing would solve your double buffering issue for you...IMHO, would make a better choice - there's a lot more documentation and examples on Swing laying around now days ;)
While I'm on my hobble horse...I would, personally, recommend ImageIO over Toolkit#createImage or ImageIcon, mostly because it supports more formats, but also because it will throw an Exception when the image can't be read for some reason...
I have a simple example if Swing, but I won't post it, because I'll get in trouble for running of topic...let me know if you would like to see it
Updated with Swing example
This uses a embedded image in the default package...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ChickenDance {
public static void main(String[] args) {
new ChickenDance();
}
public ChickenDance() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage chicken;
private int xPos;
private int yPos;
private int xDelta = 4;
public TestPane() {
try {
chicken = ImageIO.read(getClass().getResource("/Chicken.png"));
} catch (IOException ex) {
Logger.getLogger(ChickenDance.class.getName()).log(Level.SEVERE, null, ex);
}
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
xPos += xDelta;
if (xPos + chicken.getWidth() > getWidth()) {
xPos = getWidth() - chicken.getWidth();
xDelta *= -1;
} else if (xPos < 0) {
xPos = 0;
xDelta *= -1;
}
yPos = (getHeight() - chicken.getHeight()) / 2;
repaint();
}
});
if (chicken != null) {
timer.start();
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (chicken != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(chicken, xPos, yPos, this);
g2d.dispose();
}
}
}
}

Categories

Resources