Zoom Capability

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.

Comments:

Post a Comment:
  • HTML Syntax: NOT allowed
About

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.

Search

Archives
« July 2014
SunMonTueWedThuFriSat
  
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  
       
Today