I got a class with a resizable background. There are paintings over that background(using a paint method and Java2D).
How can i delete everything that was drawn every time that the background gets a resize? (To eventually draw again in the correct places) Is there any sort of transform i can do on the already-drawn objects(like scaling to fit the image again)?
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
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.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Background extends JLabel implements ChangeListener {
private ImageIcon background;
private BufferedImage image;
public Background(JPanel parent){
super();
parent.add(this);
try {
image = ImageIO.read(new File("/example/background"));
} catch (IOException e) {
e.printStackTrace();
}
this.background = new ImageIcon(image);
this.setIcon(background);
}
public void stateChanged(ChangeEvent e) {
int value = ((JSlider) e.getSource()).getValue();
double scale = value / 100.0;
BufferedImage scaled = getScaledImage(scale);
this.setIcon(new ImageIcon(scaled));
this.revalidate();
}
private BufferedImage getScaledImage(double scale) {
int w = (int) (scale * image.getWidth());
int h = (int) (scale * image.getHeight());
BufferedImage bi = new BufferedImage(w, h, image.getType());
Graphics2D g2 = bi.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BICUBIC);
AffineTransform at = AffineTransform.getScaleInstance(scale, scale);
g2.drawRenderedImage(image, at);
g2.dispose();
return bi;
}
#Override
public void paint(Graphics g){
super.paint(g);
Graphics2D graphObj = (Graphics2D) g;
RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);rh.put(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
graphObj.setRenderingHints(rh);
graphObj.fillOval(500, 500, 20, 20);
graphObj.finalize();
}
}
Consider:
Drawing in a paintComponent(...) override, not a paint(...) override.
Save a List<Point> where each Point is normalized, say to a 1000 by 1000 size.
Then in the paintComponent method, iterate through each Point in a for loop, scaling it to the current component size, and drawing it.
You'll want to scale any image drawn in the component in a ComponentListener, and then call repaint().
Or perhaps even better, scale the image drawn using the Graphics#drawImage(...) overload that takes width and height parameters.
e.g.,
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class MyBackground extends JPanel {
private BufferedImage img;
public MyBackground(BufferedImage img) {
this.img = img;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
}
}
private static void createAndShowGui() {
String comfyChair = "https://duke.kenai.com/comfyChair/ComfyChairRad.png";
BufferedImage img;
try {
URL url = new URL(comfyChair);
img = ImageIO.read(url);
MyBackground mainPanel = new MyBackground(img);
JFrame frame = new JFrame("MyBackground");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
example 2:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.*;
public class MyBackground extends JPanel {
public static final double NORM_CONST = 1.0;
private BufferedImage img;
private List<List<Point2D>> normalizedPoints = new ArrayList<List<Point2D>>();
private List<Point2D> pointSubList;
public MyBackground(BufferedImage img) {
this.img = img;
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
}
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (List<Point2D> pointList : normalizedPoints) {
if (pointList.size() > 1) {
for (int i = 1; i < pointList.size(); i++) {
Point p1 = deNormalize(pointList.get(i - 1));
Point p2 = deNormalize(pointList.get(i));
g2.drawLine(p1.x, p1.y, p2.x, p2.y);
}
}
}
if (pointSubList != null && pointSubList.size() > 1) {
for (int i = 1; i < pointSubList.size(); i++) {
Point p1 = deNormalize(pointSubList.get(i - 1));
Point p2 = deNormalize(pointSubList.get(i));
g2.drawLine(p1.x, p1.y, p2.x, p2.y);
}
}
}
private Point deNormalize(Point2D p2d) {
int x = (int) (p2d.getX() * getWidth() / NORM_CONST);
int y = (int) (p2d.getY() * getHeight() / NORM_CONST);
return new Point(x, y);
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
Point2D p = normalizePoint(e.getPoint());
pointSubList = new ArrayList<>();
pointSubList.add(p);
}
#Override
public void mouseReleased(MouseEvent e) {
Point2D p = normalizePoint(e.getPoint());
pointSubList.add(p);
normalizedPoints.add(pointSubList);
pointSubList = null;
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
Point2D p = normalizePoint(e.getPoint());
pointSubList.add(p);
repaint();
}
private Point2D normalizePoint(Point point) {
double x = (NORM_CONST * point.x) / getWidth();
double y = (NORM_CONST * point.y) / getHeight();
Point2D result = new Point2D.Double(x, y);
return result;
}
}
private static void createAndShowGui() {
String comfyChair = "https://duke.kenai.com/comfyChair/ComfyChairRad.png";
BufferedImage img;
try {
URL url = new URL(comfyChair);
img = ImageIO.read(url);
MyBackground mainPanel = new MyBackground(img);
JFrame frame = new JFrame("MyBackground");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Related
I'm trying to draw rectangles on fairly large images in order to get the pixel coordinates of objects within the image. I am able to display the image and make it scrollable, or display the image and be able to draw rectangles on top of it....but not both.
It's obvious that I'm drawing the image on top of the canvas that I'm trying to draw the rectangles on, but I can't for the life of me figure out how to make it all coexist.
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
public class DrawRect extends JPanel {
int x, y, x2, y2;
private static final long serialVersionUID = 1L;
private BufferedImage image;
private JPanel canvas;
public static void main(String[] args) {
JPanel p = new DrawRect();
JFrame f = new JFrame();
f.setContentPane(p);
f.setSize(400, 300);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
DrawRect() {
x = y = x2 = y2 = 0; //
MyMouseListener listener = new MyMouseListener();
addMouseListener(listener);
addMouseMotionListener(listener);
try {
this.image = ImageIO.read(new URL("https://previews.123rf.com/images/victoroancea/victoroancea1201/victoroancea120100059/12055848-tv-color-test-pattern-test-card-for-pal-and-ntsc.jpg"));
}catch(IOException ex) {
Logger.getLogger(DrawRect.class.getName()).log(Level.SEVERE, null, ex);
}
this.canvas = new JPanel() {
private static final long serialVersionUID = 1L;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
}
};
canvas.setPreferredSize(new Dimension(image.getWidth(), image.getHeight()));
JScrollPane sp = new JScrollPane(canvas);
setLayout(new BorderLayout());
add(sp, BorderLayout.CENTER);
}
public void setStartPoint(int x, int y) {
this.x = x;
this.y = y;
}
public void setEndPoint(int x, int y) {
x2 = (x);
y2 = (y);
}
public void drawRect(Graphics g, int x, int y, int x2, int y2) {
int px = Math.min(x,x2);
int py = Math.min(y,y2);
int pw=Math.abs(x-x2);
int ph=Math.abs(y-y2);
g.drawRect(px, py, pw, ph);
}
class MyMouseListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
setStartPoint(e.getX(), e.getY());
}
public void mouseDragged(MouseEvent e) {
setEndPoint(e.getX(), e.getY());
repaint();
}
public void mouseReleased(MouseEvent e) {
setEndPoint(e.getX(), e.getY());
repaint();
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
drawRect(g, x, y, x2, y2);
}
}
Your image-drawing JPanel must be the same JPanel that draws the rectangle and that has the MouseAdapter added to it. For instance:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Image;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
#SuppressWarnings("serial")
public class DrawRect2 extends JPanel {
public static final String IMG_PATH = "https://previews.123rf.com/images/victoroancea"
+ "/victoroancea1201/victoroancea120100059"
+ "/12055848-tv-color-test-pattern-test-card-for-pal-and-ntsc.jpg";
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private DrawingPanel drawingPanel;
public DrawRect2(Image img) {
drawingPanel = new DrawingPanel(img);
JScrollPane scrollPane = new JScrollPane(drawingPanel);
MyMouse myMouse = new MyMouse();
drawingPanel.addMouseListener(myMouse);
drawingPanel.addMouseMotionListener(myMouse);
setLayout(new BorderLayout());
add(scrollPane);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
Image img = null;
try {
URL url = new URL(IMG_PATH);
img = ImageIO.read(url);
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
DrawRect2 mainPanel = new DrawRect2(img);
JFrame frame = new JFrame("DrawRect2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class DrawingPanel extends JPanel {
private Image img;
private Rectangle rectangle;
public DrawingPanel(Image img) {
this.img = img;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
if (rectangle != null) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setXORMode(Color.WHITE);
g2.draw(rectangle);
g2.dispose(); // since we created this object
}
}
#Override
public Dimension getPreferredSize() {
Dimension superSize = super.getPreferredSize();
if (img == null) {
return super.getPreferredSize();
} else {
int w = img.getWidth(this);
int h = img.getHeight(this);
return new Dimension(w, h);
}
}
public void setRectangle(Rectangle rectangle) {
this.rectangle = rectangle;
}
}
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class MyMouse extends MouseAdapter {
private Point p1;
#Override
public void mousePressed(MouseEvent e) {
p1 = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e) {
if (p1 != null) {
createRect(e);
}
}
private void createRect(MouseEvent e) {
Point p2 = e.getPoint();
int x = Math.min(p1.x, p2.x);
int y = Math.min(p1.y, p2.y);
int width = Math.abs(p1.x - p2.x);
int height = Math.abs(p1.y - p2.y);
Rectangle r = new Rectangle(x, y, width, height);
((DrawingPanel) e.getSource()).setRectangle(r);
((DrawingPanel) e.getSource()).repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
if (p1 != null) {
createRect(e);
}
p1 = null;
}
}
So in this paintComponent method, I draw both the image and the Rectangle, using Graphics2D XOR mode to help show the lines regardless of the background color:
#SuppressWarnings("serial")
public class DrawingPanel extends JPanel {
private Image img;
private Rectangle rectangle;
public DrawingPanel(Image img) {
this.img = img;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
if (rectangle != null) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setXORMode(Color.WHITE);
g2.draw(rectangle);
g2.dispose(); // since we created this object
}
}
I also have this method:
public void setRectangle(Rectangle rectangle) {
this.rectangle = rectangle;
}
To allow the MouseListener/Adapter to pass in the Rectangle into this JPanel.
Rectangle r = new Rectangle(x, y, width, height);
((DrawingPanel) e.getSource()).setRectangle(r);
((DrawingPanel) e.getSource()).repaint();
I would like to plot some points from a given wkt file, but because of their closeness I only can display a heap of ovals that are overlapped.
The points differ only in their decimal places:
POINT (3346349.958 5642197.806)
POINT (3346349.313 5642199.622)
POINT (3346349.237 5642201.918)
POINT (3346349.734 5642204.058)
POINT (3346351.746 5642205.777)
POINT (3346351.636 5642210.304)
POINT (3346349.335 5642216.518)
POINT (3346347.326 5642221.15)
POINT (3346347.365 5642223.671)
POINT (3346351.577 5642195.711)
etc...
First I tried to plot the points, but as I have mentioned all points are seemingly displayed at the same place.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
import com.vividsolutions.jts.io.ParseException;
public class Display extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
private int width;
private int height;
private WKTGrabsteine p = new WKTGrabsteine();
public Display() {
setLayout(null);
width = 0;
height = 0;
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.WHITE);
Graphics2D g2 = (Graphics2D) g;
g2.translate(height, width);
try {
for (int point = 0; point < p.geoCoordinates().size(); point++) {
Ellipse2D shape = new Ellipse2D.Double(p.geoCoordinates().get(point).getX() / 1000000 + 400,
p.geoCoordinates().get(point).getY() / 1000000 + 100, 5, 5);
g2.draw(shape);
}
} catch (IOException | ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
However I thought that the solution could lie in rescaling the coordinate system, which I tried to transform by Affinetransform and .scale()
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
import com.vividsolutions.jts.io.ParseException;
public class Display extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
private int width;
private int height;
private WKTGrabsteine p = new WKTGrabsteine();
public Display() {
setLayout(null);
width = 0;
height = 0;
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.WHITE);
Graphics2D g2 = (Graphics2D) g;
AffineTransform at = new AffineTransform();
g2.translate(height, width);
at.scale(6000000, 6000000);
try {
for (int point = 0; point < p.geoCoordinates().size(); point++) {
Ellipse2D shape = new Ellipse2D.Double(p.geoCoordinates().get(point).getX(),
p.geoCoordinates().get(point).getY(), 10, 10);
g2.transform(at);
g2.draw(shape);
}
} catch (IOException | ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
In fact I am quite new to this topic and have no clue how to make all points visible. Would be great if somebody could help me.
Many thanks
Use a combination of scaling and translating affine transforms.
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class PointPlotter {
Point2D.Double[] points = {
new Point2D.Double(3346349.958, 5642197.806),
new Point2D.Double(3346349.313, 5642199.622),
new Point2D.Double(3346349.237, 5642201.918),
new Point2D.Double(3346349.734, 5642204.058),
new Point2D.Double(3346351.746, 5642205.777),
new Point2D.Double(3346351.636, 5642210.304),
new Point2D.Double(3346349.335, 5642216.518),
new Point2D.Double(3346347.326, 5642221.15),
new Point2D.Double(3346347.365, 5642223.671),
new Point2D.Double(3346351.577, 5642195.711)
};
public static int SZ = 400;
BufferedImage image = new BufferedImage(SZ, SZ, BufferedImage.TYPE_INT_RGB);
private JComponent ui = null;
PointPlotter() {
initUI();
}
private void drawImage() {
Graphics2D g = image.createGraphics();
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.WHITE);
g.fillRect(0, 0, SZ, SZ);
Area area = new Area();
double r = 0.3;
for (Point2D.Double point : points) {
Ellipse2D.Double e = new Ellipse2D.Double(
point.getX() - r, point.getY() - r, 2*r, 2*r);
area.add(new Area(e));
}
Rectangle2D rect = area.getBounds2D();
double w = rect.getWidth();
double h = rect.getHeight();
double max = w>h ? w : h;
double s = SZ/max;
AffineTransform scale = AffineTransform.getScaleInstance(s, s);
double tX = -rect.getMinX();
double tY = -rect.getMinY();
AffineTransform translate = AffineTransform.getTranslateInstance(tX, tY);
AffineTransform transform = scale;
transform.concatenate(translate);
area = new Area(transform.createTransformedShape(area));
g.setColor(Color.RED);
g.draw(area);
g.dispose();
}
public void initUI() {
if (ui != null) {
return;
}
drawImage();
ui = new JPanel(new BorderLayout(4, 4));
ui.setBorder(new EmptyBorder(4, 4, 4, 4));
ui.add(new JLabel(new ImageIcon(image)));
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
PointPlotter o = new PointPlotter();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
class DrawIma extends JPanel{
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i=0;i<20;i++){
for (int j=0;j<20;j++) {
g.drawImage(BuArr[i*20+j], 20*i, 20*j, 20, 20, null);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
In this part, BuArr are the 400 blocks divided from a BufferedImage, now i want them to be draw one by one, but the method can not draw the blocks separately, how can i do this?
Swing is single thread and not thread safe.
This means that you should not perform any long running or blocking (Thread.sleep) operations within the IU thread (the Event Dispatching Thread). It also means that you can not update, modify or create UI elements outside of the EDT context.
Instead, use a Swing Timer to generate a repeated callback at a specified interval and render the portions of the image to something like a BufferedImage, which you can the paint to the component via its paintComponent method...
See Concurrency in Swing and How to use Swing Timers for more details
Because it was a good time waster
This generates a List of Rectangles which represent the individual blocks I want to paint, I then randomise the List and run the Timer, picking the top most Rectangle off the List and using BufferedImage#getSubImage to draw it from the master to the buffer, which gets painted to the screen...
import java.awt.AlphaComposite;
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.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
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 TestImage {
public static void main(String[] args) {
new TestImage();
}
public TestImage() {
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 master;
private BufferedImage copy;
private List<Rectangle> blocks;
public TestPane() {
setBackground(Color.BLACK);
try {
master = ImageIO.read(new File("..."));
copy = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = copy.createGraphics();
AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f);
g2d.setComposite(composite);
g2d.setColor(new Color(0, 0, 0, 0));
g2d.fillRect(0, 0, master.getWidth(), master.getHeight());
g2d.dispose();
int blockSize = 40;
int width = master.getWidth();
int height = master.getHeight();
float aspect = Math.min(width, height) / (float) Math.max(width, height);
int blockHeight = blockSize;
blocks = new ArrayList<>(blockSize * 2);
for (int y = 0; y < master.getHeight(); y += blockHeight) {
if (y + blockHeight > master.getHeight()) {
blockHeight = master.getHeight() - y;
}
int blockWidth = blockSize;
for (int x = 0; x < master.getWidth(); x += blockWidth) {
if (x + blockWidth > master.getWidth()) {
blockWidth = master.getWidth() - x;
}
Rectangle block = new Rectangle(x, y, blockWidth, blockHeight);
blocks.add(block);
}
}
Collections.shuffle(blocks);
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (blocks.isEmpty()) {
((Timer) e.getSource()).stop();
} else {
Graphics2D g2d = copy.createGraphics();
Rectangle block = blocks.remove(0);
g2d.drawImage(master.getSubimage(block.x, block.y, block.width, block.height), block.x, block.y, TestPane.this);
g2d.dispose();
repaint();
}
}
});
timer.start();
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return master == null ? new Dimension(200, 200) : new Dimension(master.getWidth(), master.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (copy != null) {
int x = (getWidth() - copy.getWidth()) / 2;
int y = (getHeight() - copy.getHeight()) / 2;
g2d.drawImage(copy, x, y, this);
}
g2d.dispose();
}
}
}
I am trying to make a piece of a JPanel transparent, but I cannot quite get it to work. Is it possible to do this?
import java.awt.*;
import javax.swing.*;
public class ClearPanel extends JPanel{
public static void main(String[] args) {
ClearPanel c = new ClearPanel();
c.setPreferredSize(new Dimension(200, 200));
c.setOpaque(false);
JPanel backPanel = new JPanel();
backPanel.setBackground(Color.CYAN);
backPanel.add(c);
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(backPanel);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillOval(0, 0, 200, 200);
g.clearRect(45, 45, 50, 50);
Graphics2D g2 = (Graphics2D) g;
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.0f));
g2.fillRect(75, 75, 50, 50);
}
}
The oval should be opaque, but the rectangles I would like to be transparent. By transparent, I mean that I should be able to see the panel behind the ClearPanel.
Going off of MadProgrammer's answer, is there any way to make that gray box draw where it is outside of the area, but remain transparent where it is in the area?
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle fill = new Rectangle(getWidth(), getHeight());
Graphics2D g2d = (Graphics2D) g.create();
Rectangle hole = new Rectangle(0, 0, 100, 100);
Area area = new Area(fill);
area.subtract(new Area(hole));
g2d.setColor(getBackground());
g2d.fill(area);
g2d.setColor(Color.RED);
g2d.setComposite(AlphaComposite.SrcOver.derive(0.0f));
g2d.fill(hole);
g2d.setComposite(AlphaComposite.SrcOver.derive(1.0f));
g2d.setColor(Color.DARK_GRAY);
if(area.contains(0,0,100,200))
g2d.fillRect(0, 0, 100, 200);
g2d.dispose();
}
The problem you have is, by default, JPanel is opaque, meaning that the repaint will NOT paint anything under it.
You need to set the the panel to transparent and then take over the painting of the background.
Now, the real trick begins. If you simply fill the component and then try and paint transparent section over the top of it, you will simply be painting a transparent section over a opaque background...not very helpful.
What you need to do is not fill the area you want to remain transparent.
You can accomplish this by using a Area shape, which has a neat trick of been able to append/add and remove shapes from it.
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.Rectangle;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
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.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TransparentPane {
public static void main(String[] args) {
new TransparentPane();
}
public TransparentPane() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
BackgroundPane backgroundPane = new BackgroundPane();
backgroundPane.setBackground(Color.RED);
backgroundPane.setLayout(new BorderLayout());
backgroundPane.add(new TranslucentPane());
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(backgroundPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class BackgroundPane extends JPanel {
private BufferedImage bg;
public BackgroundPane() {
try {
bg = ImageIO.read(new File("/path/to/your/image.jpg"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return bg == null ? super.getPreferredSize() : new Dimension(bg.getWidth(), bg.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (bg != null) {
int width = getWidth() - 1;
int height = getHeight() - 1;
int x = (width - bg.getWidth()) / 2;
int y = (height - bg.getHeight()) / 2;
g.drawImage(bg, x, y, this);
}
}
}
public class TranslucentPane extends JPanel {
public TranslucentPane() {
setOpaque(false);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle fill = new Rectangle(getWidth(), getHeight());
Graphics2D g2d = (Graphics2D) g.create();
int width = getWidth() - 1;
int height = getHeight() - 1;
int radius = Math.min(width, height) / 2;
int x = (width - radius) / 2;
int y = (height - radius) / 2;
Ellipse2D hole = new Ellipse2D.Float(x, y, radius, radius);
Area area = new Area(fill);
area.subtract(new Area(hole));
g2d.setColor(getBackground());
g2d.fill(area);
g2d.setColor(Color.RED);
g2d.setComposite(AlphaComposite.SrcOver.derive(0.25f));
g2d.fill(hole);
g2d.dispose();
}
}
}
Update
Well, that took a little longer the I expected...
Basically, we need to create a mask of the shape that subtracts the hole from the rectangle we want to display, then subtract that result from the rectangle we want to diplay
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.Rectangle;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
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.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TransparentPane {
public static void main(String[] args) {
new TransparentPane();
}
public TransparentPane() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
BackgroundPane backgroundPane = new BackgroundPane();
backgroundPane.setBackground(Color.RED);
backgroundPane.setLayout(new BorderLayout());
backgroundPane.add(new TranslucentPane());
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(backgroundPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class BackgroundPane extends JPanel {
private BufferedImage bg;
public BackgroundPane() {
try {
bg = ImageIO.read(new File("/Users/swhitehead/Dropbox/MegaTokyo/Evil_Small.jpg"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return bg == null ? super.getPreferredSize() : new Dimension(bg.getWidth(), bg.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (bg != null) {
int width = getWidth() - 1;
int height = getHeight() - 1;
int x = (width - bg.getWidth()) / 2;
int y = (height - bg.getHeight()) / 2;
g.drawImage(bg, x, y, this);
}
}
}
public class TranslucentPane extends JPanel {
public TranslucentPane() {
setOpaque(false);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle fill = new Rectangle(getWidth(), getHeight());
Graphics2D g2d = (Graphics2D) g.create();
int width = getWidth() - 1;
int height = getHeight() - 1;
int radius = Math.min(width, height) / 2;
int x = (width - radius) / 2;
int y = (height - radius) / 2;
Ellipse2D hole = new Ellipse2D.Float(x, y, radius, radius);
Area area = new Area(fill);
area.subtract(new Area(hole));
g2d.setColor(getBackground());
g2d.fill(area);
g2d.setColor(Color.RED);
g2d.setComposite(AlphaComposite.SrcOver.derive(0.0f));
g2d.fill(hole);
g2d.dispose();
g2d = (Graphics2D) g.create();
// Basically, we create an area that is subtraction of the window/rectangle
// from the whole. This leaves us with a rectangle (with a hole in it)
// that doesn't include the area where the whole is...
Rectangle win = new Rectangle(
x + (radius / 2),
y + (radius / 2), radius, (radius / 4));
area = new Area(win);
area.subtract(new Area(hole));
// Then we create a area that is a subtraction of the original rectangle
// from the one with a "hole" in it...
Area actual = new Area(win);
actual.subtract(area);
g2d.setColor(Color.BLUE);
g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
g2d.fill(actual);
g2d.dispose();
}
}
}
I have an image inside the JOptionPane and I want it to disappear whenever I point the mouse cursor and click into it.
Is there something to do about the position?
Thanks...
Here's the code :
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
class ImageBlinking extends JComponent
{
BufferedImage image;
boolean showImage;
int x = -1;
int y = -1;
Random r;
ImageBlinking()
{
try
{
File sourceimage = new File("ball.gif");
image = ImageIO.read(sourceimage);
}
catch (IOException e)
{
e.printStackTrace();
}
r = new Random();
ActionListener listener = new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
if (image != null)
{
if (!showImage)
{
int w = image.getWidth();
int h = image.getHeight();
int rx = getWidth() - w;
int ry = getHeight() - h;
if (rx > -1 && ry > -1)
{
x = r.nextInt(rx);
y = r.nextInt(ry);
}
}
showImage = !showImage;
repaint();
}
}
};
Timer timer = new Timer(200, listener);
timer.start();
setPreferredSize(new Dimension(1000, 1000));
JOptionPane.showMessageDialog(null, this);
timer.stop();
}
public void paintComponent(Graphics g)
{
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
if (image != null)
{
g.drawImage(image, x, y,80,80, this);
setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
}
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new ImageBlinking();
}
});
}
}
(Edited:)
I put a Keylistener on your JComponent, then I look if the MouseEvent is on your Image and if its the case, I stop the timer and put the color of the image to Black
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
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 java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
class BlockBlinking extends JComponent {
BufferedImage image;
boolean showImage;
int x = -1;
int y = -1;
int imageW = 20;
int imageH = 20;
Random r;
private Timer timer;
Color imageColor=null;
BlockBlinking() {
{
try
{
File sourceimage = new File("ball.gif");
image = ImageIO.read(sourceimage);
}
catch (IOException e)
{
e.printStackTrace();
}
this.addMouseListener(new MyMouseListener());
r = new Random();
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if (image != null) {
if (!showImage) {
int w = image.getWidth();
int h = image.getHeight();
int rx = getWidth() - w;
int ry = getHeight() - h;
if (rx > -1 && ry > -1) {
x = r.nextInt(rx);
y = r.nextInt(ry);
}
}
showImage = !showImage;
repaint();
}
}
};
timer = new Timer(500, listener);
timer.start();
setPreferredSize(new Dimension(500, 400));
JOptionPane.showMessageDialog(null, this);
timer.stop();
}
}
public void paintComponent(Graphics g) {
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
if (image != null) {
if(imageColor != null){
Graphics imageGraphic =image.createGraphics();
imageGraphic.setColor(imageColor);
imageGraphic.fillRect(0, 0, image.getWidth(), image.getHeight());
}
g.drawImage(image, x, y,imageW,imageH, this);
setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new BlockBlinking();
}
});
}
class MyMouseListener extends MouseAdapter {
#Override
public void mouseReleased(MouseEvent e) {
if (e.getX() >= x && e.getX() <= x + imageW && e.getY() >= y && e.getY() <= y + imageH) {
imageColor = Color.BLACK;
repaint();
timer.stop();
}
}
}
}
Edit: look at the fields imageW and imageH
One approach is to use a JToggleButton.
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
class ImageVanish extends JComponent {
ImageVanish() {
// put your image reading code here..
BufferedImage imageSelected = new BufferedImage(
32,32,BufferedImage.TYPE_INT_ARGB);
BufferedImage image = new BufferedImage(
32,32,BufferedImage.TYPE_INT_ARGB);
Graphics g = image.createGraphics();
g.setColor(Color.ORANGE);
g.fillOval(0,0,32,32);
g.dispose();
// END - image read
JToggleButton b = new JToggleButton();
b.setIcon(new ImageIcon(image));
b.setSelectedIcon(new ImageIcon(imageSelected));
b.setBorderPainted(false);
b.setContentAreaFilled(false);
JOptionPane.showMessageDialog(null, b);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ImageVanish();
}
});
}
}
For the positioning, see #Hovercraft FOE's advice on their answer to your earlier question.