Implementing Pan and Zoom Together
Now let's use both the scroll (pan) and the zoom features to implement a combined pan-zoom operator and use it in the image viewer described in Chapter 6. The Scroll and Zoom operator classes provide no GUIs. But we need a GUI interface that indicates to Scroll and Zoom objects when to zoom and when to pan. So let's provide a pop-up menu that is launched by right-clicking on the image. This pop-up menu will have the following three menu items:
Zoom in
Zoom out
Pan
You can choose any of these options at any time.
The PanZoom class (see Listing 7.12) combines the pan and zoom features.
LISTING 7.12 The PanZoom class
package com.vistech.imageviewer; import java.io.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class PanZoom extends MouseAdapter{ protected ImageManipulator imageCanvas; protected ScrollGUI pan; protected Scroll scroll; protected ZoomGUI zoomGUI; protected Zoom zoom; protected boolean panOn,zoomOn, zoomOut, panZoomOn = true; public PanZoom(ImageManipulator manip) { imageCanvas = manip; scroll = new Scroll(imageCanvas); pan = new ScrollGUI(scroll); zoom = new Zoom(imageCanvas); zoomGUI = new ZoomGUI(zoom); init(); } protected void init() { if(imageCanvas == null) return; imageCanvas.addMouseListener(pan); imageCanvas.addMouseListener(zoomGUI); imageCanvas.addMouseListener(this); imageCanvas.addMouseMotionListener(pan); panOn = true; zoomOn = false; zoomOut = false; } protected void setStates() { pan.setScrollOn(panOn); zoomGUI.setZoomOn(zoomOn); zoomGUI.setZoomOut(zoomOut); } public void setPanZoomOn(boolean onOrOff){ if(panZoomOn == onOrOff) return; panZoomOn = onOrOff; if(panZoomOn){ imageCanvas.addMouseListener(pan); imageCanvas.addMouseListener(zoomGUI); imageCanvas.addMouseListener(this); imageCanvas.addMouseMotionListener(pan); }else { imageCanvas.removeMouseListener(pan); imageCanvas.removeMouseListener(zoomGUI); imageCanvas.removeMouseListener(this); imageCanvas.removeMouseMotionListener(pan); } } public boolean getZoomOut(){ return zoomOut; } public boolean getZoomOn(){ return zoomOn; } public double getZoomFactor(){ return zoomGUI.getZoomFactor(); } public boolean getPanOn(){ return panOn; } public void reset(){ zoomGUI.reset(); pan.reset(); } protected void popupMenu(JComponent comp,int x, int y){ JPopupMenu jp = new JPopupMenu(""); jp.setLightWeightPopupEnabled(true); comp.add(jp); JMenuItem zout = new JMenuItem("Zoom out"); zout.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e){ zoomOut = true; zoomOn = true; panOn = false; setStates(); } } ); JMenuItem zin = new JMenuItem("Zoom in"); zin.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e){ zoomOut = false; zoomOn = true; panOn = false; setStates(); } } ); JMenuItem pn = new JMenuItem("Pan"); pn.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e){ zoomOn = false; panOn = true; setStates(); } } ); jp.add(zin); jp.add(zout); jp.add(pn); jp.show(comp,x,y); } public void mousePressed(MouseEvent e) { if(!SwingUtilities.isLeftMouseButton(e)){ popupMenu((JComponent)e.getSource(), e.getX(), e.getY()); } } }
The PanZoom class extends the java.awt.events.MouseAdapter class, which implements the MouseListener interface. This interface is required to launch the pop-up menu. The constructor for the PanZoom class takes the ImageManipulator interface as input. It creates Pan and Zoom objects by passing the ImageManipulator parameter to their constructor and calls the init() method. The init() method registers the Pan object to receive mouse and mouseMotion events.
When pan mode is selected, the position where the mouse is pressed is the anchor for pan. While the mouse is being dragged, the difference in distance from the current position to the anchor is computed and passed to the ImageManipulator object to paint the image at the new position. The init() method registers the Zoom object to receive mouse events and then sets the default values for the three state variables: panOn, zoomOn, and zoomOut.
The popupMenu() method takes x and y coordinates of the position at which the mouse is clicked as the input parameters and uses them to show the pop-up menu at that location. This method creates three menu itemsPan, Zoom out, and Zoom ineach of which has an anonymous inner class to handle action events. These actionPerformed() methods set the member variables panOn, zoomOn, and zoomOut and call the appropriate setStates() methods in the Pan and Zoom objects, depending on the menu item selected.
The screen shot in Figure 7.10 shows an image viewer that implements the combined pan-zoom feature. In this image viewer, you can right-click on the image to select the operation you want to perform by choosing the appropriate item from the pop-up menu. This image viewer is an extension of the one in Chapter 6. As the figure shows, the status bar displays the image manipulation status messages. Regarding pan-zoom, the status bar tells you which feature is currently active and the current zoom factor.
FIGURE 7.10 An image viewer with the pan-zoom feature
Now let's implement a special feature called Lens using the zoom API.