Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Zooming in and zooming out within a panel

Tags:

java

swing

panel

I have a Panel in which some 2D objects are moving about. I have overridden paintComponent() as necessary. Now I want to be able to zoom in and zoom out that area. When zooming in, scrollbars will appear by which one can view the entire field by scrolling. While zooming in and out, the 2D objects should increase or decrease in size accordingly. Which Swing component or rather combination of components will help to achieve this?

like image 756
aps Avatar asked Jul 01 '11 03:07

aps


People also ask

What is zooming in and zooming out?

to (cause a camera or computer to) make the image of something or someone appear much larger and nearer, or much smaller and further away: At the beginning of the film, the camera zooms in to show two people sitting by the side of a river. Click on a photo of any student, and it zooms out to full-size.

How do I fix zoom in and zoom out?

Only one page is zoomed in/outIf you are zoomed out too far, you can zoom in by pressing Ctrl + Plus (+) If you are zoomed in too closely, you can zoom out by pressing Ctrl + Minus (-) If you prefer to reset the zoom level back to the default, press Ctrl + 0 (zero)

How to zoom in and zoom out in java?

Manually, we have to press CTRL+ADD to do Zoom In and we have to press CTRL+SUBTRACT to do zoom out.


2 Answers

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)
like image 173
Andreas Holstenson Avatar answered Sep 29 '22 12:09

Andreas Holstenson


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) {

    }

}
like image 41
Thanasis1101 Avatar answered Sep 29 '22 14:09

Thanasis1101