X

Geertjan's Blog

  • April 1, 2011

Zoom Capability

Geertjan Wielenga
Product Manager
Look at the Zoom buttons in the extreme left of the toolbar below. In the first screenshot, the selected window does not require zoomability, hence the buttons are disabled...

...while in this window, we imagine an image of some kind that should be zoomable, hence the Zoom buttons are enabled:

Jesse created the above solution as part of VisiTrend's NDVis:

http://sourceforge.net/projects/ndvis/develop

Here's a step by step instruction to achieve the above.

  1. First, let's create an interface that we'll require components to publish in order to be zoomable:
    package org.zoom.solution;
    /\*\*
    \* Should be in the lookup of a component that can be zoomed.
    \*/
    public interface Zoomable {
    enum Mode {IN, OUT}
    void setMode(Mode mode);
    }

  2. Then, here's the constructor of the ImageTopComponent, where we put the Zoomable implementation into the TopComponent's Lookup:
    public ImageTopComponent() {
    initComponents();
    setName(NbBundle.getMessage(ImageTopComponent.class, "CTL_ImageTopComponent"));
    setToolTipText(NbBundle.getMessage(ImageTopComponent.class, "HINT_ImageTopComponent"));
    final ZoomHelper zoomHelper = new ZoomHelper(this);
    Zoomable z = new Zoomable() {
    @Override
    public void setMode(Mode mode) {
    zoomHelper.setZoom(mode);
    }
    };
    associateLookup(Lookups.singleton(z));
    }

    The helper class referred to above is something like this (for the complete source, see the NDVis reference above):

    class ZoomHelper {
    private final TopComponent panel;
    public ZoomHelper(TopComponent panel) {
    this.panel = panel;
    }
    private ToggleButtonMouseListener ToggleButtonMouseListener;
    public void setZoom(Zoomable.Mode mode) {
    panel.removeMouseListener(ToggleButtonMouseListener);
    switch (mode) {
    case IN: {
    ToggleButtonMouseListener = new ToggleButtonMouseListener(1.1);
    panel.addMouseListener(ToggleButtonMouseListener);
    ImageIcon ICON = ImageUtilities.loadImageIcon("org/zoom/solution/zoomin.gif", true);
    Cursor c = Toolkit.getDefaultToolkit().createCustomCursor(ICON.getImage(), new Point(0, 0), "ZOOMIN");
    panel.setCursor(c);
    StatusDisplayer.getDefault().setStatusText("Zoom in enabled...");
    }
    break;
    case OUT: {
    ToggleButtonMouseListener = new ToggleButtonMouseListener(0.9);
    panel.addMouseListener(ToggleButtonMouseListener);
    ImageIcon ICON = ImageUtilities.loadImageIcon("org/zoom/solution/zoomout.gif", true);
    Cursor c = Toolkit.getDefaultToolkit().createCustomCursor(ICON.getImage(), new Point(0, 0), "ZOOMOUT");
    panel.setCursor(c);
    StatusDisplayer.getDefault().setStatusText("Zoom out enabled...");
    }
    break;
    default:
    throw new AssertionError();
    }
    }
    private class ToggleButtonMouseListener implements MouseListener {
    private final double zoomFactor;
    public ToggleButtonMouseListener(double zoomFactor) {
    this.zoomFactor = zoomFactor;
    }
    @Override
    public void mousePressed(MouseEvent evt) {
    if (SwingUtilities.isLeftMouseButton(evt)) {
    //Somehow do your zooming now:
    //ZoomUtility.zoom(panel, evt.getPoint(), zoomFactor);
    }
    }
    @Override
    public void mouseReleased(MouseEvent e) {
    }
    @Override
    public void mouseClicked(MouseEvent e) {
    }
    @Override
    public void mouseEntered(MouseEvent e) {
    }
    @Override
    public void mouseExited(MouseEvent e) {
    }
    }
    }

  3. So, now we have an implementation of Zoomable in the Lookup of our TopComponent. That's what all TopComponents would do to integrate with the Zoom functionality.

    The Zoomable implementation is published. Now our buttons should subscribe to it. Here's a JToggleButton that will be displayed via Presenter.Toolbar in the next step. We create a ButtonGroup for the toggle effect, a LookupListener subscribed to Zoomable implementations, and an ItemListener for notifications when a different button is selected:

    import java.awt.event.ItemEvent;
    import java.awt.event.ItemListener;
    import java.util.Collection;
    import javax.swing.ButtonGroup;
    import javax.swing.JToggleButton;
    import org.openide.util.Lookup;
    import org.openide.util.LookupEvent;
    import org.openide.util.LookupListener;
    import org.openide.util.Utilities;
    import org.openide.util.WeakListeners;
    class ZoomableModeButton extends JToggleButton implements LookupListener, ItemListener {
    private static final ButtonGroup bg = new ButtonGroup();
    private static final Lookup.Result<Zoomable> zoomables = Utilities.actionsGlobalContext().lookupResult(Zoomable.class);
    private final Zoomable.Mode mode;
    public ZoomableModeButton(Zoomable.Mode mode, String label) {
    super(label);
    this.mode = mode;
    bg.add(this);
    setEnabled(false);
    addItemListener(this);
    zoomables.addLookupListener(WeakListeners.create(LookupListener.class, this, zoomables));
    }
    @Override
    public void resultChanged(LookupEvent ev) {
    change();
    }
    @Override
    public void itemStateChanged(ItemEvent e) {
    change();
    }
    private void change() {
    Collection<? extends Zoomable> z = zoomables.allInstances();
    if (z.size() == 1) {
    setEnabled(true);
    if (isSelected()) {
    z.iterator().next().setMode(mode);
    }
    } else {
    setEnabled(false);
    }
    }
    }

    We check that there's one Zoomable available, then set the enablement of the button, and use the mode of the current Zoomable for the selected button.


  4. Finally, here are the two Actions that will be presented as JToggleButtons:
    @ActionID(id = "com.visitrend.ndvis.actions.ZoomInAction", category = "NDVisActions")
    @ActionRegistration(displayName = "Zoom In")
    @ActionReference(path = "Toolbars/File", position = 10)
    public class ZoomInAction extends AbstractAction implements Presenter.Toolbar {
    @Override
    public void actionPerformed(ActionEvent e) {
    assert false;
    }
    @Override
    public Component getToolbarPresenter() {
    return new ZoomableModeButton(Zoomable.Mode.IN, "Zoom In");
    }
    }
    @ActionID(id = "com.visitrend.ndvis.actions.ZoomOutAction", category = "NDVisActions")
    @ActionRegistration(displayName = "Zoom Out")
    @ActionReference(path = "Toolbars/File", position = 20)
    public class ZoomOutAction extends AbstractAction implements Presenter.Toolbar {
    @Override
    public void actionPerformed(ActionEvent e) {
    assert false;
    }
    @Override
    public Component getToolbarPresenter() {
    return new ZoomableModeButton(Zoomable.Mode.OUT, "Zoom Out");
    }
    }

That's it. Thanks, Jesse.

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.