It's for a pacman game and it works perfectly when I import it from my computer. But when I try to take it from an URL, my game starts lagging and the image doesn't show.
URL url = new URL("https://www.dropbox.com/s/xpc49t8xpqt8dir/pacman%20down.jpg");
image = ImageIO.read(url);
G.drawImage(image, x, y, 20,20,null);
Image
( http://i.stack.imgur.com/Cp1XL.png at IMGUR )
https://www.dropbox.com/s/xpc49t8xpqt8dir/pacman%20down.jpg is return HTML text not image data.
This is a hack, but try https://www.dropbox.com/s/xpc49t8xpqt8dir/pacman%20down.jpg?dl=1 instead. Be warned though, it's possible that drop box could change this query in the future.
public class TestURL02 {
public static void main(String[] args) {
new TestURL02();
}
public TestURL02() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new PacPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PacPane extends JPanel {
private BufferedImage image;
public PacPane() {
InputStream is = null;
try {
URL url = new URL("https://www.dropbox.com/s/xpc49t8xpqt8dir/pacman%20down.jpg?dl=1");
// StringBuilder sb = new StringBuilder(1024);
// byte[] buffer = new byte[1024 * 1024];
// is = url.openStream();
// int in = -1;
// while ((in = is.read(buffer)) != -1) {
// sb.append(new String(buffer));
// }
// System.out.println(sb.toString());
image = ImageIO.read(url);
} catch (IOException exp) {
exp.printStackTrace();
} finally {
try {
is.close();
} catch (Exception e) {
}
}
}
#Override
public Dimension getPreferredSize() {
return image == null ? super.getPreferredSize() : new Dimension(image.getWidth(), image.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null) {
int x = (getWidth() - image.getWidth()) / 2;
int y = (getHeight() - image.getHeight()) / 2;
g.drawImage(image, x, y, this);
}
}
}
}
I think that it may lag because the program downloads the image each time you draw it with your Graphics object. You should use a cache system for your image or download it once for all the program execution.
My guess, and it's only a guess because you don't tell us, but could you possibly be trying to read in the Image from the URL from within a Swing or AWT paint(...) or paintComponent(...) method? If so, don't do this. Read the image in once, and then use it in the paintComponent(...) method.
If this doesn't help, please do tell us the details we'll need to know to be able to help you.
Related
I'm trying to move the boat on the x-axis (without the keyboard yet). How can I relate the movement/ animation to the boat.png and not to any other image?
public class Mama extends Applet implements Runnable {
int width, height;
int x = 200;
int y = 200;
int dx = 1;
Image img1, img2, img3, img4;
#Override
public void init(){
setSize(627, 373);
Thread t = new Thread(this);
img1 = getImage(getCodeBase(),"Background.png");
img2 = getImage(getCodeBase(), "boat.png");
img3 = getImage(getCodeBase(), "LeftPalm.png");
img4 = getImage(getCodeBase(), "RightPalm.png");
}
#Override
public void paint(Graphics g){
g.drawImage(img1, 0, 0, this);
g.drawImage(img2, 200, 200, this);
g.drawImage(img3, 40, 100, this);
g.drawImage(img4, 450, 130, this);
}
#Override
public void run() {
while(true){
x += dx;
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
System.out.println("Thread generates an error.");
}
}
}
}
There are a few things that stand out...
The "Problem"
As has already been stated, you need to supply variable arguments to the image drawing process. g.drawImage(img2, x, y, this);, this will allow you define where the image should be painted.
While you've implemented Runnable, you've actually not started any threads to call it. This means, nothing is actually changing the variables.
In you start method, you should be calling something like new Thread(this).start().
Recommendations
Although you've tagged the question as Swing, you're using AWT components. This isn't recommended (in fact applets are generally discouraged as they are troublesome - IMHO). The other problem, as you are bound to find out shortly, is they are not double buffered, this generally leads to flickering when performing animation, which isn't desirable.
As a side note, it is also discouraged to override the paint method of top level containers like Applet. Top level containers tend to contain a number additional components, by overriding the paint method like this, you destroy this setup. Also, top level containers don't tend to be double buffered either.
The example below uses a JFrame, but it wouldn't take much to convert it to use a JApplet (just drop the AnimationPanel on to it. This is another reason why extending from top level containers is generally discouraged ;)
public class AnimatedBoat {
public static void main(String[] args) {
new AnimatedBoat();
}
public AnimatedBoat() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new AnimationPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class AnimationPane extends JPanel {
private BufferedImage boat;
private int xPos = 0;
private int direction = 1;
public AnimationPane() {
try {
boat = ImageIO.read(new File("boat.png"));
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
xPos += direction;
if (xPos + boat.getWidth() > getWidth()) {
xPos = getWidth() - boat.getWidth();
direction *= -1;
} else if (xPos < 0) {
xPos = 0;
direction *= -1;
}
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return boat == null ? super.getPreferredSize() : new Dimension(boat.getWidth() * 4, boat.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int y = getHeight() - boat.getHeight();
g.drawImage(boat, xPos, y, this);
}
}
}
You need to replace g.drawImage(img2, 200, 200, this); with g.drawImage(img2, x, y, this);
So I'm trying to find a way to modify an image in Java. In other words, if user clicks on the image, a mark will be put at the point where the user just clicked.
I have an ImageIcon which I put in a JLabel.
So far, the approach I took was to use JLayeredPanel to put another JPanel on top of the JLabel and draw on this JPanel:
//...
ImageIcon icon = new ImageIcon("foo.jpg");
JLabel lb = new JLabel(icon);
JPanel glass = new JPanel();
lb.setBounds(0, 0, 100, 100);
glass.setBounds(0, 0, 100, 100);
glass.setOpaque(false);
LayeredPane container = new LayeredPane();
container.add(lb, 1);
container.add(glass, 2);
//...
But this way doesn't seem to work. I never see the background image (the image in lb).
So I was wondering if I'm even on the right track at all? Or is there a cleaner way to achieve this?
There's nothing wrong with using a JLayeredPane or the glass pane for something like this, personally, I find it troublesome, because in a large application, you tend to want to use these layers for any number of things, so it becomes very complicated very fast.
I prefer to keep it "in the family" so to speak...
Personally, I would use a custom component. This isolates the work flow to a very particular location and makes it easier to provide the customisations that you might like...
public class MarkImage {
public static void main(String[] args) {
new MarkImage();
}
public MarkImage() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
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 List<Point> clickPoints;
public TestPane() {
clickPoints = new ArrayList<>(25);
try {
background = ImageIO.read(getClass().getResource("/Miho_Small.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
clickPoints.add(e.getPoint());
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return background == null ? super.getPreferredSize() : new Dimension(background.getWidth(), background.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (background != null) {
int x = (getWidth() - background.getWidth()) / 2;
int y = (getHeight() - background.getHeight()) / 2;
g.drawImage(background, x, y, this);
}
g.setColor(Color.RED);
for (Point p : clickPoints) {
g.fillOval(p.x - 4, p.y - 4, 8, 8);
}
}
}
}
I'd also consider using JXLayer (AKA JLayer in Java 7). This is best described as a glass pane for components (on steroids). Check out How to decorate components for more details...
Updated with JLayer Example
This is an example using Java 7's JLayer. There are some slight differences between JLayer and JXLayer, but it wouldn't take much to convert it...
(Sorry, couldn't resist the temptation of having ago)
public class MarkLayer {
public static void main(String[] args) {
new MarkLayer();
}
public MarkLayer() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
try {
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
JLabel label = new JLabel(new ImageIcon(ImageIO.read(getClass().getResource("/Miho_Small.png"))));
LayerUI<JLabel> layerUI = new MarkLayerUI();
JLayer<JLabel> layer = new JLayer<>(label, layerUI);
frame.add(layer);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (Exception exp) {
exp.printStackTrace();
}
}
});
}
public class MarkLayerUI extends LayerUI<JLabel> {
private Map<JLayer, List<Point>> mapPoints;
public MarkLayerUI() {
mapPoints = new WeakHashMap<>(25);
}
#Override
public void installUI(JComponent c) {
System.out.println("install");
super.installUI(c);
JLayer layer = (JLayer) c;
layer.setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK);
}
#Override
public void uninstallUI(JComponent c) {
super.uninstallUI(c);
mapPoints.remove((JLayer) c);
}
#Override
protected void processMouseEvent(MouseEvent e, JLayer<? extends JLabel> l) {
if (e.getID() == MouseEvent.MOUSE_CLICKED) {
List<Point> points = mapPoints.get(l);
if (points == null) {
points = new ArrayList<>(25);
mapPoints.put(l, points);
}
Point p = e.getPoint();
p = SwingUtilities.convertPoint(e.getComponent(), p, l);
points.add(p);
l.repaint();
}
}
#Override
public void paint(Graphics g, JComponent c) {
Graphics2D g2d = (Graphics2D) g.create();
super.paint(g2d, c);
g2d.setColor(Color.BLUE);
g2d.drawRect(0, 0, c.getWidth() - 1, c.getHeight() - 1);
List<Point> points = mapPoints.get((JLayer) c);
if (points != null && points.size() > 0) {
g2d.setColor(Color.RED);
for (Point p : points) {
g2d.fillOval(p.x - 4, p.y - 4, 8, 8);
}
}
g2d.dispose();
}
}
}
The blue border is renderer as part of the layer, this gives you a guide as to where you can click - I did this for testing and demonstration purposes
You're on the right track with wanting to use another pane. In Java, there actually already is a glass pane that is designed for just this purpose. Read through this tutorial http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html and it should help you understand.
I have a JPanel, and i want to add an image as its background. How can i do that ?
frame = new JFrame("Some frame");
panel1 = new JPanel();
panel1.setBorder(new EmptyBorder(5, 5, 5, 5));
// NEED TO ADD AN IMAGE TO THIS PANEL
panel1.setLayout(cardlayout);
frame.getContentPane().add(panel1);
frame.setLocationByPlatform(true);
frame.setVisible(true);
I need to add an image to the panel and how can i do it ?
UPDATE 1
panel1 = new JPanel()
{
private static final long serialVersionUID = 1L;
#Override
public void paintComponent(Graphics g)
{
g.drawImage(Toolkit.getDefaultToolkit().createImage("1.jpg"), 0, 0, null);
}
};
You need to override the method paintComponent(Graphics g) of JPanel and use drawImage() on the Graphics object g as in this example.
Also, check these two examples by #trashgod:
example.
example.
You have a resource location problem.
Toolkit#createImage may return an empty image if the resource can not be found.
I suggest you use the ImageIO API instead, it supports a wider range of image formats, but will also throw an exception if the image is not found or can not be loaded.
How you load the image will also depend on where the image is.
If the image exists on the file system, you can simply use a File object reference, if the image is an embedded resource (within you application), you will need to use Class#getResource to obtain a URL to it.
public class TestGraphics {
public static void main(String[] args) {
new TestGraphics();
}
public TestGraphics() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new PaintTest());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PaintTest extends JPanel {
private BufferedImage image;
public PaintTest() {
setLayout(new BorderLayout());
try {
// Use this if the image exists within the file system
image = ImageIO.read(new File("/path/to/image/imageName.png"));
// Use this if the image is an embedded resource
// image = ImageIO.read(getClass().getResource("/path/to/resource/imageName.png"));
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return image == null ? super.getPreferredSize() : new Dimension (image.getWidth(), image.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null) {
int x = (getWidth() - image.getWidth()) / 2;
int y = (getHeight()- image.getHeight()) / 2;
g.drawImage(image, x, y, this);
}
}
}
}
I have a Java swing application where I've created an ImageIcon with a picture and displayed it to a screen. I did that by loading a URL as an ImageIcon and placing it in the Java Swing window as a label.
Now I need to place 'markers' on the image with other images.
In context: Place a picture of an eye on someones face over their eye.
I'd appreciate anyone who can point my in the right direction or give me some SSCCE code to work from.
What is the best manner to place 'markers' on an ImageIcon Java Swing?
The basic concept is, you need a temporary image onto which you can paint the master/base image and the marker.
Create a new BufferedImage. This would typically be the same size as the master image, but doesn't have to be.
Paint the master image onto BufferedImage
Paint the marker onto the BufferedImage
Create a new ImageIcon using the BufferedImage
Apply the ImageIcon to the label...
public class PaintIcon {
public static void main(String[] args) {
new PaintIcon();
}
public PaintIcon() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new PaintPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PaintPane extends JPanel {
private JLabel label;
private int state = 0;
private BufferedImage disk;
private BufferedImage play;
private BufferedImage pause;
private BufferedImage stop;
public PaintPane() {
setLayout(new GridBagLayout());
add((label = new JLabel()));
try {
disk = ImageIO.read(getClass().getResource("/cd.png"));
play = ImageIO.read(getClass().getResource("/media_play.png"));
pause = ImageIO.read(getClass().getResource("/media_pause.png"));
stop = ImageIO.read(getClass().getResource("/media_stop.png"));
} catch (Exception e) {
e.printStackTrace();
}
updateState();
label.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
state++;
if (state > 2) {
state = 0;
}
updateState();
}
});
}
protected void updateState() {
BufferedImage base = new BufferedImage(disk.getWidth(), disk.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = base.createGraphics();
g2d.drawImage(disk, 0, 0, this);
BufferedImage marker = null;
switch (state) {
case 0:
marker = stop;
break;
case 1:
marker = play;
break;
case 2:
marker = pause;
break;
}
int x = disk.getWidth() - marker.getWidth();
int y = disk.getHeight() - marker.getHeight();
g2d.drawImage(marker, x, y, this);
g2d.dispose();
label.setIcon(new ImageIcon(base));
}
}
}
I want to make an object to open mouth and close it using two images that switch quickly. I tried with a for loop but it lagged my game.
if(direction == Constant.UP){
ImageIcon i = new ImageIcon("src\\images\\pacman up.png");
image = i.getImage();
ImageIcon i2 = new ImageIcon("src\\images\\pacman left.png");
image = i2.getImage();
}
G.drawImage(image, x, y, 20,20,null);
Any animation in Swing needs to take into consideration the Event Dispatching Thread.
You should NEVER perform any action within the content of the EDT that may block it (such as loops or I/O) as this will prevent the EDT from (amongst other things) processing paint requests.
You should always use a surface capable of supporting double buffer, such as JPanel as this will help eliminate flickering
The following uses a javax.swing.Timer to switch between the two images...
public class TestPacMan {
public static void main(String[] args) {
new TestPacMan();
}
public TestPacMan() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new PacManPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PacManPane extends JPanel {
private BufferedImage pacOpened;
private BufferedImage pacClosed;
private BufferedImage frame;
private boolean opened = true;
public PacManPane() {
try {
pacOpened = ImageIO.read(new File("PC-Closed.png"));
pacClosed = ImageIO.read(new File("PC-Opened.png"));
frame = pacOpened;
} catch (IOException exp) {
exp.printStackTrace();
}
Timer timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
opened = !opened;
frame = opened ? pacOpened : pacClosed;
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (frame != null) {
int x = (getWidth() - frame.getWidth()) / 2;
int y = (getHeight() - frame.getHeight()) / 2;
g2d.drawImage(frame, x, y, this);
}
g2d.dispose();
}
}
}
don't create the icon each time. create the two images at startup and just switch back
and forth at runtime.
if(direction == Constant.UP){
image = open;
}else {
image = closed;
}
G.drawImage(image, x, y, 20,20,null);