Zooming in and zooming out within a panel
Easiest way is to modify your panel and introduce a double indicating your zoom level. This double would indicate your scale, where 1 is normal and higher is zoomed in. You can use that double together with Graphics2D
in your paintComponent
.
Such as:
Graphics2D g2 = (Graphics2D) g;
int w = // real width of canvas
int h = // real height of canvas
// Translate used to make sure scale is centered
g2.translate(w/2, h/2);
g2.scale(scale, scale);
g2.translate(-w/2, -h/2);
For the scrolling, put your panel in a JScrollPane and combine that with a getPreferredSize that also uses your zoom scale. JScrollPane uses the preferred size of the component you put in it. It will show scrollbars if the preferred size exceeds its own size.
If you change the preferred size of your panel so that the width and height it returns is scaled you should be fine. Basically you can just return something like:
return new Dimension(w * scale, h * scale)
I know this question is old, but I thought I could post my solution in case it could be useful for someone in the future.
So, I created a class that extends JPanel which implements the MouseWheelListener in order to detect when the user rolls the mouse. My class also listens for dragging in order to move the contents when the user clicks and drags.
Code Explanation
First, in the constructor you must set this as the MouseWheelListener
addMouseWheelListener(this);
For the zoom in and out I used a boolean zoomer
(to indicate when the user rolls with the mouse) and two doubles zoomFactor
(to keep the current factor by which the objects' sizes are multiplied) and prevZoomFactor
(for the previous zoom factor).
private double zoomFactor = 1;
private double prevZoomFactor = 1;
private boolean zoomer;
I also override the paint()
method of the JPanel, in which (before drawing anything) when the user zooms (zoomer
=true) I scale the graphics by the zoomFactor
. Code:
@Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
if (zoomer) {
AffineTransform at = new AffineTransform();
at.scale(zoomFactor, zoomFactor);
prevZoomFactor = zoomFactor;
g2.transform(at);
zoomer = false;
}
// All drawings go here
}
Finally, I override the mouseWheelMoved
method of the MouseWheelListener, in which I increase the zoomFactor
(if the user rolls up) or decrease the zoomFactor
(if the user rolls down). Code:
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
zoomer = true;
//Zoom in
if (e.getWheelRotation() < 0) {
zoomFactor *= 1.1;
repaint();
}
//Zoom out
if (e.getWheelRotation() > 0) {
zoomFactor /= 1.1;
repaint();
}
}
Working Example
If you also want to use the drag function and want to zoom according to the position of the mouse, you can use the class below, which gets a BufferedImage as a parameter in the constructor in order to display something on screen.
I have also uploaded a project on GitHub called Zoomable-Java-Panel in which there is a functional example of what I showed above, which you can test and see how it can be implemented into a project.
package zoomable.panel;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
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.image.BufferedImage;
import javax.swing.JPanel;
/**
*
* @author Thanasis1101
* @version 1.0
*/
public class MainPanel extends JPanel implements MouseWheelListener, MouseListener, MouseMotionListener {
private final BufferedImage image;
private double zoomFactor = 1;
private double prevZoomFactor = 1;
private boolean zoomer;
private boolean dragger;
private boolean released;
private double xOffset = 0;
private double yOffset = 0;
private int xDiff;
private int yDiff;
private Point startPoint;
public MainPanel(BufferedImage image) {
this.image = image;
initComponent();
}
private void initComponent() {
addMouseWheelListener(this);
addMouseMotionListener(this);
addMouseListener(this);
}
@Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
if (zoomer) {
AffineTransform at = new AffineTransform();
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;
at.translate(xOffset, yOffset);
at.scale(zoomFactor, zoomFactor);
prevZoomFactor = zoomFactor;
g2.transform(at);
zoomer = false;
}
if (dragger) {
AffineTransform at = new AffineTransform();
at.translate(xOffset + xDiff, yOffset + yDiff);
at.scale(zoomFactor, zoomFactor);
g2.transform(at);
if (released) {
xOffset += xDiff;
yOffset += yDiff;
dragger = false;
}
}
// All drawings go here
g2.drawImage(image, 0, 0, this);
}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
zoomer = true;
//Zoom in
if (e.getWheelRotation() < 0) {
zoomFactor *= 1.1;
repaint();
}
//Zoom out
if (e.getWheelRotation() > 0) {
zoomFactor /= 1.1;
repaint();
}
}
@Override
public void mouseDragged(MouseEvent e) {
Point curPoint = e.getLocationOnScreen();
xDiff = curPoint.x - startPoint.x;
yDiff = curPoint.y - startPoint.y;
dragger = true;
repaint();
}
@Override
public void mouseMoved(MouseEvent e) {
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
released = false;
startPoint = MouseInfo.getPointerInfo().getLocation();
}
@Override
public void mouseReleased(MouseEvent e) {
released = true;
repaint();
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}