I'm trying to draw over an image (with the mouse) in a JPanel, this is working, but when I try to take an screenshot of the panel and generate an image of this, I only can see the image background without drawn with the mouse.
This is my code to generate the background Panel.java
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(this.createImage("/imagenes/cuerpoHumano.png").getImage(), 0, 0, null);
}
This is my code to draw as a pencil over the image: Panel.java
private void formMouseDragged(java.awt.event.MouseEvent evt) {
x = evt.getX();
y = evt.getY();
this.getGraphics().setColor(Color.RED);
this.getGraphics().fillOval(x, y, 4, 4);
}
This is the code to generate an screenshot
Dimension size = panel.getSize();
BufferedImage image = (BufferedImage) panel.createImage(size.width, size.height);
Graphics g = image.getGraphics();
panel.paint(g);
g.dispose();
try {
String fileName = UUID.randomUUID().toString().substring(0, 18);
ImageIO.write(image, "jpg", new File(path, fileName + ".jpg"));
} catch (IOException e) {
e.printStackTrace();
}
When you are taking the screenshot, the paintComponent() method is called. This means it will only paint you the image. You have to store the mouse move inside some model and paint the contents of the model in the paintComponent() method. This method is triggered by calling repaint() on the panel during the mouse move.
I think this is code that works .
public class PanelImagenCuerpoHumano extends JPanel {
private int x = -1;
private int y = -1;
private Image image = null;
private ArrayList<Point> puntos = new ArrayList<Point>();
public PanelImagenCuerpoHumano() {
image = new ImageIcon(getClass()
.getResource("/imagenes/cuerpoHumano.png")).getImage();
this.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent e) {
x = e.getX();
y = e.getY();
puntos.add(new Point(x, y));
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
}
});
}
#Override
protected void paintComponent(Graphics g) {
g.drawImage(image, 0, 0, null);
for (Point p : puntos) {
g.setColor(Color.red);
g.fillOval(p.x, p.y, 3, 3);
}
}
}
Related
I am getting input==null while trying to load an Image. I can't seem to figure out why, even after browsing a good number of StackOverflow questions. It looks right to me.
Here is the code:
private BufferedImage image;
public practice(){
setLayout(new BorderLayout());
timeBall.start();
JPanel panelNorth = makePanel();
panelNorth.setBackground(Color.CYAN);
add(panelNorth, BorderLayout.NORTH);
try{
image = ImageIO.read(practice.class.getResource("/pics/flying.png"));
}catch(IOException e){
e.printStackTrace();
}
}
public Dimension getPreferredSize() {
return image == null ? new Dimension(400, 300): new Dimension(image.getWidth(), image.getHeight());
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLUE);
ellipse = new Ellipse2D.Double(Ox, Oy+Speedy, height, height);
Graphics2D graphics = (Graphics2D)g;
g.drawImage(image, 0, 0, this);
graphics.fill(ellipse);
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
Oy = Oy + Speedy / 10;
Ox = Ox + Speedx / 10;
}
I have this simple paint code that should draw but instead it moves the oval around the panel.
When I remove super.paintComponent(g) line the program works it paints and not just move the oval, but I keep reading that we should not remove this line, so what can I do to leave the line in but still get the desired results?
class OraclePaint extends JFrame {
public static void main(String[] args) {
OraclePaint ss = new OraclePaint();
ss.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ss.add(new MyPanel());
ss.setSize(250, 200);
ss.setVisible(true);
}
}
class MyPanel extends JPanel {
private int x = -10, y = -10;
public MyPanel() {
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent event) {
x = event.getX();
y = event.getY();
repaint();
}
}); // end call to addMouseMotionListener
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillOval(x, y, 22, 22);
}
}
Based on the description, I assume that you want something like "a simple paint program".
It is correct to invoke super.paintComponent(g) as the first line of an overridden paintComponent. And it is true that this erases the background (that is, everything that was painted before will be deleted).
In Swing, everything that you want to paint has to be painted in the paintComponent method (or in any method that is called from there, and receives the same Graphics object).
If you want to "save" everything that you have painted, you have to paint everything into an image (that is, into a BufferedImage), and paint this image in your paintComponent method.
There are some other issues with the code, but without changing too much of the remaining code, this could roughly (!) be achieved like this:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
class OraclePaint extends JFrame {
public static void main(String[] args) {
OraclePaint ss = new OraclePaint();
ss.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ss.add(new MyPanel());
ss.setSize(250, 200);
ss.setVisible(true);
}
}
class MyPanel extends JPanel {
private BufferedImage image = null;
public MyPanel() {
addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent event) {
if (image != null) {
// Paint into the image
Graphics g = image.getGraphics();
g.setColor(Color.BLACK);
g.fillOval(event.getX(), event.getY(), 22, 22);
g.dispose();
repaint();
}
}
}); // end call to addMouseMotionListener
}
// Make sure that the image is not 'null' and that
// it has the same size as this panel
private void validateImage()
{
if (image == null)
{
image = new BufferedImage(getWidth(), getHeight(),
BufferedImage.TYPE_INT_ARGB);
}
if (image.getWidth() != getWidth() || image.getHeight() != getHeight())
{
BufferedImage newImage = new BufferedImage(getWidth(), getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics g = newImage.getGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
image = newImage;
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
validateImage();
g.drawImage(image, 0, 0, null);
}
}
change your MyPanel to this:
class MyPanel extends JPanel
{
private int x2 = 0, y2 = 0;
private int x1 = 0, y1 = 0;
public MyPanel()
{
addMouseMotionListener(new MouseMotionAdapter()
{
public void mouseDragged( MouseEvent event )
{
x2 = event.getX();
y2 = event.getY();
repaint();
}
}
); // end call to addMouseMotionListener
addMouseListener(new MouseListener() {
#Override
public void mousePressed(MouseEvent e) {
x1 = e.getX();
y1 = e.getY();
}
});
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.fillOval(x1, y1, x2, y2);
}
}
I need to show an image in a java applet, with a text element (label) to move to a point chosen by the user. Is it possible by dragging and dropping the text over the image? What methods would I need to use?
I am looking for something similar to this.
Edit: Thanks you for your useful response. The code below works fine! But how to get a text position by x,y coordinates within the image?
public class MouseDragTest extends JPanel {
private static final String TITLE = "Drag me!";
private static final int W = 640;
private static final int H = 480;
private Point textPt = new Point(W / 2, H / 2);
private Point mousePt;
Image img;
public MouseDragTest() {
img = Toolkit.getDefaultToolkit().createImage("my_image.jpg");
this.setFont(new Font("Serif", Font.ITALIC + Font.BOLD, 32));
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
mousePt = e.getPoint();
repaint();
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
int dx = e.getX() - mousePt.x;
int dy = e.getY() - mousePt.y;
textPt.setLocation(textPt.x + dx, textPt.y + dy);
mousePt = e.getPoint();
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(W, H);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int w2 = g.getFontMetrics().stringWidth(TITLE) / 2;
g.drawImage(img, 0, 0, null);
g.drawString(TITLE, textPt.x - w2, textPt.y);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame(TITLE);
f.add(new MouseDragTest());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
}
You can use drawImage() in paintComponent() to show your invoice, like they show here, and drag the text, like they show here. Another way is to use the The Glass Pane.
How to get a text position by x,y coordinates within the image?
It sounds like you want to edit the text and location repeatedly. When you're done dragging, textPt will be the point at which you want to draw the text when you next load that image. You can store the details in java.util.Preferences and restore them when you restart.
private static class AnnotatedImage {
File file;
List<String> notes;
List<Point> points;
}
As you are using createImage(), use this as the image observer when drawing.
g.drawImage(img, 0, 0, this);
Th code below has few problems :
1) The polygon joins last and first point itself, should not do itself but user should draw it.
2) The polygons lines disappeared after clicking on other shapes.
package Circles;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import javax.swing.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Iterator;
//////////////////////////////////////////////////////////////PaintDemo
class PaintDemo2 {
//============================================================= main
public static void main(String[] args) {
PaintWindow2 window = new PaintWindow2();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
}//end main
}//endclass PaintDemo
#SuppressWarnings("serial")
////////////////////////////////////////////////////////////PaintWindow
class PaintWindow2 extends JFrame {
PaintPanel2 canvas = new PaintPanel2();
//====================================================== constructor
public PaintWindow2() {
//--- create the buttons
JButton circleButton = new JButton("Circle");
circleButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
canvas.setShape(PaintPanel2.CIRCLE);
}});
JButton rectangleButton = new JButton("Rectangle");
rectangleButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
canvas.setShape(PaintPanel2.Ellipse);
}});
JButton polyButton = new JButton("Polygon");
polyButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
canvas.setShape(PaintPanel2.POLY);
}});
//--- layout the buttons
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(2, 1));
buttonPanel.add(circleButton);
buttonPanel.add(rectangleButton);
buttonPanel.add(polyButton);
//--- layout the window
Container content = this.getContentPane();
content.setLayout(new BorderLayout());
content.add(buttonPanel, BorderLayout.WEST);
content.add(canvas , BorderLayout.CENTER);
this.setTitle("Paint Demo");
this.pack();
}//end constructor
}//endclass PaintWindow
///////////////////////////////////////////////////////////// PaintPanel2
#SuppressWarnings("serial")
class PaintPanel2 extends JPanel implements MouseListener,
MouseMotionListener {
//--- Public constants used to specify shape being drawn.
public static final int NONE = 0;
public static final int LINE = 1;
public static final int Ellipse = 2;
public static final int CIRCLE = 3;
public static final int POLY = 4;
//--- Variables to store the current figure info
private int _shape = NONE;
public int getShape() {
return _shape;
}
private int _currentStartX = 0; // where mouse first pressed
private int _currentStartY = 0;
private int _currentEndX = 0; // where dragged to or released
private int _currentEndY = 0;
//--- BufferedImage to store the underlying saved painting.
// Will be initialized first time paintComponent is called.
private BufferedImage _bufImage = null;
private boolean polygonIsNowComplete = false;
//--- Private constant for size of paint area.
private static final int SIZE = 600; // size of paint area
private final Point trackPoint = new Point();
private Path2D currentShape;
private ArrayList<Path2D> lstPloys = new ArrayList<Path2D>();;
private Point lastPoint;
private Point currentPoint;
#SuppressWarnings("rawtypes")
private ArrayList points = new ArrayList();
//====================================================== constructor
public PaintPanel2() {
setPreferredSize(new Dimension(SIZE, SIZE));
setBackground(Color.white);
//--- Add the mouse listeners.
this.addMouseListener(this);
this.addMouseMotionListener(this);
}//endconstructor
//========================================================= setShape
public void setShape(int shape) {
//--- Provided so users can set the shape.
_shape = shape;
}//end setShape
//=================================================== paintComponent
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g; // downcast to Graphics2D
if (_bufImage == null) {
//--- This is the first time, initialize _bufImage
int w = this.getWidth();
int h = this.getHeight();
_bufImage = (BufferedImage)this.createImage(w, h);
Graphics2D gc = _bufImage.createGraphics();
gc.setColor(Color.white);
gc.fillRect(0, 0, w, h); // fill in background
}
g2.drawImage(_bufImage, null, 0, 0); // draw previous shapes
drawCurrentShape(g2);
}//end paintComponent
//================================================= drawCurrentShape
private void drawCurrentShape(Graphics2D g2) {
//--- Draws current shape on a graphics context, either
// on the context passed to paintComponent, or the
// context for the BufferedImage.
switch (_shape) {
case NONE :
break;
case CIRCLE:
g2.drawOval(_currentStartX, _currentStartY,
_currentEndX - _currentStartX,
_currentEndY - _currentStartY);
break;
case Ellipse:
g2.draw(new Ellipse2D.Double(_currentStartX, _currentStartY,
_currentEndX - _currentStartX,
_currentEndY - _currentStartY));
break;
case POLY:
drawPolyGon(g2);
break;
default: // should never happen
g2.drawString("Huh?", 10, 20);
break;
}
}//end paintComponent
private void drawPolyGon(Graphics2D g2) {
g2.create();
if (lastPoint != null) {
g2.setColor(Color.RED);
g2.fillOval(lastPoint.x - 2, lastPoint.y - 2, 4, 4);
}
if (currentShape != null) {
g2.setColor(Color.RED);
g2.draw(currentShape);
if (lastPoint != null && currentPoint != null) {
g2.setColor(new Color(255, 0, 0, 64));
g2.draw(new Line2D.Float(lastPoint, currentPoint));
}
}
g2.setColor(Color.BLACK);
for (Path2D shape : lstPloys) {
g2.draw(shape);
}
g2.dispose();
// TODO Auto-generated method stub
}
//===================================================== mousePressed
public void mousePressed(MouseEvent e) {
_currentStartX = e.getX(); // save x coordinate of the click
_currentStartY = e.getY(); // save y
_currentEndX = _currentStartX; // set end to same pixel
_currentEndY = _currentStartY;
}//end mousePressed
//===================================================== mouseDragged
public void mouseDragged(MouseEvent e) {
_currentEndX = e.getX(); // save new x and y coordinates
_currentEndY = e.getY();
this.repaint();
// show new shape
}//end mouseDragged
//==================================================== mouseReleased
public void mouseReleased(MouseEvent e) {
// This will save the shape that has been dragged by
// drawing it onto the bufferedImage where all shapes
// are written.
_currentEndX = e.getX(); // save ending coordinates
_currentEndY = e.getY();
//--- Draw the current shape onto the buffered image.
Graphics2D grafarea = _bufImage.createGraphics();
drawCurrentShape(grafarea);
this.repaint();
}//end mouseReleased
public void mouseMoved (MouseEvent e) {
if (currentShape != null) {
currentPoint = e.getPoint();
repaint();
} else {
currentPoint = null;
}
}
public void mouseEntered (MouseEvent e) {}
public void mouseExited (MouseEvent e) {}
public void mouseClicked (MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
if (e.getClickCount() == 1) {
Point p = e.getPoint();
lastPoint = p;
if (currentShape == null) {
currentShape = new Path2D.Float();
currentShape.moveTo(p.x, p.y);
} else {
currentShape.lineTo(p.x, p.y);
}
repaint();
} else if (e.getClickCount() == 2) {
currentShape.closePath();
lstPloys.add(currentShape);
currentShape = null;
lastPoint = null;
repaint();
}
}
}
}
Paint cycles are stateless, that is, the contents of the graphics are not passed from one cycle to another.
You are required to re-paint the entire contents of component on each paint cycles.
You've attempt to implement a double buffer solution, but instead of passing the graphs context of the buffer, you've passed the graphics contents supplied to you by the paint system. If you passed the graphs context of the buffer to the drawCurrentShape method, it might solve your problem (and eliminate the need to cache all the shapes)
UPDATED
So, in your paintComponent method of your PaintPanel2 component, you are creating a BufferedImage, but you are not painting the components to it...
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g; // downcast to Graphics2D
if (_bufImage == null) {
//--- This is the first time, initialize _bufImage
int w = this.getWidth();
int h = this.getHeight();
_bufImage = (BufferedImage)this.createImage(w, h);
Graphics2D gc = _bufImage.createGraphics();
gc.setColor(Color.white);
gc.fillRect(0, 0, w, h); // fill in background
}
g2.drawImage(_bufImage, null, 0, 0); // draw previous shapes
drawCurrentShape(g2);
}//end paintComponent
Instead, you should use the graphics context from the buffered image to drawCurrentShape
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g; // downcast to Graphics2D
Graphics2D gc = null;
if (_bufImage == null) {
//--- This is the first time, initialize _bufImage
int w = this.getWidth();
int h = this.getHeight();
_bufImage = (BufferedImage)this.createImage(w, h);
gc = _bufImage.createGraphics();
gc.setColor(Color.white);
gc.fillRect(0, 0, w, h); // fill in background
} else {
gc = _bufImage.createGraphics();
}
drawCurrentShape(g2);
gc.dispose();
g2.drawImage(_bufImage, null, 0, 0); // draw previous shapes
}//end paintComponent
It should be noted that this might create some other issues, but the concept is sound.
Personally, I prefer to keep a List of all the shapes and repaint them. This gives you the ability to select, move, delete, re-order and change all the shapes within the program, as well as provide a type of history ;)
I have a component extends JPanel. It saves itself as bufferedimage on every call of paintComponent method. Component is not completely transparent, only its background. Problem is background is not transparent. I am using setOpaque(false);
Here is my relevant code;
private BufferedImage bufImage = null;
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
// if first time call
if (bufImage == null) {
int w = this.getWidth();
int h = this.getHeight();
bufImage = (BufferedImage)this.createImage(w, h);
}
g2.drawImage(bufImage, null, 0, 0);
// draw sth
g2.draw(sth);
}
--
I also tried
bufImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
instead of
bufImage = (BufferedImage)this.createImage(w, h);
When i do that; background transperancy works but i can only draw with white color. I have no idea what causes that.
Note:
I used that code to check if it is working;
File outputfile = new File("saved.png");
ImageIO.write(bufImage, "png", outputfile);
saved.png had transparent background but drawings were only white.
This is the component, only lets drawing rectangle with mouse;
class PaintPanel extends JPanel implements MouseListener, MouseMotionListener {
private BufferedImage _bufImage = null;
private boolean dragging = false;
private Point _start = null, _end = null;
public PaintPanel() {
setOpaque(false);
this.addMouseListener(this);
this.addMouseMotionListener(this);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
if (_bufImage == null) {
int w = this.getWidth();
int h = this.getHeight();
_bufImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
//_bufImage = (BufferedImage)this.createImage(w, h);
}
g2.drawImage(_bufImage, null, 0, 0);
if (dragging) {
drawCurrentShape(g2);
}
}
private void drawCurrentShape(Graphics2D g2) {
int startx = (int) _start.getX();
int starty = (int) _start.getY();
int stopx = (int) _end.getX();
int stopy = (int) _end.getY();
int width = Math.abs(startx - stopx);
int height = Math.abs(starty - stopy);
int x = startx, y = starty;
if(x > stopx)
x = stopx;
if(y > stopy)
y = stopy;
Rectangle r = new Rectangle(x, y, width, height);
g2.draw(r);
}
public void mousePressed(MouseEvent e) {
dragging = true;
_start = e.getPoint();
_end = _start;
}
public void mouseDragged(MouseEvent e) {
_end = e.getPoint();
this.repaint();
}
public void mouseReleased(MouseEvent e) {
_end = e.getPoint();
if (dragging) {
dragging = false;
drawCurrentShape(_bufImage.createGraphics());
this.repaint();
}
}
public void mouseMoved (MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited (MouseEvent e) {}
public void mouseClicked(MouseEvent e) {}
}
try this:
bufImage = new BufferedImage(w,h,java.awt.image.BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = bufImage.createGraphics();
this.print(graphics);
graphics.dispose();
The key is to use print()
Edit: I tried the following and transparency works like a charm:
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test2 {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel p = new JPanel();
p.setPreferredSize(new Dimension(400, 400));
p.setOpaque(false);
JButton button = new JButton("Hello world");
p.add(button);
frame.add(p);
frame.pack();
frame.setVisible(true);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
BufferedImage bufImage = new BufferedImage(p.getWidth(), p.getHeight(), java.awt.image.BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = bufImage.createGraphics();
p.print(graphics);
graphics.dispose();
try {
ImageIO.write(bufImage, "png", new File("d:/tmp/tmp.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}
createImage(w, h) will create a "blank" image with the specified width and height. That being said, what you'll need to do is invoke createGraphics on the BufferedImage instance and draw directly to the returned Graphics object.