Im trying to make an applet that will allow me to open, zoom in and out of an image. Ive got a working applet going, but am having trouble with the zoom. Any ideas on where to h
You could continue to use a JLabel
and scale the image and reset the JLabel
s icon
property, or you could create a custom component dedicated to the job...
To start with, we need to display the image...
public class ZoomPane extends JPanel {
private BufferedImage master;
private Image scaled;
private float scale = 1f;
public ZoomPane() {
try {
master = ImageIO.read(new File("..."));
scaled = master;
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
public Dimension getPreferredSize() {
return scaled != null ? new Dimension(scaled.getWidth(this), scaled.getHeight(this)) : new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (scaled != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - scaled.getWidth(this)) / 2;
int y = (getHeight() - scaled.getHeight(this)) / 2;
g2d.drawImage(scaled, x, y, this);
g2d.dispose();
}
}
}
Now, you could use a MouseWheelListener
to scale the image...
addMouseWheelListener(new MouseWheelListener() {
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (e.getWheelRotation() < 0) {
scale -= 0.1;
} else {
scale += 0.1;
}
scaleBy(scale);
}
});
And because you'll probably want to allow the users a few different methods to scale the image, a nice convenience method....
public void scaleBy(float amount) {
scale += amount;
scale = Math.min(Math.max(scale, 0.1f), 200);
scaled = master.getScaledInstance(
Math.round(master.getWidth() * scale),
Math.round(master.getHeight() * scale),
Image.SCALE_SMOOTH);
revalidate();
repaint();
}
Now, it'd probably be nice to allow the user to use the + and - keys, for this, we'll want some kind of Action
...
public class ZoomAction extends AbstractAction {
private ZoomPane zoomPane;
private float zoomAmount;
public ZoomAction(ZoomPane zoomPane, String name, float zoomAmount) {
this.zoomAmount = zoomAmount;
this.zoomPane = zoomPane;
putValue(NAME, name);
}
@Override
public void actionPerformed(ActionEvent e) {
zoomPane.scaleBy(zoomAmount);
System.out.println("...");
}
}
This allows us to bind keyboard actions, buttons and menus and re-use the same basic code to do it...
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ADD, 0), "zoom-in");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, 0), "zoom-out");
am.put("zoom-in", new ZoomAction(this, "Zoom in", 0.1f));
am.put("zoom-out", new ZoomAction(this, "Zoom out", -0.1f));
This example works with the numpad + and - keys.
All this functionality should be added directly within the ZoomPane
You can re-use the ZoomAction
in your menus...
JMenuBar mb = new JMenuBar();
JMenu pictureMenu = new JMenu("Picture");
pictureMenu.add(new ZoomAction(zoomPane, "Zoom In", 0.1f));
pictureMenu.add(new ZoomAction(zoomPane, "Zoom Out", -0.1f));
mb.add(pictureMenu);
And even in you buttons...
JPanel buttons = new JPanel();
buttons.add(new JButton(new ZoomAction(zoomPane, "Zoom In", 0.1f)));
buttons.add(new JButton(new ZoomAction(zoomPane, "Zoom Out", -0.1f)));
frame.add(buttons, BorderLayout.SOUTH);
The scaling is pretty rough and ready, you should consider taking a look at:
... for more details
And finally, hacking it all together, as a runnable example...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
ZoomPane zoomPane = new ZoomPane();
JMenuBar mb = new JMenuBar();
JMenu pictureMenu = new JMenu("Picture");
pictureMenu.add(new ZoomAction(zoomPane, "Zoom In", 0.1f));
pictureMenu.add(new ZoomAction(zoomPane, "Zoom Out", -0.1f));
mb.add(pictureMenu);
JFrame frame = new JFrame("Testing");
frame.setJMenuBar(mb);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(zoomPane);
JPanel buttons = new JPanel();
buttons.add(new JButton(new ZoomAction(zoomPane, "Zoom In", 0.1f)));
buttons.add(new JButton(new ZoomAction(zoomPane, "Zoom Out", -0.1f)));
frame.add(buttons, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ZoomPane extends JPanel {
private BufferedImage master;
private Image scaled;
private float scale = 1f;
public ZoomPane() {
try {
master = ImageIO.read(new File("C:\\Users\\shane\\Dropbox\\MegaTokyo\\megatokyo_omnibus_1_3_cover_by_fredrin-d4oupef.jpg"));
scaled = master;
addMouseWheelListener(new MouseWheelListener() {
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (e.getWheelRotation() < 0) {
scale -= 0.1;
} else {
scale += 0.1;
}
scaleBy(scale);
}
});
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ADD, 0), "zoom-in");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, 0), "zoom-out");
am.put("zoom-in", new ZoomAction(this, "Zoom in", 0.1f));
am.put("zoom-out", new ZoomAction(this, "Zoom out", -0.1f));
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void scaleBy(float amount) {
scale += amount;
scale = Math.min(Math.max(scale, 0.1f), 200);
scaled = master.getScaledInstance(
Math.round(master.getWidth() * scale),
Math.round(master.getHeight() * scale),
Image.SCALE_SMOOTH);
revalidate();
repaint();
}
@Override
public Dimension getPreferredSize() {
return scaled != null ? new Dimension(scaled.getWidth(this), scaled.getHeight(this)) : new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (scaled != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - scaled.getWidth(this)) / 2;
int y = (getHeight() - scaled.getHeight(this)) / 2;
g2d.drawImage(scaled, x, y, this);
g2d.dispose();
}
}
}
public class ZoomAction extends AbstractAction {
private ZoomPane zoomPane;
private float zoomAmount;
public ZoomAction(ZoomPane zoomPane, String name, float zoomAmount) {
this.zoomAmount = zoomAmount;
this.zoomPane = zoomPane;
putValue(NAME, name);
}
@Override
public void actionPerformed(ActionEvent e) {
zoomPane.scaleBy(zoomAmount);
System.out.println("...");
}
}
}