Here is my code below. I am trying to implement zooming by moving the slider.
However, the effect does'nt show. Please help me on this. I am lost. I am new to java and I am using Netbeans for this.
I further need to click on the zoomed image and display the corresponding points in the actual image. How can I make this possible?
public class TrialZoom extends javax.swing.JFrame {
/**
* Creates new form TrialZoom
*/
private float scaleX, scaleY;
Point p = new Point();
Point q = new Point();
Vector<Point> v = new Vector();
Vector<Float> v_scale = new Vector();
public TrialZoom() {
initComponents();
}
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jPanel1 = new javax.swing.JPanel();
jButton1 = new javax.swing.JButton();
jPanel2 = new javax.swing.JPanel();
jPanel3 = new javax.swing.JPanel();
jSlider2 = new javax.swing.JSlider();
jPanel4 = new javax.swing.JPanel();
jLabel1 = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jPanel1.setLayout(new java.awt.GridLayout(1, 0));
jButton1.setText("Done");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
jPanel1.add(jButton1);
getContentPane().add(jPanel1, java.awt.BorderLayout.PAGE_END);
jPanel2.setLayout(new java.awt.BorderLayout());
jPanel3.setLayout(new java.awt.GridLayout(1, 0));
jSlider2.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
jSlider2StateChanged(evt);
}
});
jPanel3.add(jSlider2);
jPanel2.add(jPanel3, java.awt.BorderLayout.PAGE_END);
jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
jLabel1.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
jLabel1MouseClicked(evt);
}
});
javax.swing.GroupLayout jPanel4Layout = new javax.swing.GroupLayout(jPanel4);
jPanel4.setLayout(jPanel4Layout);
jPanel4Layout.setHorizontalGroup(
jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
.addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel4Layout.createSequentialGroup()
.addGap(0, 200, Short.MAX_VALUE)
.addComponent(jLabel1)
.addGap(0, 200, Short.MAX_VALUE)))
);
jPanel4Layout.setVerticalGroup(
jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 251, Short.MAX_VALUE)
.addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel4Layout.createSequentialGroup()
.addGap(0, 125, Short.MAX_VALUE)
.addComponent(jLabel1)
.addGap(0, 126, Short.MAX_VALUE)))
);
jPanel2.add(jPanel4, java.awt.BorderLayout.CENTER);
getContentPane().add(jPanel2, java.awt.BorderLayout.CENTER);
pack();
}// </editor-fold>
private void jSlider2StateChanged(javax.swing.event.ChangeEvent evt) {
// TODO add your handling code here:
int val = ((JSlider) evt.getSource()).getValue();
setScale(val * .01f, val * .01f);
}
private void jLabel1MouseClicked(java.awt.event.MouseEvent evt) {
setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.CROSSHAIR_CURSOR));
p = evt.getPoint();
q = SwingUtilities.convertPoint(evt.getComponent(), p, this);
v.add(p);
v_scale.add(scaleX);
v_scale.add(scaleY);
double c = q.getX();
double d = q.getY();
String x1 = Double.toString(p.getX());
String x2 = Double.toString(p.getY());
Graphics g = this.getGraphics();
paint(g, (int) c, (int) d); // TODO add your handling code here:
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
System.out.println(p.getX() + " " + p.getY() + " " + q.getX() + " " + q.getY());
float sx=v_scale.remove(0);
float sy=v_scale.remove(0);
System.out.println(sx+" "+sy);
dispose();
// TODO add your handling code here:
}
public Vector<Point> first(ImageIcon icon) {
jLabel1.setIcon(icon);
return return_vector();
}
public void paint(Graphics g, int a, int b) {
g.setColor(Color.RED);
g.drawRect(a - 1, b - 1, 3, 3);
g.fillRect(a, b, 2, 2);
}
#Override
public Dimension getPreferredSize() {
int prefWidth;
prefWidth = (int) (jLabel1 == null ? 0 : jPanel4.getWidth() * scaleX);
int prefHeight;
prefHeight = (int) (jLabel1 == null ? 0 : jPanel4.getHeight() * scaleY);
return new Dimension(prefWidth, prefHeight);
}
public void paintComponent(Graphics g) {
if (jLabel1 == null) {
return;
}
int w = (int) (jLabel1.getWidth() * scaleX);
int h = (int) (jLabel1.getHeight() * scaleY);
int x = (getWidth() - w) / 2;
int y = (getHeight() - h) / 2;
ImageIcon img_icon=(ImageIcon) jLabel1.getIcon();
g.drawImage(img_icon.getImage(), x, y, w, h, null);
}
public void setScale(float x, float y) {
this.scaleX = x;
this.scaleY = y;
jLabel1.revalidate();
jLabel1.repaint();
}
public Vector<Point> return_vector() {
return this.v;
}
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(TrialZoom.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(TrialZoom.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(TrialZoom.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(TrialZoom.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new TrialZoom().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JButton jButton1;
private javax.swing.JLabel jLabel1;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JPanel jPanel3;
private javax.swing.JPanel jPanel4;
private javax.swing.JSlider jSlider2;
// End of variables declaration
}
First, start with a component that is capable of managing the image and scaling. This should be as self contained as you can make it. This allows you to decouple your program and focus on individual responsibilities of the application.
Next, you need to maintain a list of normalised points. The reason for normalising them is to ensure that the points will continue to be rendered at the right locations when the image scaled...
Take a look at Performing Custom Painting for more details
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.Image;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class ZoomExample {
public static void main(String[] args) {
new ZoomExample();
}
public ZoomExample() {
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 ZoomPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ZoomPane extends JPanel {
private JSlider slider;
private ZoomImagePane zoomImagePane;
public ZoomPane() {
zoomImagePane = new ZoomImagePane();
slider = new JSlider(1, 200);
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
zoomImagePane.setScale((float) slider.getValue() / 100f);
}
});
setLayout(new BorderLayout());
add(slider, BorderLayout.SOUTH);
add(zoomImagePane);
slider.setValue(100);
}
}
public class ZoomImagePane extends JPanel {
private float scale = 0f;
private BufferedImage master;
private Image scaled;
private List<Point2D> clickPoints;
public ZoomImagePane() {
clickPoints = new ArrayList<>(25);
try {
master = ImageIO.read(new File("/path/to/image"));
setScale(1f);
} catch (IOException ex) {
ex.printStackTrace();
}
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
Point p = e.getPoint();
Point2D scaledPoint = new Point2D.Float();
int xOffset = (getWidth() - scaled.getWidth(null)) / 2;
int yOffset = (getHeight() - scaled.getHeight(null)) / 2;
float x = (float)(p.x - xOffset) / (float)scaled.getWidth(null);
float y = (float)(p.y - yOffset) / (float)scaled.getHeight(null);
scaledPoint.setLocation(x, y);
clickPoints.add(scaledPoint);
repaint();
}
});
}
protected void setScale(float value) {
if (scale != value) {
scale = value;
scaled = master.getScaledInstance((int) ((float) master.getWidth() * scale), -1, Image.SCALE_SMOOTH);
revalidate();
repaint();
}
}
#Override
public Dimension getPreferredSize() {
Dimension size = new Dimension(200, 200);
if (scaled != null) {
size = new Dimension(scaled.getWidth(this), scaled.getHeight(this));
}
return size;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (scaled != null) {
int x = (getWidth() - scaled.getWidth(this)) / 2;
int y = (getHeight() - scaled.getHeight(this)) / 2;
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(scaled, x, y, this);
g2d.setColor(Color.RED);
for (Point2D p : clickPoints) {
int xPos = x + ((int)(p.getX() * scaled.getWidth(this)) - 5);
int yPos = y + ((int)(p.getY() * scaled.getHeight(this)) - 5);
g2d.fillOval(xPos, yPos, 10, 10);
}
g2d.dispose();
}
}
}
}
Related
I need some assistance figuring out how to translate coordinates from mouse events during zoom ... it works when zoom factor is 1.0 but not sure of algorithm when it changes...
I can drag the rectangle around the screen when if I comment out the zoom code but once zoom, the mouse coordinates screw up once the zoom is applied
I just cannot figure out the coordinates translation code
package ca.stackoverflow.main;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class Demo extends JFrame {
private static final long serialVersionUID = 1L;
public Demo() {
setPreferredSize(new Dimension(640, 480));
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JScrollPane scroll = new JScrollPane(new Panel());
add(scroll, BorderLayout.CENTER);
pack();
setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
Demo demo = new Demo();
demo.setVisible(true);
}
catch(Throwable e) {
throw new RuntimeException(e);
}
}
});
}
}
class Panel extends JPanel implements MouseWheelListener, MouseListener, MouseMotionListener {
private static final long serialVersionUID = 1L;
private static final double MIN_ZOOM_FACTOR = 0.1;
private static final double MAX_ZOOM_FACTOR = 5.0;
private Color _fillColor;
private Point _startPoint;
private double xOffset;
private double yOffset;
private int xdragOffset;
private int ydragOffset;
private double zoomFactor = 1;
private double prevZoomFactor = 1;
private boolean zoomer;
private Rectangle _rectangle;
public Panel() {
setPreferredSize(new Dimension(1000, 1000));
addMouseWheelListener(this);
addMouseMotionListener(this);
addMouseListener(this);
_fillColor = Color.WHITE;
_rectangle = new Rectangle(50, 50, 100, 200);
}
#Override public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
AffineTransform at = new AffineTransform();
if (zoomer) {
double xRel = MouseInfo.getPointerInfo().getLocation().getX() - getLocationOnScreen().getX();
double yRel = MouseInfo.getPointerInfo().getLocation().getY() - getLocationOnScreen().getY();
double zoomDiv = zoomFactor / prevZoomFactor;
xOffset = (zoomDiv) * (xOffset) + (1 - zoomDiv) * xRel;
yOffset = (zoomDiv) * (yOffset) + (1 - zoomDiv) * yRel;
prevZoomFactor = zoomFactor;
zoomer = false;
}
at.translate(xOffset, yOffset);
at.scale(zoomFactor, zoomFactor);
g2.transform(at);
g.setColor(_fillColor);
g.fillRect(_rectangle.x, _rectangle.y, _rectangle.width, _rectangle.height);
g.setColor(Color.BLACK);
g.drawRect(_rectangle.x, _rectangle.y, _rectangle.width, _rectangle.height);
}
#Override public void mouseMoved(MouseEvent e) {
_fillColor = Color.WHITE;
if(_rectangle.contains(e.getPoint())) {
_fillColor = Color.GREEN;
}
repaint();
}
#Override public void mousePressed(MouseEvent e) {
_startPoint = null;
_fillColor = Color.WHITE;
if(_rectangle.contains(e.getPoint())) {
_startPoint = e.getPoint();
_fillColor = Color.GREEN;
xdragOffset = _startPoint.x - _rectangle.x;
ydragOffset = _startPoint.y - _rectangle.y;
}
repaint();
}
#Override public void mouseDragged(MouseEvent e) {
if(_startPoint != null) {
int diffX = e.getX() - _startPoint.x;
int diffY = e.getY() - _startPoint.y;
_rectangle.x = _startPoint.x + diffX - xdragOffset;
_rectangle.y = _startPoint.y + diffY - ydragOffset;
}
else {
_fillColor = Color.WHITE;
if(_rectangle.contains(e.getPoint())) {
_fillColor = Color.GREEN;
}
}
repaint();
}
#Override public void mouseWheelMoved(MouseWheelEvent e) {
zoomer = true;
if (e.getWheelRotation() < 0) {
zoomFactor = Math.max(zoomFactor / 1.1, MIN_ZOOM_FACTOR);
}
if (e.getWheelRotation() > 0) {
zoomFactor = Math.min(zoomFactor * 1.1, MAX_ZOOM_FACTOR);
}
repaint();
}
#Override public void mouseClicked(MouseEvent e) {}
#Override public void mouseReleased(MouseEvent e) {}
#Override public void mouseEntered(MouseEvent e) {}
#Override public void mouseExited(MouseEvent e) {}
}
Okay, so, that was a little more involved than I first thought.
The "basic" concept is, you need to apply the same AffineTransformation you used to paint the component to you _rectangle
So, I started by creating an instance property to keep track of the current transformation, as this is going to get re-used a bit
private AffineTransform transformation = new AffineTransform();
Then I added a getter
protected AffineTransform getTransformation() {
return transformation;
}
Then I "optimised" your paintComponent, seriously...
double xRel = MouseInfo.getPointerInfo().getLocation().getX() - getLocationOnScreen().getX();
double yRel = MouseInfo.getPointerInfo().getLocation().getY() - getLocationOnScreen().getY();
is a really bad idea, generally, but especially from within a paint pass
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setTransform(getTransformation());
g2.setColor(_fillColor);
g2.fillRect(_rectangle.x, _rectangle.y, _rectangle.width, _rectangle.height);
g2.setColor(Color.BLACK);
g2.drawRect(_rectangle.x, _rectangle.y, _rectangle.width, _rectangle.height);
g2.dispose();
}
I then modified the mouseWheelMoved to calculate the new AffineTransformation each time it changed
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
Point2D zoomAnchor = e.getPoint();
prevZoomFactor = zoomFactor;
if (e.getWheelRotation() < 0) {
zoomFactor = Math.max(zoomFactor / 1.1, MIN_ZOOM_FACTOR);
}
if (e.getWheelRotation() > 0) {
zoomFactor = Math.min(zoomFactor * 1.1, MAX_ZOOM_FACTOR);
}
transformation = new AffineTransform();
double zoomDiv = zoomFactor / prevZoomFactor;
xOffset = (zoomDiv) * (xOffset) + (1 - zoomDiv) * zoomAnchor.getX();
yOffset = (zoomDiv) * (yOffset) + (1 - zoomDiv) * zoomAnchor.getX();
transformation.translate(xOffset, yOffset);
transformation.scale(zoomFactor, zoomFactor);
repaint();
}
Now, each time mouseMoved is called, you need to apply the AffineTransformation to the _rectangle and check it for any collisions...
#Override
public void mouseMoved(MouseEvent e) {
AffineTransform at = getTransformation();
PathIterator pathIterator = _rectangle.getPathIterator(at);
GeneralPath shape = new GeneralPath();
shape.append(pathIterator, true);
_fillColor = Color.WHITE;
if (shape.contains(e.getPoint())) {
_fillColor = Color.GREEN;
}
repaint();
}
Now, I would be tempted to create a "shadow" Shape each time mouseWheelMoved is called, as you're going to want it for the other mouse events
Runnable example...
I've not updated your mousePressed or mouseDragged methods, I'll leave you to do that. I've also left in some debug code which will draw the "transformed shape" on each paint pass. This is draw BEFORE the Graphics context is transformed, so it should give you a bit of a guide
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class Main extends JFrame {
private static final long serialVersionUID = 1L;
public Main() {
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JScrollPane scroll = new JScrollPane(new TestPane());
add(scroll, BorderLayout.CENTER);
pack();
setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
Main demo = new Main();
demo.setVisible(true);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
});
}
class TestPane extends JPanel implements MouseWheelListener, MouseListener, MouseMotionListener {
private static final long serialVersionUID = 1L;
private static final double MIN_ZOOM_FACTOR = 0.1;
private static final double MAX_ZOOM_FACTOR = 5.0;
private Color _fillColor;
private Point _startPoint;
private double xOffset;
private double yOffset;
private int xdragOffset;
private int ydragOffset;
private double zoomFactor = 1;
private double prevZoomFactor = 1;
private boolean zoomer;
private Point zoomAnchor;
private Rectangle _rectangle;
private AffineTransform transformation = new AffineTransform();
public TestPane() {
addMouseWheelListener(this);
addMouseMotionListener(this);
addMouseListener(this);
_fillColor = Color.WHITE;
_rectangle = new Rectangle(50, 50, 100, 200);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(640, 480);
}
// This would be better pre-calculated when the
// zoom actually changes
protected AffineTransform getTransformation() {
return transformation;
}
private Shape testPath;
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
if (testPath != null) {
g2.setColor(Color.RED);
g2.draw(testPath);
}
g2.setTransform(getTransformation());
g2.setColor(_fillColor);
g2.fillRect(_rectangle.x, _rectangle.y, _rectangle.width, _rectangle.height);
g2.setColor(Color.BLACK);
g2.drawRect(_rectangle.x, _rectangle.y, _rectangle.width, _rectangle.height);
g2.dispose();
}
// This is purly for test purposes and you could simply
// create based on needs at the time
// Alternativly, you could apply a simular logic to it as the
// AffineTransformation and each time the zoom is changed,
// you could create a new, reusable, instance
protected Shape createTransformedShape() {
AffineTransform at = getTransformation();
PathIterator pathIterator = _rectangle.getPathIterator(at);
GeneralPath path = new GeneralPath();
path.append(pathIterator, true);
testPath = path;
return path;
}
#Override
public void mouseMoved(MouseEvent e) {
Shape shape = createTransformedShape();
_fillColor = Color.WHITE;
if (shape.contains(e.getPoint())) {
_fillColor = Color.GREEN;
}
repaint();
}
#Override
public void mousePressed(MouseEvent e) {
// _startPoint = null;
// _fillColor = Color.WHITE;
//
// AffineTransform at = getTransformation();
// Point2D zoomPoint = zoomedPointFrom(e.getPoint());
// PathIterator pathIterator = _rectangle.getPathIterator(at);
// GeneralPath path = new GeneralPath();
// path.append(pathIterator, true);
//
// if (path.contains(zoomPoint)) {
// _startPoint = e.getPoint();
// _fillColor = Color.GREEN;
// xdragOffset = _startPoint.x - _rectangle.x;
// ydragOffset = _startPoint.y - _rectangle.y;
// }
// repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
// if (_startPoint != null) {
// int diffX = e.getX() - _startPoint.x;
// int diffY = e.getY() - _startPoint.y;
//
// _rectangle.x = _startPoint.x + diffX - xdragOffset;
// _rectangle.y = _startPoint.y + diffY - ydragOffset;
// } else {
// _fillColor = Color.WHITE;
// if (_rectangle.contains(e.getPoint())) {
// _fillColor = Color.GREEN;
// }
// }
// repaint();
}
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
Point2D zoomAnchor = e.getPoint();
prevZoomFactor = zoomFactor;
if (e.getWheelRotation() < 0) {
zoomFactor = Math.max(zoomFactor / 1.1, MIN_ZOOM_FACTOR);
}
if (e.getWheelRotation() > 0) {
zoomFactor = Math.min(zoomFactor * 1.1, MAX_ZOOM_FACTOR);
}
transformation = new AffineTransform();
double zoomDiv = zoomFactor / prevZoomFactor;
xOffset = (zoomDiv) * (xOffset) + (1 - zoomDiv) * zoomAnchor.getX();
yOffset = (zoomDiv) * (yOffset) + (1 - zoomDiv) * zoomAnchor.getX();
transformation.translate(xOffset, yOffset);
transformation.scale(zoomFactor, zoomFactor);
createTransformedShape();
repaint();
}
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
}
After some digging on the internet, I found another way to do this...
All the complicated logic remains inside the mouse wheel event...
#Override public void mouseWheelMoved(MouseWheelEvent e) {
try {
if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
double scaleValue = scale - (0.1 * e.getWheelRotation());
scaleValue = scaleValue < 0.1 ? 0.1 : scaleValue;
scaleValue = scaleValue > 3 ? 3 : scaleValue;
scale = scaleValue;
Point2D p1 = e.getPoint();
Point2D p2 = null;
p2 = tx.inverseTransform(p1, null);
tx.setToIdentity();
tx.translate(p1.getX(), p1.getY());
tx.scale(scale, scale);
tx.translate(-p2.getX(), -p2.getY());
repaint();
}
}
catch (Throwable ex) {
throw new RuntimeException(ex);
}
}
In the paintComponent, the call is quite simple:
#Override protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setTransform(tx);
g2.setColor(Color.BLACK);
g2.draw(getBounds());
g2.setColor(_color);
g2.fill(rect1);
g2.setColor(Color.BLACK);
g2.draw(rect1);
g2.setColor(Color.BLUE);
g2.draw(rect2);
g2.dispose();
}
All mouse events are handled the same way. I created a routine to convert the original mouse event's coordinates ...
private final Point transformMouseEventPoint(MouseEvent event) {
try {
Point2D p = tx.inverseTransform(
event.getPoint(), null);
return new Point((int)p.getX(), (int)p.getY());
}
catch(Throwable e) {
throw new RuntimeException(e);
}
}
This is how it is used
#Override public void mousePressed(MouseEvent e) {
try {
_color = Color.WHITE;
_startPoint = null;
Point p = transformMouseEventPoint(e);
if(rect1.contains(p)) {
_color = Color.RED;
_startPoint = p;
xOffset = _startPoint.x - (int)rect1.getX();
yOffset = _startPoint.y - (int)rect1.getY();
}
repaint();
}
catch (Throwable e1) {
throw new RuntimeException(e1);
}
}
Next challenge is to add scrollbars to the scaled workspace
I am very new to Java but I have been working on a scrolling background game, like Geometry Dash. It is very bare bones with just some clouds to indicate that the background is moving, but I am now confronted with the problem of making it so my player can jump up then fall back down by pressing the arrow up key, like a jumping motion. I hope there is a simple solution to my problem, so that someone can help me and I understand it. I have made it so the player can jump up, but I have not been able to make it go back down after it jumps. Any help would be greatly appreciated. Thanks!
here is the code:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Rectangle2D;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
/**
*
* #author kids
*/
public class game extends javax.swing.JFrame {
private PaintSurface canvas;
int x_position = 0;
int y_position = 580;
int x_speed = 7;
int enemy_posX = 0;
int enemy_posY = 560;
int x_pos = 0;
int y_pos = 0;
int x_pos2 = -1200;
int x_position2 = -1200;
int enemy_posX2 = -1150;
int enemy_posY2 = 560;
int cloudOnex = 30;
int cloudOney = 70;
int cloud2x = -1150;
int cloud2y = 70;
int cloud3x = 700;
int cloud3y = 70;
int cloud4x = -600;
int cloud4y = 70;
int playerx =400;
int playery = 540;
/**
* Creates new form game
*/
public game() {
JPanel btnPanel = new JPanel(new FlowLayout());
JButton btnUp = new JButton("Move Up ");
btnPanel.add(btnUp);
btnUp.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
playery += 10;
canvas.repaint();
requestFocus(); // change the focus to JFrame to receive KeyEvent
}
});
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
// "super" JFrame fires KeyEvent
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent evt) {
switch (evt.getKeyCode()) {
case KeyEvent.VK_UP:
playery -= 22;
repaint();
break;
}
}
});
this.setTitle("Scrolling Game");
this.setSize(1200, 650);
// super.setBackground(Color.YELLOW);
this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);
this.add(new PaintSurface(), BorderLayout.CENTER);
this.setVisible(true);
canvas = new PaintSurface();
this.add(canvas, BorderLayout.CENTER);
//settings for the form, handling things such as exiting and size
Timer timer = new Timer(10, e -> {
canvas.movement();
canvas.check();
canvas.repaint();
});
timer.start();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
pack();
}// </editor-fold>
class PaintSurface extends JComponent {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Rectangle2D background = new Rectangle2D.Float(x_pos, y_pos, 1200, 650);
g2.setColor(Color.CYAN);
g2.fill(background);
Rectangle2D ground = new Rectangle2D.Float(x_position, y_position, 1200, 30);
g2.setColor(Color.GREEN);
g2.fill(ground);
Rectangle2D cloudOne = new Rectangle2D.Float(cloudOnex, cloudOney, 70, 70);
g2.setColor(Color.WHITE);
g2.fill(cloudOne);
Rectangle2D cloudThree = new Rectangle2D.Float(cloud3x, cloud3y, 70, 70);
g2.setColor(Color.WHITE);
g2.fill(cloudThree);
Rectangle2D background2 = new Rectangle2D.Float(x_pos2, y_pos, 1200, 650);
g2.setColor(Color.CYAN);
g2.fill(background2);
Rectangle2D ground2 = new Rectangle2D.Float(x_position2, y_position, 1200, 30);
g2.setColor(Color.GREEN);
g2.fill(ground2);
Rectangle2D cloudTwo = new Rectangle2D.Float(cloud2x, cloud2y, 70, 70);
g2.setColor(Color.WHITE);
g2.fill(cloudTwo);
Rectangle2D cloudFour = new Rectangle2D.Float(cloud4x, cloud4y, 70, 70);
g2.setColor(Color.WHITE);
g2.fill(cloudFour);
Rectangle2D player = new Rectangle2D.Float(playerx, playery,40,40);
g2.setColor(Color.red);
g2.fill(player);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
/**
* #param args the command line arguments
*/
}
public void movement(){
cloudOnex += 10;
cloud2x += 10;
cloud3x += 10;
cloud4x += 10;
x_position += 10;
x_pos += 10;
x_position2 += 10;
x_pos2 += 10;
enemy_posX += 10;
enemy_posX2 += 10;
try { Thread.sleep(20); } /* this will pause for 50 milliseconds */
catch (InterruptedException e) { System.err.println("sleep exception"); }
}
public void check(){
if (x_pos == 1200 ) {
x_pos = -1200;
//x_position = -1200;
repaint();
}
if (x_pos2 == 1200) {
x_pos2 = -1200;
// x_position2 = -1200;
repaint();
}
if (x_position == 1200) {
x_position = -1200;
repaint();
}
if (x_position2 == 1200) {
x_position2 = -1200;
repaint();
}
if (cloudOnex == 1200) {
cloudOnex = -1150;
repaint();
}
if (cloud2x == 1200){
cloud2x = -1150;
repaint();
}
// if (x_position2 > 1300) {
// x_position2 = -600;
// repaint();
// }
}
}
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(game.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(game.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(game.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(game.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new game().setVisible(true);
}
});
}
// Variables declaration - do not modify
// End of variables declaration
}
The simplest way to do this is to make the character go up, and then go down after a certain time. To do this replace the addKeyListener code in your function with the following:
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent evt) {
switch (evt.getKeyCode()) {
case KeyEvent.VK_UP:
playery -= 22;
repaint();
new java.util.Timer().schedule(
new java.util.TimerTask() {
#Override
public void run() {
playery += 22;
}
},
100
);
break;
}
}
});
This uses java.util.TimerTask, which allows you to delay an action.
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.*;
public class NewJFrame extends JFrame {
private Graphics g1;
private JLabel label = new JLabel();
// holds information of all businesses
private Object[][] busInfo = new Object[10][15];
public NewJFrame() {
initComponents();
g1 = jPanel1.getGraphics();
}
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jPanel1 = new javax.swing.JPanel();
jButton1 = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 858, Short.MAX_VALUE));
jPanel1Layout.setVerticalGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 564, Short.MAX_VALUE));
jButton1.setText("Click Me");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(
javax.swing.GroupLayout.Alignment.TRAILING,
layout.createSequentialGroup().addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jButton1).addGap(425, 425, 425))
.addGroup(layout.createSequentialGroup().addGap(48, 48, 48)
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(61, Short.MAX_VALUE)));
layout.setVerticalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup().addGap(28, 28, 28)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED).addComponent(jButton1)));
pack();
}// </editor-fold>
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
printBarChart(2, 1);
System.out.println(getSize());
}
public static void main(String args[]) {
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
java.awt.EventQueue.invokeLater(() -> {
new NewJFrame().setVisible(true);
});
}
public void printBarChart(int bestBus, int worstBus) {
busInfo[0][7] = 24325.08;
busInfo[1][7] = 15394.59;
busInfo[2][7] = 186719.84;
int y = jPanel1.getSize().height;
int x = jPanel1.getSize().width;
double balance, maxScale = (double) busInfo[bestBus][7] + 650;
int sameBusDistance, diffBusDistance = 0, scaleNum, maxPoint;
for (int i = 0; i <= 2; ++i) {
if (i == 0) {
diffBusDistance = 0;
} else {
diffBusDistance += 65;
}
// color of best business
if (i == bestBus) {
g1.setColor(Color.YELLOW);
// color of worst business
} else if (i == worstBus) {
g1.setColor(Color.RED);
// color of other businesses (neither best nor worst)
} else {
g1.setColor(Color.BLACK);
}
balance = (double) busInfo[i][7];
sameBusDistance = 25;
scaleNum = y - 100;
maxPoint = scaleNum - (scaleNum * (int) balance / (int) maxScale) + 50;
g1.drawLine(125 + diffBusDistance, y - 50, 125 + diffBusDistance, maxPoint);
g1.drawLine(125 + sameBusDistance + diffBusDistance, y - 50, 125 + sameBusDistance + diffBusDistance,
maxPoint);
g1.drawLine(125 + sameBusDistance + diffBusDistance, maxPoint, 125 + diffBusDistance, maxPoint);
jPanel1.add(label);
jPanel1.setLayout(null);
label.setSize(100, 50);
label.setFont(label.getFont().deriveFont(8f));
label.setLocation(125 + sameBusDistance + diffBusDistance - 30, maxPoint - 50);
label.setText("" + busInfo[i][7]);
}
}
// Variables declaration - do not modify
private javax.swing.JButton jButton1;
private javax.swing.JPanel jPanel1;
// End of variables declaration
}
Line drawn by Graphics type variable disappears when making a label for it
This code is in a for loop for the number of businesses. I will attach a picture of the problem.The first bar works just fine:
The second however removes the first bar and its label from view:
Printing labels for Bar Charts causing other bars and their labels to dissapear
Again, I suggest that you don't use getGraphics() called on a component. By now you should have minimized and restored your GUI to see that the drawing is not stable when you minimize and restore the GUI. I suggest that you draw in the paintComponent of your JPanel.
There is an exception however -- if you draw in a BufferedImage, you can use a Graphics object obtained from it, and then display the image in an ImageIcon in a JLabel. For example in the code below I create a JLabel filled with an empty image (to give it size). I then fill the image with some bar chart data on button press, put the image into an ImageIcon and then set the JLabel with that icon by calling setIcon(...) on it:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class DrawInImage extends JPanel {
private static final int IMG_W = 900;
private static final int IMG_H = 700;
private static final int GAP = 20;
private BufferedImage img = new BufferedImage(IMG_W, IMG_H, BufferedImage.TYPE_INT_ARGB);
private Icon icon = new ImageIcon(img);
private JLabel label = new JLabel(icon);
private int[] data = { 4, 2, 9, 7, 3, 8, 2, 8 };
public DrawInImage() {
JPanel btnPanel = new JPanel();
btnPanel.add(new JButton(new AbstractAction("Press Me") {
#Override
public void actionPerformed(ActionEvent arg0) {
printBarChart();
}
}));
setLayout(new BorderLayout());
add(label);
add(btnPanel, BorderLayout.PAGE_END);
}
private void printBarChart() {
// create new image
img = new BufferedImage(IMG_W, IMG_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics(); // get image's graphics
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 18));
// get sizes of drawing area
int totalWidth = IMG_W - 2 * GAP;
int totalHeight = IMG_H - 2 * GAP;
// number of columns including gaps
int columns = 2 * data.length + 1;
// calc the max data + 1
int maxData = 0;
for (int i : data) {
if (i > maxData) {
maxData = i;
}
}
maxData++; // + 1
for (int i = 0; i < data.length; i++) {
int x1 = GAP + ((2 * i + 1) * totalWidth) / columns;
int x2 = GAP + ((2 * i + 2) * totalWidth) / columns;
int y1 = GAP + (totalHeight * (maxData - data[i])) / maxData;
int y2 = GAP + totalHeight;
float hue = (float) i / (float) data.length;
Color c = Color.getHSBColor(hue, 1f, 1f);
g2.setColor(c);
g2.fillRect(x1, y1, x2 - x1, y2 - y1);
g2.setColor(Color.BLACK);
String text = "Data " + (i + 1);
int strX = x1;
int strY = y1 - GAP / 2;
g2.drawString(text, strX, strY);
}
g2.dispose(); // dispose of graphics objects *we* create
icon = new ImageIcon(img); // create new icon
label.setIcon(icon); // display in label
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Draw In Image");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new DrawInImage());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
Which displays as
Here is what I have so far, I tried creating the draw function just to test if that would work. The palette is just another gui window that will have color options once I figure this saving problem out first
import csc260final.Palette;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JOptionPane;
/**
*
* #author Jared Hughes
*/
public class Canvas extends javax.swing.JFrame {
/**
* Creates new form Canvas
*/
Draw line;
private int curX, curY, oldX, oldY;
public Graphics2D g2;
Palette palette;
public Canvas() {
initComponents();
palette = new Palette();
palette.setVisible(true);
}
public void draw(){
g2 = (Graphics2D) jPanel1.getGraphics();
g2.setColor(Color.yellow);
g2.setStroke(new BasicStroke(10));
g2.drawLine(oldX, oldY, curX, curY);
}
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D)g;
super.paint(g);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jPanel1 = new javax.swing.JPanel();
jButton1 = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jPanel1.setBackground(new java.awt.Color(255, 255, 255));
jPanel1.setPreferredSize(new java.awt.Dimension(1130, 550));
jPanel1.setRequestFocusEnabled(false);
jPanel1.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
public void mouseDragged(java.awt.event.MouseEvent evt) {
jPanel1MouseDragged(evt);
}
public void mouseMoved(java.awt.event.MouseEvent evt) {
jPanel1MouseMoved(evt);
}
});
jPanel1.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
jPanel1MouseClicked(evt);
}
public void mouseEntered(java.awt.event.MouseEvent evt) {
jPanel1MouseEntered(evt);
}
public void mouseExited(java.awt.event.MouseEvent evt) {
jPanel1MouseExited(evt);
}
public void mousePressed(java.awt.event.MouseEvent evt) {
jPanel1MousePressed(evt);
}
public void mouseReleased(java.awt.event.MouseEvent evt) {
jPanel1MouseReleased(evt);
}
});
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 1130, Short.MAX_VALUE)
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 550, Short.MAX_VALUE)
);
jButton1.setText("jButton1");
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jButton1)
.addGap(94, 94, 94))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 28, Short.MAX_VALUE)
.addComponent(jButton1)
.addContainerGap())
);
pack();
}// </editor-fold>
private void jPanel1MousePressed(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
// save x and y when mouse is pressed
curX = evt.getX();
curY = evt.getY();
oldX = curX;
oldY = curY;
}
private void jPanel1MouseDragged(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
// get x and y when mouse is dragged
curX = evt.getX();
curY = evt.getY();
g2 = (Graphics2D) jPanel1.getGraphics();
g2.setColor(Color.yellow);
g2.setStroke(new BasicStroke(10));
g2.drawLine(oldX, oldY, curX, curY);
oldX = curX;
oldY = curY;
}
private void jPanel1MouseClicked(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
}
private void jPanel1MouseEntered(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
}
private void jPanel1MouseMoved(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
}
private void jPanel1MouseExited(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
}
private void jPanel1MouseReleased(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
}
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(Canvas.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(Canvas.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(Canvas.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(Canvas.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Canvas().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JButton jButton1;
private javax.swing.JPanel jPanel1;
// End of variables declaration
}
Your Swing drawing is being done incorrectly. You should not draw with a Graphics object obtained by calling getGraphics() on a component. This will return a Graphics object that is short lived, risking disappearing graphics or worse, a NullPointerException. Instead, draw in the JPanel's paintComponent(...) method either directly, or indirectly by drawing on a BufferedImage (yes, you can get its Graphics object via getGraphics()) and then drawing the BufferedImage to the GUI within the paintComponent method.
Useful Java Tutorials:
Lesson: Performing Custom Painting: introductory tutorial to Swing graphics
Painting in AWT and Swing: advanced tutorial on Swing graphics
Small nitpicks:
Avoid giving your classes names that clash with core Java classes, such as Canvas. This will help prevent confusing others and your future self.
When posting code here, we greatly appreciate it if you strive to format it well, including judicious use of empty lines. Your code above has several large empty regions that make following it hard. A single empty line here or there is OK, but a lot, not so much.
For example:
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class TestDrawingCanvas extends JPanel {
private DrawingCanvas drawingCanvas = new DrawingCanvas();
public TestDrawingCanvas() {
JPanel btnPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
btnPanel.add(new JButton(new ClearAction()));
setLayout(new BorderLayout());
add(drawingCanvas, BorderLayout.CENTER);
add(btnPanel, BorderLayout.PAGE_END);
}
private class ClearAction extends AbstractAction {
public ClearAction() {
super("Clear Canvas");
putValue(MNEMONIC_KEY, KeyEvent.VK_C);
}
#Override
public void actionPerformed(ActionEvent e) {
drawingCanvas.clear();
}
}
private static void createAndShowGui() {
TestDrawingCanvas mainPanel = new TestDrawingCanvas();
JFrame frame = new JFrame("Drawing Canvas");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
#SuppressWarnings("serial")
class DrawingCanvas extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 600;
public static final Color LINE_COLOR = Color.YELLOW;
public static final Stroke IMG_STROKE = new BasicStroke(10f);
private Color lineColor = LINE_COLOR;
private BufferedImage image;
public DrawingCanvas() {
setBackground(Color.WHITE);
image = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null) {
g.drawImage(image, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
public void setLineColor(Color lineColor) {
this.lineColor = lineColor;
}
public void clear () {
image = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
repaint();
}
private class MyMouse extends MouseAdapter {
private Graphics2D imgG2d;
private Point p1;
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
imgG2d = image.createGraphics();
imgG2d.setColor(lineColor);
imgG2d.setStroke(IMG_STROKE);
p1 = e.getPoint();
}
#Override
public void mouseReleased(MouseEvent e) {
drawLine(e);
imgG2d.dispose();
p1 = null;
imgG2d = null;
}
#Override
public void mouseDragged(MouseEvent e) {
drawLine(e);
p1 = e.getPoint();
}
private void drawLine(MouseEvent e) {
if (imgG2d == null || p1 == null) {
return;
}
Point p2 = e.getPoint();
int x1 = p1.x;
int y1 = p1.y;
int x2 = p2.x;
int y2 = p2.y;
imgG2d.drawLine(x1, y1, x2, y2);
repaint();
}
}
}
I have aJPanel in which I draw lines to create an illusion of pencil. This panel is in aScrollPane.
When I resize the panel one call to revalidate() method is automatically placed and all my drawn lines in this panel are gone. Is there any way to keep my drawn line in the panel with the new size ?
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
*
* #author Sanjeev
*/
public class WorkArea extends JFrame implements ActionListener, MouseListener, MouseMotionListener
{
private final int PEN_OP = 1;
private final int ERASER_OP = 2;
private final int SCROLL_OP = 3;
private int mousex = 0;
private int mousey = 0;
private int prevx = 0;
private int prevy = 0;
private boolean initialPen = true;
private boolean initialEraser = true;
private int eraserLength = 5;
private int opStatus = PEN_OP;
private Color mainColor = new Color(0,0,0);
private int drawPanelHeight =1000;
public WorkArea()
{
initComponents();
setLocationRelativeTo(null);
pencilButton.addActionListener(this);
eraserButton.addActionListener(this);
drawPanel.addMouseMotionListener(this);
drawPanel.addMouseListener(this);
drawPanel.add(new TestPane());
this.addMouseListener(this);
this.addMouseMotionListener(this);
}
private void initComponents() {
headerPanel = new javax.swing.JPanel();
backButton = new javax.swing.JLabel();
headerImage = new javax.swing.JLabel();
controlPanel = new javax.swing.JPanel();
scrollButton = new javax.swing.JButton();
pencilButton = new javax.swing.JButton();
eraserButton = new javax.swing.JButton();
drawingPanel = new javax.swing.JPanel();
drawingScrollPane = new javax.swing.JScrollPane();
drawPanel = new javax.swing.JPanel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("v0.1");
setBackground(new java.awt.Color(237, 254, 255));
setBounds(new java.awt.Rectangle(0, 0, 513, 693));
setResizable(false);
headerPanel.setBackground(new java.awt.Color(237, 254, 255));
headerPanel.setPreferredSize(new java.awt.Dimension(513, 25));
headerPanel.setLayout(null);
backButton.setBackground(new java.awt.Color(237, 254, 255));
backButton.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
backButton.setForeground(new java.awt.Color(255, 255, 255));
backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/back-arrow.png"))); // NOI18N
backButton.setText("Back");
backButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
backButton.setPreferredSize(new java.awt.Dimension(40, 20));
headerPanel.add(backButton);
backButton.setBounds(0, 3, 40, 20);
headerImage.setBackground(new java.awt.Color(237, 254, 255));
headerImage.setFont(new java.awt.Font("Tahoma", 1, 14)); // NOI18N
headerImage.setForeground(new java.awt.Color(255, 255, 255));
headerImage.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/topbar_ipad_wide.png"))); // NOI18N
headerImage.setText("Work Area");
headerImage.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
headerImage.setPreferredSize(new java.awt.Dimension(513, 25));
headerPanel.add(headerImage);
headerImage.setBounds(0, 0, 513, 25);
controlPanel.setBackground(new java.awt.Color(237, 254, 255));
controlPanel.setPreferredSize(new java.awt.Dimension(90, 670));
controlPanel.setLayout(null);
scrollButton.setBackground(new java.awt.Color(237, 254, 255));
scrollButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/up_down_ipad.png"))); // NOI18N
scrollButton.setPreferredSize(new java.awt.Dimension(60, 60));
scrollButton.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
scrollButtonMouseClicked(evt);
}
});
controlPanel.add(scrollButton);
scrollButton.setBounds(20, 570, 60, 60);
pencilButton.setBackground(new java.awt.Color(237, 254, 255));
pencilButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/pencil_ipad.png"))); // NOI18N
pencilButton.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
pencilButtonMouseClicked(evt);
}
});
controlPanel.add(pencilButton);
pencilButton.setBounds(20, 450, 60, 60);
eraserButton.setBackground(new java.awt.Color(237, 254, 255));
eraserButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/eraser_ipad.png"))); // NOI18N
eraserButton.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
eraserButtonMouseClicked(evt);
}
});
controlPanel.add(eraserButton);
eraserButton.setBounds(20, 510, 60, 60);
drawingPanel.setBackground(new java.awt.Color(237, 254, 255));
drawingPanel.setPreferredSize(new java.awt.Dimension(420, 670));
drawingPanel.setLayout(null);
drawingScrollPane.setBorder(null);
drawingScrollPane.setPreferredSize(new java.awt.Dimension(423, 1000));
drawPanel.setBackground(new java.awt.Color(237, 254, 255));
drawPanel.setPreferredSize(new java.awt.Dimension(400, 1000));
drawPanel.setLayout(null);
drawingScrollPane.setViewportView(drawPanel);
drawingPanel.add(drawingScrollPane);
drawingScrollPane.setBounds(0, 0, 424, 670);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 513, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(headerPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 513, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(controlPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 423, Short.MAX_VALUE)))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 93, Short.MAX_VALUE)
.addComponent(drawingPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 420, javax.swing.GroupLayout.PREFERRED_SIZE)))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 693, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(headerPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 668, Short.MAX_VALUE)))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 23, Short.MAX_VALUE)
.addComponent(controlPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 670, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 23, Short.MAX_VALUE)
.addComponent(drawingPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 670, javax.swing.GroupLayout.PREFERRED_SIZE)))
);
pack();
}
#Override
public void actionPerformed(ActionEvent e)
{
if (e.getActionCommand() == "Pen")
opStatus = PEN_OP;
if (e.getActionCommand() == "Eraser")
opStatus = ERASER_OP;
if(e.getActionCommand() == "Scroll")
opStatus = SCROLL_OP;
}
private void pencilButtonMouseClickedTest(java.awt.event.MouseEvent evt)
{
opStatus = PEN_OP;
Graphics g = drawPanel.getGraphics();
if (initialPen)
{
setGraphicalDefaults(evt);
initialPen = false;
g.drawLine(prevx,prevy,mousex,mousey);
}
if (mouseHasMoved(evt))
{
mousex = evt.getX();
mousey = evt.getY();
g.drawLine(prevx,prevy,mousex,mousey);
prevx = mousex;
prevy = mousey;
}
}
private void eraserButtonMouseClickedTest(java.awt.event.MouseEvent evt)
{
opStatus = ERASER_OP;
Graphics g = drawPanel.getGraphics();
if (initialEraser)
{
setGraphicalDefaults(evt);
initialEraser = false;
mousex = evt.getX();
mousey = evt.getY();
System.out.println("Initial Eraser ::::::::x's value is : "+prevx+" , "+mousey+" and y's value is : "+mousex+" , "+mousey);
g.setColor(new java.awt.Color(237,254,255));
g.fillRect(mousex-eraserLength, mousey-eraserLength,eraserLength*2,eraserLength*2);
//g.setColor(Color.black); //Eraser Border
g.drawRect(mousex-eraserLength,mousey-eraserLength,eraserLength*2,eraserLength*2);
prevx = mousex;
prevy = mousey;
}
if (mouseHasMoved(evt))
{
System.out.println("Eraser ::::::::x's value is : "+prevx+" , "+mousey+" and y's value is : "+mousex+" , "+mousey);
g.setColor(new java.awt.Color(237,254,255));
g.drawRect(prevx-eraserLength, prevy-eraserLength,eraserLength*2,eraserLength*2);
mousex = evt.getX();
mousey = evt.getY();
/* Draw eraser block to panel */
g.setColor(new java.awt.Color(237,254,255));
g.fillRect(mousex-eraserLength, mousey-eraserLength,eraserLength*2,eraserLength*2);
g.setColor(Color.black);//Eraser Border
g.drawRect(mousex-eraserLength,mousey-eraserLength,eraserLength*2,eraserLength*2);
prevx = mousex;
prevy = mousey;
}
}
private void scrollButtonMouseClicked(java.awt.event.MouseEvent evt) {
opStatus = SCROLL_OP;
drawingScrollPane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {
#Override
public void adjustmentValueChanged(AdjustmentEvent e)
{
int extent,curValue;
extent = drawingScrollPane.getVerticalScrollBar().getModel().getExtent();
curValue = drawingScrollPane.getVerticalScrollBar().getValue()+extent;
if(curValue==drawPanel.getHeight())
{
System.out.println("value of scroll equals to Max value....");
drawPanel.setPreferredSize(new Dimension(423,drawPanelHeight*4));
}
System.out.println("Value: " + curValue + " Max: " + drawingScrollPane.getVerticalScrollBar().getMaximum());
}
});
}
private void eraserButtonMouseClicked(java.awt.event.MouseEvent evt) {
eraserButtonMouseClickedTest(evt);
updateMouseCoordinates(evt);
}
private void pencilButtonMouseClicked(java.awt.event.MouseEvent evt) {
opStatus = PEN_OP;
}
public boolean mouseHasMoved(MouseEvent e)
{
return (mousex != e.getX() || mousey != e.getY());
}
public void setGraphicalDefaults(MouseEvent e)
{
mousex = e.getX();
mousey = e.getY();
prevx = e.getX();
prevy = e.getY();
}
#Override
public void mouseDragged(MouseEvent e)
{
updateMouseCoordinates(e);
switch (opStatus)
{
case PEN_OP : pencilButtonMouseClickedTest(e);
break;
case ERASER_OP: eraserButtonMouseClicked(e);
break;
case SCROLL_OP: scrollButtonMouseClicked(e);
break;
}
}
public void mouseReleased(MouseEvent e)
{
updateMouseCoordinates(e);
switch (opStatus)
{
case PEN_OP : releasedPen();
break;
case ERASER_OP : releasedEraser();
break;
}
}
public void mouseEntered(MouseEvent e)
{
updateMouseCoordinates(e);
}
public void releasedPen()
{
initialPen = true;
}
public void releasedEraser()
{
initialEraser = true;
Graphics g = drawPanel.getGraphics();
g.setColor(mainColor.white);
g.drawRect(mousex-eraserLength,mousey-eraserLength,eraserLength*2,eraserLength*2);
}
public void updateMouseCoordinates(MouseEvent e)
{
String xCoor ="";
String yCoor ="";
if (e.getX() < 0) xCoor = "0";
else
{
xCoor = String.valueOf(e.getX());
}
if (e.getY() < 0) xCoor = "0";
else
{
yCoor = String.valueOf(e.getY());
}
}
public static void main(String args[]) {
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(WorkArea.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(WorkArea.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(WorkArea.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(WorkArea.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new WorkArea().setVisible(true);
}
});
}
private javax.swing.JLabel backButton;
private javax.swing.JPanel controlPanel;
private javax.swing.JPanel drawPanel;
private javax.swing.JPanel drawingPanel;
private javax.swing.JScrollPane drawingScrollPane;
private javax.swing.JButton eraserButton;
private javax.swing.JLabel headerImage;
private javax.swing.JPanel headerPanel;
private javax.swing.JButton pencilButton;
private javax.swing.JButton scrollButton;
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
updateMouseCoordinates(e);
}
#Override
public void mouseMoved(MouseEvent e) {
updateMouseCoordinates(e);
}
#Override
public void mousePressed(MouseEvent e) {
updateMouseCoordinates(e);
}
}
I assume you are drawing to the JPanel by using getGraphics() and rendering your out put to it.
You have now seen why you shouldn't do this. When the component is repainted, anything previously painted to is wiped cleaned and you are expected to repaint the contents.
Start by overriding paintComponent and updating all the lines within this method (don't forget to call super.paintComponent
See Performing Custom Painting and Painting in AWT and Swing for more details
For example..
Drawing a rectangle that won't disappear in next paint
MouseEvent is not registering a release when I release the mouse button
Updated with example
This is a modified version of the answer to MouseEvent is not registering a release when I release the mouse button which includes a scroll pane...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
public class MouseDraggedTest {
public static void main(String[] args) {
new MouseDraggedTest();
}
public MouseDraggedTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(new TestPane()));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Map<Point, List<Point>> mapPoints;
private Point currentPoint;
public TestPane() {
mapPoints = new HashMap<>(25);
MouseAdapter mouseListener = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
currentPoint = e.getPoint();
mapPoints.put(currentPoint, new ArrayList<Point>(25));
}
#Override
public void mouseReleased(MouseEvent e) {
List<Point> points = mapPoints.get(currentPoint);
if (points.isEmpty()) {
mapPoints.remove(currentPoint);
}
currentPoint = null;
}
#Override
public void mouseDragged(MouseEvent me) {
List<Point> points = mapPoints.get(currentPoint);
points.add(me.getPoint());
repaint();
}
};
addMouseListener(mouseListener);
addMouseMotionListener(mouseListener);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 800);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Point startPoint : mapPoints.keySet()) {
List<Point> points = mapPoints.get(startPoint);
for (Point p : points) {
if (startPoint != null) {
g.drawLine(startPoint.x, startPoint.y, p.x, p.y);
}
startPoint = p;
}
}
}
}
}
Updated with a BufferedImage example
Because you need to supply more operations than just drawing, you may find it easier to use BufferedImage as your primary drawing surface and render this to your DrawingPanel
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.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToggleButton;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MyPicture {
public static void main(String[] args) {
new MyPicture();
}
public MyPicture() {
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 enum DrawOperation {
Draw,
Erase
}
public class TestPane extends JPanel {
private DrawOperation op;
private JToggleButton pencil;
private JToggleButton eraser;
private DrawPane drawPane;
public TestPane() {
setLayout(new BorderLayout());
drawPane = new DrawPane();
MouseAdapter adapter = new MouseAdapter() {
private Point startPoint;
#Override
public void mouseEntered(MouseEvent e) {
drawPane.updateDrawCursor(e.getPoint(), op);
}
#Override
public void mouseExited(MouseEvent e) {
drawPane.removeDrawCursor();
}
#Override
public void mousePressed(MouseEvent e) {
startPoint = e.getPoint();
}
#Override
public void mouseReleased(MouseEvent e) {
startPoint = null;
}
#Override
public void mouseDragged(MouseEvent e) {
drawPane.applyOperation(startPoint, e.getPoint(), op);
drawPane.updateDrawCursor(e.getPoint(), op);
startPoint = e.getPoint();
}
#Override
public void mouseMoved(MouseEvent e) {
drawPane.updateDrawCursor(e.getPoint(), op);
}
};
drawPane.addMouseListener(adapter);
drawPane.addMouseMotionListener(adapter);
JPanel operations = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
pencil = new JToggleButton("Draw");
eraser = new JToggleButton("Erase");
ButtonGroup bgOps = new ButtonGroup();
bgOps.add(pencil);
bgOps.add(eraser);
operations.add(pencil, gbc);
operations.add(eraser, gbc);
pencil.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
op = DrawOperation.Draw;
}
});
eraser.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
op = DrawOperation.Erase;
}
});
add(operations, BorderLayout.WEST);
add(new JScrollPane(drawPane));
}
}
public class DrawPane extends JPanel {
private BufferedImage image;
private Shape drawCursor;
private Point cursorPoint;
private int eraseSize = 20;
public DrawPane() {
image = new BufferedImage(400, 400, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = image.createGraphics();
g2d.setBackground(Color.WHITE);
g2d.fillRect(0, 0, 400, 400);
g2d.dispose();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (image != null) {
g2d.drawImage(image, 0, 0, this);
}
if (drawCursor != null && cursorPoint != null) {
int x = (cursorPoint.x - (drawCursor.getBounds().width) / 2);
int y = (cursorPoint.y - (drawCursor.getBounds().height) / 2);
g2d.translate(x, y);
g2d.draw(drawCursor);
g2d.translate(-x, -y);
}
g2d.dispose();
}
public void updateDrawCursor(Point point, DrawOperation op) {
cursorPoint = point;
if (op != null) {
switch (op) {
case Draw:
drawCursor = new Ellipse2D.Float(0, 0, 4, 4);
break;
case Erase:
drawCursor = new Ellipse2D.Float(0, 0, eraseSize, eraseSize);
break;
}
} else {
drawCursor = null;
}
repaint();
}
protected void removeDrawCursor() {
drawCursor = null;
repaint();
}
protected void applyOperation(Point fromPoint, Point toPoint, DrawOperation op) {
if (image != null) {
if (op != null) {
Graphics2D g2d = image.createGraphics();
switch (op) {
case Draw:
g2d.setColor(Color.BLACK);
g2d.draw(new Line2D.Float(fromPoint, toPoint));
break;
case Erase:
g2d.setColor(Color.WHITE);
g2d.setStroke(new BasicStroke(eraseSize));
g2d.draw(new Line2D.Float(fromPoint, toPoint));
break;
}
g2d.dispose();
}
}
repaint();
}
}
}