zoom using mouse and graphics
I draw in my JComponent some curves, etc .. with Graphics G ( not 2D ).
Now I want to use the scroll wheel of my mouse to zoom in and out.
Any tracks ?
I heard talk about a BuferredImage ?
There are a few considerations you need to take into account...
The end result will depend on what you want to achieve. If you are drawing curves using the Graphics2D API, it might be simpler to simply scale the coordinates each time the component is rendered. You will need to make sure that any changes in the scale are reflected in the preferred size of the component itself.
You could also render the "default" output to a BufferedImage
and simply use an AffineTransform
to change the scaling the is used to render the result, for example.
This simple uses a BufferedImage
and loads a picture from disk, but the basic concept is the same.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ZoomPane {
public static void main(String[] args) {
new ZoomPane();
}
public ZoomPane() {
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 JScrollPane(new TestPane()));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage img;
private float scale = 1;
public TestPane() {
try {
img = ImageIO.read(new File("/path/to/image"));
} catch (IOException ex) {
ex.printStackTrace();
}
addMouseWheelListener(new MouseAdapter() {
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
double delta = 0.05f * e.getPreciseWheelRotation();
scale += delta;
revalidate();
repaint();
}
});
}
@Override
public Dimension getPreferredSize() {
Dimension size = new Dimension(200, 200);
if (img != null) {
size.width = Math.round(img.getWidth() * scale);
size.height = Math.round(img.getHeight() * scale);
}
return size;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
Graphics2D g2d = (Graphics2D) g.create();
AffineTransform at = new AffineTransform();
at.scale(scale, scale);
g2d.drawImage(img, at, this);
g2d.dispose();
}
}
}
}
You could also scale the Graphics
context passed to your paintComponent
method directly.
The important thing here is to remember to reset the AffineTransform
after you have completed, otherwise it will be passed to other components when they are rendered, which won't generate the expected output...
This example basically creates a copy of the Graphics
context which we can manipulate and dispose of without effecting the original, making it simpler to mess with
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.event.MouseAdapter;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Path2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ZoomPane {
public static void main(String[] args) {
new ZoomPane();
}
public ZoomPane() {
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 JScrollPane(new TestPane()));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private float scale = 1;
public TestPane() {
addMouseWheelListener(new MouseAdapter() {
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
double delta = 0.05f * e.getPreciseWheelRotation();
scale += delta;
revalidate();
repaint();
}
});
}
@Override
public Dimension getPreferredSize() {
Dimension size = new Dimension(200, 200);
size.width = Math.round(size.width * scale);
size.height = Math.round(size.height * scale);
return size;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
AffineTransform at = new AffineTransform();
at.scale(scale, scale);
g2d.setTransform(at);
g2d.setColor(Color.RED);
// This is for demonstration purposes only
// I prefer to use getWidth and getHeight
int width = 200;
int height = 200;
Path2D.Float path = new Path2D.Float();
int seg = width / 3;
path.moveTo(0, height / 2);
path.curveTo(0, 0, seg, 0, seg, height / 2);
path.curveTo(
seg, height,
seg * 2, height,
seg * 2, height / 2);
path.curveTo(
seg * 2, 0,
seg * 3, 0,
seg * 3, height / 2);
g2d.draw(path);
g2d.dispose();
}
}
}
Take a look at Transforming Shapes, Text and Images for more details
Try JFreeChart
; the setMouseWheelEnabled()
method, used to control zooming in ChartPanel
, is illustrated in examples cited here.