I am creating a simple game where a person clicks on an image the score increases by one.
It seems simple enough, right? Here's the catch-- the images will be hidden partially behind other images!
Currently, I'm using several imageIcons to set up my scene. For instance, my foreground has an image "foreground.png," my background is "background.png", and my image that is hiding between the two is "hiding.png".
My first thought was to simply get the coordinates of the imageIcon hiding, add the height() and width() to them, and create a mouse listener that would only work in that specified region. However, that would give me a rectangle for the user to click which would defeat the purpose of hiding the object (someone could click the rigid boundary of the graphic behind the foreground).
Do you have any suggestions on how to make a mouse action listener work only on the VISIBLE pixels of an imageIcon? Yes, I understand that action listeners can only be applied to components (such as buttons) but "the button" just doesn't do what I want for this project.
Example 1
This basically uses a series of JLabels on a JLayeredPane. Each label has it's own mouse listener and when you mouse over it, will turn red. But, if there is a label above it, it won't respond to mouse events...
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
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 javax.imageio.ImageIO;
import javax.swing.Icon;
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 ClickMyImages {
public static void main(String[] args) {
new ClickMyImages();
}
public ClickMyImages() {
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 JLayeredPane {
public TestPane() {
try {
BufferedImage img1 = ImageIO.read("/Image1");
BufferedImage img2 = ImageIO.read("/Image2");
BufferedImage img3 = ImageIO.read("/Image3");
BufferedImage img4 = ImageIO.read("/Image4");
BufferedImage img5 = ImageIO.read("/Image5");
JLabel label1 = new ClickableLabel(new ImageIcon(img1));
JLabel label2 = new ClickableLabel(new ImageIcon(img2));
JLabel label3 = new ClickableLabel(new ImageIcon(img3));
JLabel label4 = new ClickableLabel(new ImageIcon(img4));
JLabel label5 = new ClickableLabel(new ImageIcon(img5));
Dimension masterSize = getPreferredSize();
Dimension size = label1.getPreferredSize();
label1.setBounds((masterSize.width - size.width) / 2, (masterSize.height - size.height) / 2, size.width, size.height);
Point masterPoint = label1.getLocation();
size = label2.getPreferredSize();
label2.setBounds(
masterPoint.x - (size.width / 2),
masterPoint.y - (size.height / 2),
size.width, size.height);
size = label3.getPreferredSize();
label3.setBounds(
masterPoint.x + (size.width / 2),
masterPoint.y - (size.height / 2),
size.width, size.height);
size = label4.getPreferredSize();
label4.setBounds(
masterPoint.x - (size.width / 2),
masterPoint.y + (size.height / 2),
size.width, size.height);
size = label5.getPreferredSize();
label5.setBounds(
masterPoint.x + (size.width / 2),
masterPoint.y + (size.height / 2),
size.width, size.height);
add(label1);
add(label2);
add(label3);
add(label4);
add(label5);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 800);
}
}
// This is for demonstration purposes only!
public class ClickableLabel extends JLabel {
private boolean isIn = false;
public ClickableLabel(Icon image) {
super(image);
addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
isIn = true;
repaint();
}
#Override
public void mouseExited(MouseEvent e) {
isIn = false;
repaint();
}
});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (isIn) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
g2d.setColor(Color.RED);
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.dispose();
}
}
}
}
Example 2
This examples uses the paintComponent method to renderer the images. It checks the pixel alpha of the image at the mouse point to determine if the mouse event should fall through or not.
I've been a little strict using an alpha value of 255, but you could soften it a little based on your needs (something like 225 instead for example)...
I've hard coded the layers so that the tree is always above the squirrel, but it wouldn't be hard to add all the images to List in the order you want them to appear and simple run down the list till you get a hit.
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Composite;
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 ClickMyDrawnImages {
public static void main(String[] args) {
new ClickMyDrawnImages();
}
public ClickMyDrawnImages() {
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 tree;
private BufferedImage squirrel;
private BufferedImage mouseOver;
public TestPane() {
try {
tree = ImageIO.read(new File("Tree.png"));
squirrel = ImageIO.read(new File("Squirrel.png"));
} catch (IOException exp) {
exp.printStackTrace();
}
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
if (withinTree(e.getPoint())) {
mouseOver = tree;
} else if (withinSquirrel(e.getPoint())) {
mouseOver = squirrel;
} else {
mouseOver = null;
}
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected boolean withinTree(Point p) {
return withinBounds(p, getTreeBounds(), tree);
}
protected boolean withinSquirrel(Point p) {
return !withinBounds(p, getTreeBounds(), tree) && withinBounds(p, getSquirrelBounds(), squirrel);
}
protected Rectangle getTreeBounds() {
int width = getWidth();
int height = getHeight();
int x = (width - tree.getWidth()) / 2;
int y = (height - tree.getHeight()) / 2;
return new Rectangle(x, y, tree.getWidth(), tree.getHeight());
}
protected Rectangle getSquirrelBounds() {
Rectangle bounds = getTreeBounds();
return new Rectangle(
bounds.x - (squirrel.getWidth() / 4),
(getHeight() - squirrel.getHeight()) / 2,
squirrel.getWidth(), squirrel.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int width = getWidth();
int height = getHeight();
int x = (width - tree.getWidth()) / 2;
int y = (height - tree.getHeight()) / 2;
g.drawImage(highlight(squirrel), x - (squirrel.getWidth() / 4), (height - squirrel.getHeight()) / 2, this);
g2d.drawImage(highlight(tree), x, y, this);
g2d.dispose();
}
protected BufferedImage highlight(BufferedImage img) {
BufferedImage highlight = img;
if (img.equals(mouseOver)) {
highlight = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = highlight.createGraphics();
g2d.setColor(Color.RED);
g2d.drawImage(img, 0, 0, this);
g2d.setComposite(AlphaComposite.SrcAtop.derive(0.5f));
g2d.fillRect(0, 0, highlight.getWidth(), highlight.getHeight());
g2d.dispose();
}
return highlight;
}
protected boolean withinBounds(Point p, Rectangle bounds, BufferedImage image) {
boolean withinBounds = false;
if (bounds.contains(p)) {
int x = p.x - bounds.x;
int y = p.y - bounds.y;
int pixel = image.getRGB(x, y);
int a = (pixel >> 24) & 0xFF;
// could use a little weighting, so translucent pixels can be effected
if (a == 255) {
withinBounds = true;
}
}
return withinBounds;
}
}
}
Related
I'm creating a 2D topdown shooter game with Java Swing in which I want circular hitboxes for my player and enemies as well as projectiles. For hit detection I need to figure out if there is an intersection between a projtile and a Sprite (player or enemy). My issue is that Ellipse2D's intersect function (that takes a position a width and height) creates a Rectangle out of the arguments. In its description it advises using Area for high precision and I was hoping it had an intersect function for any shape but that also casts its argument to a Rectangle.
Here's the jist of my Sprite object:
public class Sprite {
protected float worldX;
protected float worldY;
protected float drawX;
protected float drawY;
protected int width;
protected int height;
protected Image image;
...
}
In essence I'm storing their x and y coordinates as well as their width and height.(drawX and drawY are only used for rendering)
Is there a build-in method (preferably in Swing) to intersect Ellipses with other shapes (specifically other Ellipses and Rectangles) or is there no better option then implementing these by hand?
With a simple modification to the answer form Detecting collision of two sprites that can rotate
You can end up with something like...
import java.awt.Color;
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.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
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 Ellipse2D rect01;
private Rectangle rect02;
private int angle = 0;
public TestPane() {
rect01 = new Ellipse2D.Double(0, 0, 200, 50);
rect02 = new Rectangle(0, 0, 100, 100);
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
angle++;
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(250, 250);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int width = getWidth();
int height = getHeight();
AffineTransform at = new AffineTransform();
int center = width / 2;
int x = center + (center - rect01.getBounds().width) / 2;
int y = (height - rect01.getBounds().height) / 2;
at.translate(x, y);
at.rotate(Math.toRadians(angle), rect01.getBounds().width / 2, rect01.getBounds().height / 2);
GeneralPath path1 = new GeneralPath();
path1.append(rect01.getPathIterator(at), true);
g2d.fill(path1);
g2d.setColor(Color.BLUE);
g2d.draw(path1.getBounds());
at = new AffineTransform();
x = (center - rect02.width) / 2;
y = (height - rect02.height) / 2;
at.translate(x, y);
at.rotate(Math.toRadians(-angle), rect02.width / 2, rect02.height / 2);
GeneralPath path2 = new GeneralPath();
path2.append(rect02.getPathIterator(at), true);
g2d.fill(path2);
g2d.setColor(Color.BLUE);
g2d.draw(path2.getBounds());
Area a1 = new Area(path1);
Area a2 = new Area(path2);
a2.intersect(a1);
if (!a2.isEmpty()) {
g2d.setColor(Color.RED);
g2d.fill(a2);
}
g2d.dispose();
}
}
}
I am trying to learn how to fade in and out images into another image or from another image. So, if I have 2 images, and 1 is being displayed at the moment, I want to display another image in the background and fade the first image out into the 2nd image. OR, I want to set the focus on the new image and slowly fade it in over the 1st image, then stop displaying the 1st one.
I'm not sure how:
to set focus, if even needed.
I can fade in if I change the alpha to 0 and increment up and only draw one image, however I cannot get it to fade out either with any variation of this code. (i.e. commenting out one image to draw).
Edit: Really, all I'm worried about is being able to have 2 images and make the image currently being displayed slowly disappear into the 2nd image. How that is accomplished doesn't need to be with this.
Here is a code sample I'm messing with:
import java.awt.AlphaComposite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class FadeIn extends JPanel implements ActionListener {
private Image imagem;
private Image image2;
private Timer timer;
private float alpha = 1f;
public FadeIn() {
imagem = (new ImageIcon(getClass().getResource(
"/resources/1stImage.jpg"))).getImage();
image2 = (new ImageIcon(getClass().getResource(
"/resources/2ndImage.jpg"))).getImage();
timer = new Timer(20, this);
timer.start();
}
// here you define alpha 0f to 1f
public FadeIn(float alpha) {
imagem = (new ImageIcon(getClass().getResource(
"/resources/1stImage.jpg"))).getImage();
this.alpha = alpha;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(imagem, 0, 0, 400, 300, null);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
alpha));
g2d.drawImage(image2, 0, 0, 400, 300, null);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Fade out");
frame.add(new FadeIn());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(420, 330);
// frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
alpha += -0.01f;
if (alpha <= 0) {
alpha = 0;
timer.stop();
}
repaint();
}
}
Basically, what this does is use the same alpha value, fading in from 0-1 and then using the same alpha, going from 1-0, allowing the two images to cross fade over each other...
The magic basically, happens in the paintComponent, where the image coming in using the alpha value and the outgoing image uses 1f - alpha.
Switching between the two images is actually a the same process, expect the inImage is swapped for the outImage
The timing is little different. Instead of a straight move from 0-1 using a standard delta (ie 0.01 for example), this uses a time based algorithm.
That is, I use a timer which ticks every 40 milliseconds or so, it then does a calculation based on the amount of time the timer has being running and calculates the alpha value accordingly...
This allows you to change the amount of time the animation will take, but also provides a slightly better algorithm that takes into account the passive nature of Swings rendering engine...
import java.awt.AlphaComposite;
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.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.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class FadeImage {
public static void main(String[] args) {
new FadeImage();
}
public FadeImage() {
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 static class TestPane extends JPanel {
public static final long RUNNING_TIME = 2000;
private BufferedImage inImage;
private BufferedImage outImage;
private float alpha = 0f;
private long startTime = -1;
public TestPane() {
try {
inImage = ImageIO.read(new File("/path/to/inImage"));
outImage = ImageIO.read(new File("/path/to/outImage"));
} catch (IOException exp) {
exp.printStackTrace();
}
final Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (startTime < 0) {
startTime = System.currentTimeMillis();
} else {
long time = System.currentTimeMillis();
long duration = time - startTime;
if (duration >= RUNNING_TIME) {
startTime = -1;
((Timer) e.getSource()).stop();
alpha = 0f;
} else {
alpha = 1f - ((float) duration / (float) RUNNING_TIME);
}
repaint();
}
}
});
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
alpha = 0f;
BufferedImage tmp = inImage;
inImage = outImage;
outImage = tmp;
timer.start();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(
Math.max(inImage.getWidth(), outImage.getWidth()),
Math.max(inImage.getHeight(), outImage.getHeight()));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(alpha));
int x = (getWidth() - inImage.getWidth()) / 2;
int y = (getHeight() - inImage.getHeight()) / 2;
g2d.drawImage(inImage, x, y, this);
g2d.setComposite(AlphaComposite.SrcOver.derive(1f - alpha));
x = (getWidth() - outImage.getWidth()) / 2;
y = (getHeight() - outImage.getHeight()) / 2;
g2d.drawImage(outImage, x, y, this);
g2d.dispose();
}
}
}
This is a easy and short most developers using java code for image fade.
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
/**
*
* #author ADMIN
*/
public class ImageFade extends JFrame {
ImageFade() {
setLayout(null);
JLabel l = new JLabel();
l.setBounds(0, 0, 100, 96);
add(l);
Thread tp = new Thread() {
#Override
public void run() {
for (int amp = 0; amp <= 500; amp++) {
try {
sleep(1);
try {
BufferedImage bim = ImageIO.read(new File("src/image/fade/image.png"));
BufferedImage nbim = new BufferedImage(bim.getWidth(), bim.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D createGraphics = nbim.createGraphics();
createGraphics.drawImage(bim, null, 0, 0);
RescaleOp r = new RescaleOp(new float[]{1f, 1f, 1f, (float) amp / 500}, new float[]{0, 0, 0, 0}, null);
BufferedImage filter = r.filter(nbim, null);
l.setIcon(new ImageIcon(filter));
} catch (Exception ex) {
System.err.println(ex);
}
} catch (InterruptedException ex) {
}
}
}
};
tp.start();
setUndecorated(true);
setBackground(new Color(0, 0, 0, 0));
setSize(100, 96);
setVisible(true);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
setAlwaysOnTop(true);
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
ImageFade fr = new ImageFade();
}
}
in this code you can see a thread code. in the thread this image will fade in.
the used image is stack overflow web page's logo image.
only by shown code the image will fade in.
Thread tp = new Thread() {
#Override
public void run() {
for (int amp = 0; amp <= 500; amp++) {
try {
sleep(1);
try {
BufferedImage bim = ImageIO.read(new File("src/image/fade/image.png"));
BufferedImage nbim = new BufferedImage(bim.getWidth(), bim.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D createGraphics = nbim.createGraphics();
createGraphics.drawImage(bim, null, 0, 0);
RescaleOp r = new RescaleOp(new float[]{1f, 1f, 1f, (float) amp / 500}, new float[]{0, 0, 0, 0}, null);
BufferedImage filter = r.filter(nbim, null);
l.setIcon(new ImageIcon(filter));
} catch (Exception ex) {
System.err.println(ex);
}
} catch (InterruptedException ex) {
}
}
}
};
tp.start();
This code is very simple to use.
This is not from any book, internet or etc. It is developed by me.
A normal image is not able to change alpha. By code : BufferedImage nbim = new BufferedImage(bim.getWidth(), bim.getHeight(), BufferedImage.TYPE_INT_ARGB); the image will convert to ARGB - Alpha, Red, Green, Blue (R,G,B,A) image.
So you can change the alpha of a image.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 9 years ago.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Improve this question
Is there any way to create a dynamic Zoom Box in Java which will include e. g. 20x20pix area around the cursor (but even when cursor will move beyond the Frame of app) and which will be shown for example in a small JPanel?
I'm asking in context of a Color Chooser program. The last functionality need to be implemented is just that Zoom Box.
I'm sure there are a number of different ways that this could be achieved.
This basically uses a separate component, which acts as the "zoom box". You supply it a component that you want to "zoom" on. It adds a mouse listener so it can monitor mouse motion events and enter and exit events.
These are used to determine when the "popup" window should be shown, where the popup window should be shown and the area that should be "painted".
This uses the "component to be zoomed" paint method to paint a region to of it to a backing buffer, which is then scaled and painted to the "zoom box"...simple
I've not played around with the zoom factor, so there may still be some quirks, but you should get the basic idea...
While I've presented a image to act as the background, this should work on any component
import java.awt.BorderLayout;
import java.awt.Color;
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.geom.AffineTransform;
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.JPanel;
import javax.swing.JWindow;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ZoomBoxWindow {
public static void main(String[] args) {
new ZoomBoxWindow();
}
public ZoomBoxWindow() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
TestPane pane = new TestPane();
ZoomPane zoomPane = new ZoomPane(pane);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(pane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class ZoomPane extends JPanel {
protected static final int ZOOM_AREA = 40;
private JComponent parent;
private JWindow popup;
private BufferedImage buffer;
private float zoomLevel = 2f;
public ZoomPane(JComponent parent) {
this.parent = parent;
popup = new JWindow();
popup.setLayout(new BorderLayout());
popup.add(this);
popup.pack();
MouseAdapter ma = new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
Point p = e.getPoint();
Point pos = e.getLocationOnScreen();
updateBuffer(p);
popup.setLocation(pos.x + 16, pos.y + 16);
repaint();
}
#Override
public void mouseEntered(MouseEvent e) {
popup.setVisible(true);
}
#Override
public void mouseExited(MouseEvent e) {
popup.setVisible(false);
}
};
parent.addMouseListener(ma);
parent.addMouseMotionListener(ma);
}
protected void updateBuffer(Point p) {
int width = Math.round(ZOOM_AREA);
int height = Math.round(ZOOM_AREA);
buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = buffer.createGraphics();
AffineTransform at = new AffineTransform();
int xPos = (ZOOM_AREA / 2) - p.x;
int yPos = (ZOOM_AREA / 2) - p.y;
if (xPos > 0) {
xPos = 0;
}
if (yPos > 0) {
yPos = 0;
}
if ((xPos * -1) + ZOOM_AREA > parent.getWidth()) {
xPos = (parent.getWidth() - ZOOM_AREA) * -1;
}
if ((yPos * -1) + ZOOM_AREA > parent.getHeight()) {
yPos = (parent.getHeight()- ZOOM_AREA) * -1;
}
at.translate(xPos, yPos);
g2d.setTransform(at);
parent.paint(g2d);
g2d.dispose();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(Math.round(ZOOM_AREA * zoomLevel), Math.round(ZOOM_AREA * zoomLevel));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (buffer != null) {
AffineTransform at = g2d.getTransform();
g2d.setTransform(AffineTransform.getScaleInstance(zoomLevel, zoomLevel));
g2d.drawImage(buffer, 0, 0, this);
g2d.setTransform(at);
}
g2d.setColor(Color.RED);
g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
g2d.dispose();
}
}
public class TestPane extends JPanel {
private BufferedImage img;
public TestPane() {
try {
img = ImageIO.read(new File("/path/to/your/image"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(), img.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
g2d.dispose();
}
}
}
}
Updated with "screen" version
This version will allow you to display a "zoom window" any where on the screen.
This has a minor issue in the fact that you need to hide the zoom window before you capture the screen, then re-show it.
I might be tempted to change the process so that when the updateBuffer method detected that the mouse position hadn't changed, it updated the buffer and showed the zoom window. When the mouse position changes, it would hide the window again...but that's me ;)
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.swing.Action;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import static zoomboxwindow.ZoomBoxWindow.ZoomPane.ZOOM_AREA;
public class GlobalZoomBox {
public static void main(String[] args) {
new GlobalZoomBox();
}
public GlobalZoomBox() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Zoomer zoomer = new Zoomer();
zoomer.setZoomWinodwVisible(true);
}
});
}
public class Zoomer extends JPanel {
protected static final int ZOOM_AREA = 40;
private JWindow popup;
private BufferedImage buffer;
private Robot bot;
private float zoomLevel = 2f;
private Point lastPoint;
private final Timer timer;
public Zoomer() {
popup = new JWindow();
popup.setLayout(new BorderLayout());
popup.add(this);
popup.pack();
try {
bot = new Robot();
} catch (AWTException ex) {
ex.printStackTrace();
}
timer = new Timer(125, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
updateBuffer();
}
});
timer.setCoalesce(true);
timer.setInitialDelay(0);
}
public void setZoomWinodwVisible(boolean value) {
if (value && !popup.isVisible()) {
timer.start();
popup.setVisible(true);
} else {
timer.stop();
popup.setVisible(false);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(Math.round(ZOOM_AREA * zoomLevel), Math.round(ZOOM_AREA * zoomLevel));
}
protected void updateBuffer() {
if (bot != null) {
PointerInfo info = MouseInfo.getPointerInfo();
Point p = info.getLocation();
if (lastPoint == null || !lastPoint.equals(p)) {
int x = p.x - (ZOOM_AREA / 2);
int y = p.y - (ZOOM_AREA / 2);
popup.setLocation(p.x + 16, p.y + 16);
popup.setVisible(false);
buffer = bot.createScreenCapture(new Rectangle(x, y, ZOOM_AREA, ZOOM_AREA));
popup.setVisible(true);
lastPoint = p;
repaint();
}
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (buffer != null) {
AffineTransform at = g2d.getTransform();
g2d.setTransform(AffineTransform.getScaleInstance(zoomLevel, zoomLevel));
g2d.drawImage(buffer, 0, 0, this);
g2d.setTransform(at);
}
g2d.setColor(Color.RED);
g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
g2d.dispose();
}
}
}
Updated with "tooltip" style popup
The main problems with the second example is the fact that you need to hide the popup in order to grab a screen shoot. This is done to prevent the popup from begin captured as well. This makes the popup "flash" every time the mouse is moved.
You "could" get around this ensuring the popup is positioned out side the range of the capture, but as you increase the capture area, the popup will move further away from the cursor.
This would, of course, be a great solution for fixed position display (ie, you had a panel fixed on a JFrame instead of a floating box)
This is an additional update that uses a second timer to display the zoom box after the user has stopped moving the mouse.
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.swing.Action;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import static zoomboxwindow.ZoomBoxWindow.ZoomPane.ZOOM_AREA;
public class GlobalZoomBox {
public static void main(String[] args) {
new GlobalZoomBox();
}
public GlobalZoomBox() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Zoomer zoomer = new Zoomer();
zoomer.setZoomWinodwVisible(true);
}
});
}
public class Zoomer extends JPanel {
protected static final int ZOOM_AREA = 80;
private JWindow popup;
private BufferedImage buffer;
private Robot bot;
private float zoomLevel = 2f;
private Point lastPoint;
private final Timer timer;
private final Timer popupTimer;
public Zoomer() {
popup = new JWindow();
popup.setLayout(new BorderLayout());
popup.add(this);
popup.pack();
try {
bot = new Robot();
} catch (AWTException ex) {
ex.printStackTrace();
}
timer = new Timer(125, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
updateBuffer();
}
});
timer.setCoalesce(true);
timer.setInitialDelay(0);
popupTimer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (lastPoint != null) {
System.out.println("lastPoint = " + lastPoint);
popup.setVisible(false);
Point p = lastPoint;
int x = p.x - (ZOOM_AREA / 2);
int y = p.y - (ZOOM_AREA / 2);
popup.setLocation(p.x + 16, p.y + 16);
buffer = bot.createScreenCapture(new Rectangle(x, y, ZOOM_AREA, ZOOM_AREA));
repaint();
popup.setVisible(true);
}
}
});
popupTimer.setRepeats(false);
}
public void setZoomWinodwVisible(boolean value) {
if (value && !popup.isVisible()) {
timer.start();
popup.setVisible(true);
} else {
timer.stop();
popup.setVisible(false);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(Math.round(ZOOM_AREA * zoomLevel), Math.round(ZOOM_AREA * zoomLevel));
}
protected void updateBuffer() {
if (bot != null) {
PointerInfo info = MouseInfo.getPointerInfo();
Point p = info.getLocation();
if (lastPoint == null || !lastPoint.equals(p)) {
lastPoint = p;
popupTimer.stop();
popup.setVisible(false);
} else {
if (!popup.isVisible()) {
popupTimer.start();
}
}
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (buffer != null) {
AffineTransform at = g2d.getTransform();
g2d.setTransform(AffineTransform.getScaleInstance(zoomLevel, zoomLevel));
g2d.drawImage(buffer, 0, 0, this);
g2d.setTransform(at);
}
g2d.setColor(Color.RED);
g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
g2d.dispose();
}
}
}
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.*;
class ZoomOnMouse {
public static void main(String[] args) throws AWTException {
final Robot robot = new Robot();
Runnable r = new Runnable() {
#Override
public void run() {
final int size = 256;
final BufferedImage bi = new BufferedImage(
size, size, BufferedImage.TYPE_INT_RGB);
final JLabel gui = new JLabel(new ImageIcon(bi));
ActionListener zoomListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
PointerInfo pi = MouseInfo.getPointerInfo();
Point p = pi.getLocation();
BufferedImage temp = robot.createScreenCapture(
new Rectangle(p.x-(size/4), p.y-(size/4),
(size/2), (size/2)));
Graphics g = bi.getGraphics();
g.drawImage(temp, 0, 0, size, size, null);
g.dispose();
gui.repaint();
}
};
Timer t = new Timer(40, zoomListener);
t.start();
JOptionPane.showMessageDialog(null, gui);
t.stop();
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(r);
}
}
I want to do something best explained by this picture:
In words, i need to right-down part of picture into left-top part of jpanel, i have tried setting x and y to negative, but with no succes, the image is just not displayed at all. It there a simple way to do this?
I am currently using
g.drawImage(img, x, y, null)
//x and y are negative
to draw it.
I would verify you x/y position is being calculated correctly and add a ImageObserver reference to your g.drawImage if you're painting to the screen
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
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 NegativeImage {
public static void main(String[] args) {
new NegativeImage();
}
public NegativeImage() {
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 img;
public TestPane() {
try {
img = ImageIO.read(new File("/Users/swhitehead/Dropbox/MegaTokyo/Evil_Small.jpg"));
} catch (IOException ex) {
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight()- img.getHeight()) / 2;
// Center...
g.drawImage(img, x, y, this);
// Off to the left...
x = -(img.getWidth() / 2);
g.drawImage(img, x, y, this);
// Off to the right...
x = getWidth() - (img.getWidth() / 2);
g.drawImage(img, x, y, this);
}
}
}
I want to make a directed line and make it move. I am able to make a directed line and move the line but the arrow get displaced while i move the line
This is my paint method
Line2D.Double line = new Line2D.Double(startX, startY, endX, endY);
g2d.draw(line);
tx.setToIdentity();
double angle = Math.atan2(line.y2 - line.y1, line.x2 - line.x1);
tx.translate(line.x2, line.y2);
tx.rotate((angle - Math.PI / 2d));
Graphics2D gClone = (Graphics2D) g2d.create();
gClone.setTransform(tx);
Polygon arrowHead = new Polygon();
arrowHead.addPoint(0, 15);
arrowHead.addPoint(-15, -15);
arrowHead.addPoint(15, -15);
Area area = new Arear(arrowHead );
Area lineArea = new Area(line);
lineArea.subtract(area);
gClone.fill(area);
gClone.dispose();
and i have change the value of startx and start y at mouse pressedd
and endx and enny at mouse drag
This is a basic example that demonstrates the use of a Path2D, to define a custom shape and an AffineTransformation to transform the shape.
This example will cause the arrow to point towards the mouse as it moves over the panel
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
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.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class RotateArrow {
public static void main(String[] args) {
new RotateArrow();
}
public RotateArrow() {
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 RotatePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class RotatePane extends javax.swing.JPanel {
private Point mousePoint;
private PointyThing pointyThing;
public RotatePane() {
pointyThing = new PointyThing();
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
mousePoint = e.getPoint();
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double rotation = 0f;
int width = getWidth() - 1;
int height = getHeight() - 1;
if (mousePoint != null) {
int x = width / 2;
int y = height / 2;
int deltaX = mousePoint.x - x;
int deltaY = mousePoint.y - y;
rotation = -Math.atan2(deltaX, deltaY);
rotation = Math.toDegrees(rotation) + 180;
}
Rectangle bounds = pointyThing.getBounds();
AffineTransform at = new AffineTransform();
at.translate((width - bounds.width) / 2, (height - bounds.height) / 2);
at.rotate(Math.toRadians(rotation), bounds.width / 2, bounds.height / 2);
Shape shape = new Path2D.Float(pointyThing, at);
g2d.setStroke(new BasicStroke(3));
g2d.setColor(Color.RED);
g2d.fill(shape);
g2d.draw(shape);
g2d.dispose();
}
}
public class PointyThing extends Path2D.Float {
public PointyThing() {
moveTo(15, 0);
lineTo(30, 15);
lineTo(0, 15);
lineTo(15, 0);
moveTo(15, 15);
lineTo(15, 60);
}
}
}
Update with example two
Basically, this uses the PointyThing as the arrow head only, and draws the line separately.
The arrow is orientated so it will point down the line (towards the mouse)
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
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.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class RotateArrow {
public static void main(String[] args) {
new RotateArrow();
}
public RotateArrow() {
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 RotatePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class RotatePane extends javax.swing.JPanel {
private PointyThing pointyThing;
private Point mouseStart;
private Point mouseEnd;
public RotatePane() {
pointyThing = new PointyThing();
MouseAdapter ma = new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
mouseEnd = e.getPoint();
repaint();
}
#Override
public void mouseClicked(MouseEvent e) {
mouseStart = e.getPoint();
repaint();
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (mouseStart != null && mouseEnd != null) {
double rotation = 0f;
int width = getWidth() - 1;
int height = getHeight() - 1;
if (mouseEnd != null) {
int x = mouseStart.x;
int y = mouseStart.y;
int deltaX = mouseEnd.x - x;
int deltaY = mouseEnd.y - y;
rotation = -Math.atan2(deltaX, deltaY);
rotation = Math.toDegrees(rotation) + 180;
}
Rectangle bounds = pointyThing.getBounds();
g2d.setStroke(new BasicStroke(3));
g2d.setColor(Color.RED);
g2d.draw(new Line2D.Float(mouseStart, mouseEnd));
AffineTransform at = new AffineTransform();
at.translate(mouseEnd.x - (bounds.width / 2), mouseEnd.y - (bounds.height / 2));
at.rotate(Math.toRadians(rotation), bounds.width / 2, bounds.height / 2);
Shape shape = new Path2D.Float(pointyThing, at);
g2d.fill(shape);
g2d.draw(shape);
}
g2d.dispose();
}
}
public class PointyThing extends Path2D.Float {
public PointyThing() {
moveTo(15, 0);
lineTo(30, 15);
lineTo(0, 15);
lineTo(15, 0);
}
}
}