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();
}
}
}
}
Related
when I call a repaint method its flickering, I was searching on the internet about doubleBuffered but its stil flickering all of objects on the same time,
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.ArrayList;
import java.util.Random;
public class GuiGame extends JFrame implements ActionListener {
private final Flower flower;
private final ArrayList<MyObjects> objekty;
private Image dbImage;
private Graphics dbGraphics;
public GuiGame() {
this.setFocusable(true);
Timer timer = new Timer(40, this);
timer.start();
this.setVisible(true);
/*
public void paint(Graphics g) {
this.dbImage = this.createImage(this.getWidth(), this.getHeight());
this.dbGraphics = this.dbImage.getGraphics();
this.paintComponents(g);
g.drawImage(this.dbImage, 0 ,0, this);
}
*/
public void paint(Graphics g) {
//when i use doubleBuffering this method was called paintComponents
g.drawImage(background.getImage(), 0, 0, this);
g.drawImage(flower.getImage(), flower.getPozX(), flower.getPozY(), this);
String skore = "Score: " + player.getScore() ;
g.drawString(skore, 20, 50);
this.paintObjects(g);
}
public void paintObjects(Graphics g) {
if (this.objekty != null) {
for (objekty o : this.objekty) {
o.move();
g.drawImage(o.getImage(), o.getPozX(), o.getPozY(), this);
}
}
}
when I used doubleBuffering I tried to slow down a timer e.g. to 1000, it was blank page for most of the time and my objects was there only for moment.
when I do not used it, only last objects which i draw were flickering.
how can I avoid?
I would recommend you start by taking a look at Painting in AWT and Swing and Performing Custom Painting.
Swing components, when used correctly, are double buffered by default.
Painting is very complex, there's a lot of work that goes into a paint pass. When you override a "paint" method, you either need to honour the existing workflow (ie, call the super.paintXxx method) or be prepared to take over the full responsibility of the method. Your code has circumvented whole sections of the paint workflow, this is never a good idea.
It's not generally recommend that you extend from top level containers like JFrame, you're not adding any new functionality and they are generally complex components to start with. JFrame for example, is actually a composite component, that is, it has a number of child components added to it that form it's core functionality
By overriding paint (of JFrame), you start competing with these components, and because a child component can be painted without the parent been involved, this can lead to any number of issues.
Instead, start with a JPanel and override it's paintComponent method, this guarantees that you will be operating in a double buffered workflow.
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;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
JFrame frame = new JFrame();
frame.add(new MainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public class MainPane extends JPanel {
private int xDelta = 1;
private int xPos = 0;
private BufferedImage ufo;
public MainPane() throws IOException {
ufo = ImageIO.read(getClass().getResource("/images/ufo.png"));
Timer timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
xPos += xDelta;
if (xPos + ufo.getWidth() > getWidth()) {
xPos = getWidth() - ufo.getWidth();
xDelta *= -1;
} else if (xPos < 0) {
xPos = 0;
xDelta *= -1;
}
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
paintUFO(g2d);
g2d.dispose();
}
protected void paintUFO(Graphics2D g2d) {
int y = (getHeight() - ufo.getHeight()) / 2;
g2d.drawImage(ufo, xPos, y, this);
}
}
}
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:
I am making a 2d game and I need to draw an image on top of another. After I draw the first image(the larger one, jpg), the second image(the smaller one,png) erases from where the second image is to the lower right hand corner. Like this:
I have looked into this a bit, and it was suggested that I use buffered images, so I did that with both images and the problem remains. Here is one post I looked at: How to draw an image over another image?. I have also seen some people suggesting graphics2d, though I did not really understand the reason to use them or how to use them. I am new to java graphics and images, so it is probably a silly mistake.
Here is my code. Thank you.
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import javax.swing.*;
import java.util.ArrayList;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.IOException;
public class DisplayExample extends JComponent
{
private BufferedImage backgroundImage;
private String backgroundName;
private BufferedImage image; //image to draw
private int imageX; //position of left edge of image
private int imageY; //position of top edge of image
private JFrame frame;
public static void main(String[] args)
{
DisplayExample example = new DisplayExample();
example.run();
}
public DisplayExample()
{
imageX = 200;
imageY = 200;
backgroundName = "backgroundShip.jpg";
URL backgroundURL = getClass().getResource(backgroundName);
if (backgroundURL == null)
throw new RuntimeException("Unable to load: " + backgroundName);
try{backgroundImage = ImageIO.read(backgroundURL);}catch(IOException ioe){}
//load image
String fileName = "explosion.png";
URL url = getClass().getResource(fileName);
if (url == null)
throw new RuntimeException("Unable to load: " + fileName);
//image = new ImageIcon(url).getImage();
try{image = ImageIO.read(url);}catch(IOException ioe){}
System.out.println(image instanceof BufferedImage);
setPreferredSize(new Dimension(1040,500)); //set size of drawing region
//need for keyboard input
setFocusable(true); //indicates that WorldDisp can process key presses
frame = new JFrame();
frame.getContentPane().add(this);
frame.pack();
frame.setVisible(true);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if(backgroundImage != null)
g.drawImage(backgroundImage,0,0,getWidth(), getHeight(), null);
g.drawImage(image, imageX, imageY, this);
}
public void run()
{
while(true)
{
imageY+=1;
repaint();
try{Thread.sleep(100);}catch(Exception e){}
}
}
}
So I took your code, added my own images and it runs fine for me.
Having said that, there are some areas you can improve:
You're running the risk of either blocking the Event Dispatching Thread or introducing a thread race condition into your code with your run method. You should consider using a Swing Timer instead. See How to use Swing Timers for more details. This allows you to schedule regular callbacks which are called within the context of the EDT, making it safer to update the context of the UI
You should only ever create or modify the state of the UI from within the context of the EDT, Swing is not thread safe. See Initial Threads for more details. Swing has been known to have "issues" when the UI is not initialised within the EDT
Scaling an image is expensive, you should avoid doing so from within the paint methods, instead, scale the image and keep a reference to the result and use it when you need to paint it.
You should consider using the key bindings API over KeyListener, it will solve many of the issues associated with using KeyListener. See How to Use Key Bindings for more details.
For example...
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.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DisplayExample extends JComponent {
private BufferedImage backgroundImage;
private String backgroundName;
private BufferedImage image; //image to draw
private int imageX; //position of left edge of image
private int imageY; //position of top edge of image
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
DisplayExample example = new DisplayExample();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(example);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public DisplayExample() {
imageX = 200;
imageY = 200;
try {
backgroundImage = ImageIO.read(new File("..."));
} catch (IOException ioe) {
ioe.printStackTrace();
}
//load image
try {
image = ImageIO.read(new File("..."));
} catch (IOException ioe) {
ioe.printStackTrace();
}
//need for keyboard input
//setFocusable(true); //indicates that WorldDisp can process key presses
// Use the key bindings API instead, causes less issues
Timer timer = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
imageY += 1;
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return backgroundImage == null ? new Dimension(200, 200) : new Dimension(backgroundImage.getWidth(), backgroundImage.getHeight());
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (backgroundImage != null) {
// Scaling is expensive, don't do it here
int x = (getWidth() - backgroundImage.getWidth()) / 2;
int y = (getHeight() - backgroundImage.getHeight()) / 2;
g2d.drawImage(backgroundImage, x, y, this);
}
g2d.drawImage(image, imageX, imageY, this);
g2d.dispose();
}
}
I am trying to simply rotate an image in a for loop like so:
class MyCanvas extends JComponent {
AffineTransform identity = new AffineTransform();
Image arrow;
Double angle = -180.0;
public void spin() {
angle += 10.0;
for(int i = 0; i < 10; i++) {
repaint();
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
arrow = Toolkit.getDefaultToolkit().getImage("red-arrow-right-th.png");
// Rotate + translate
AffineTransform trans = new AffineTransform();
trans.setTransform(identity);
trans.translate(getWidth()/2, getHeight()/2);
trans.rotate(Math.toRadians(angle));
System.out.println(trans);
g2.drawImage(arrow, trans, this);
g2.finalize();
}
}
However when I run call spin() in main, it appears to apply only a single rotation, whilst still printing out the loop correctly. What am I overlooking something?
I've transformed your code using the recommendation of MadProgrammer:
Don't override paint, override paintComponent.
Call super.paint before performing any custom painting,
Never call finalize on anything and especially not on objects you didn't create yourself.
Use a Swing Timer
Note the following
A qualified this is used to access the ImageRotationView instance from the ActionListener inner class.
AffineTransform.getRotateInstance returns a transform that rotates coordinates around an anchor point.
Speed can be optimized but it works correctly like this.
This class works as a standalone application
A file named dice.png should be present in the base directory.
.
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;
public class ImageRotationFrame {
public static void main(String[] args) {
new ImageRotationFrame();
}
public ImageRotationFrame() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Testing");
frame.setSize(400, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new ImageRotationComponent());
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
private class ImageRotationComponent extends JComponent {
Image arrow;
double angle = 0.0;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
angle += 0.4;
AffineTransform trans = AffineTransform.getRotateInstance(angle, getWidth() / 2, getHeight() / 2);
((Graphics2D) g).drawImage(arrow, trans, this);
}
public ImageRotationComponent() {
try {
arrow = ImageIO.read(new File("dice.png"));
} catch (IOException e) {
e.printStackTrace();
}
int delay = 500; //milliseconds
ActionListener taskPerformer = new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
ImageRotationComponent.this.repaint();
}
};
new Timer(delay, taskPerformer).start();
}
}
}
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();
}
}
}
}