BookNBPlatformCookbookCH0701

Contents

NetBeans Platform Cookbook Chapter 07 01

Create Application Infrastructure

This recipe shows how to create basic infrastructure to show any visual scene. Our application will show the Scene with example content and provides a satellite view and bird view.

The satellite view is small panel showing full but miniaturized scene. The grey rectangle represents the area visible in the scene view. The user can move the visible area by dragging this rectangle.

The bird view is rectangle in the scene view showing magnifying area under it like a magnifying lens. The user can drag it.

Preparation

We suppose for this recipe you can create modules and application suite module, TopComponent and know basic Module Development skills. But knowledge received in this chapter are useful for any Visual Library usage - the library can be used in the swing application (u can use the Lookup library, too).

How to

Create new application or suite project if you do not have any.

Add the Visual Library API module to your build Platform. Go to project Properties, select Libraries category, expand Platform cluster and enable Visual Library API.

Create module, set it dependent on Visual Library API and Utilities API.

Create new TopComponent opened by application start in the editor mode. Type class name prefix, e.g. Scene for SceneTopComponent name.

In design editor set BorderLayout and add a JScrollPane into it.

Switch to source editor and set TopComponent's persistence to NEVER.

Now prepare the component for satellite view and bird view usage.

Create two (or one common) interfaces SatelliteViewProvider and BirdViewProvider in this module:

public interface SateliteViewProvider {
    public JComponent getSateliteView();
}

public interface BirdViewProvider {
    public BirdViewController getBirdView();
}

Add these provider interfaces to SceneTopComponent class clause.

public final class SceneTopComponent extends TopComponent
        implements SatelliteViewProvider, BirdViewProvider 

Add the scene, component for satellite view and bird view controller as private members. Prepare three layers (layers and containers), too.

    private Scene scene;
    private LayerWidget mainLayer;
    private LayerWidget connectionLayer;
    private LayerWidget interactionLayer;

    private JComponent satelliteView = null;
 
    private BirdViewController birdViewController = null;

Create the Scene and scene view in the constructor and add it to the scrollPane. Create layers and add them into the scene.

        scene = new Scene();
        sceneView = scene.createView();
        scrollPane.setViewportView( sceneView );

        mainLayer = new LayerWidget(scene);
        scene.addChild( mainLayer );
        connectionLayer = new LayerWidget(scene);
        scene.addChild( connectionLayer );
        interactionLayer = new LayerWidget(scene);
        scene.addChild( interactionLayer );

Implement our two provider interfaces. Use lazy initialization.

    public JComponent getSatelliteView() {
        if (satelliteView == null) {
            satelliteView = scene.createSatelliteView();
        }
        return satelliteView;
    }

    public BirdViewController getBirdView() {
        if (birdViewController == null) {
            birdViewController = scene.createBirdView();
            birdViewController.setZoomFactor( 2.0d );
            birdViewController.hide();
        }
        return birdViewController;
    }

Note the createSatelliteView() and createBirdView() can be called only once.

We will check in the future if active TopComonent implements these interfaces. Checking it by instanceof operator is ugly. We have great tool for storing such an information – the Lookup. Expose the TopComponent itself and other instances (e.g. the scene) into the Lookup. Do not forget add the ActionMap.

       associateLookup( Lookups.fixed(
             // exposed TopComponent, 
             //   and SatelliteViewProvider, BirdViewProvider interfaces, too
             this
           , getActionMap()    // do not forget expose ActionMap
           , scene             // if some object needs it and if it is final
           ) );

Now we are prepared to create an Overview panel docked in the explorer mode. It will contain parameters for bird view and the satellite view.

Create new TopComponent with prefix e.g. Overview. Check Open on Application Start and Closing not allowed checkboxes.

Set BorderLayout, add a JPanel panel with BorderLayout.

Switch to the source editor and set pesistence type to PERSISTENCE_NEVER.

Add these members into it – actual satelliteView JComponent, BirdViewController and a BirdPanel we will creaet later.

    private JComponent satelliteView = null;
    private BirdViewController birdViewController = null;
    private BirdPanel birdPanel;

Initialize the BirdPanel and add it on top of the OverviewTopComponent:

      birdPanel = new BirdPanel();
      panel.add(birdPanel, BorderLayout.PAGE_START);

The OverviewTopComponent must listen which TopComponent is active. It is interested in that which implement SatelliteViewProvider and BirdViewProvider. So add the property listener to TopComponent's Registry:

   WindowManager.getDefault().getRegistry().addPropertyChangeListener(
                new WindowManagerListener()
                );

Now implement the WindowManagerListener.

   protected class WindowManagerListener 
                           implements PropertyChangeListener {

        public void propertyChange(PropertyChangeEvent evt) {

            if (Registry.PROP_ACTIVATED.equals(evt.getPropertyName())) {

                TopComponent actTC = WindowManager.getDefault().
                        getRegistry().getActivated();

                // consider that if (instanceof SateliteViewProvider)
                // and cast to provider is not used
                SatelliteViewProvider satprov = actTC.getLookup().
                        lookup(SatelliteViewProvider.class);
                if (satprov != null) {
                    JComponent co = satprov.getSatelliteView();

                    if (satelliteView != null && satelliteView != co) {
                        panel.remove(satelliteView);
                    }
                    if (co != null && co != satelliteView) {
                        satelliteView = co;
                        panel.add(satelliteView, BorderLayout.CENTER);
                        panel.invalidate();
                    }
                } // if satprov != null
                
                BirdViewProvider birprov = actTC.getLookup().
                        lookup(BirdViewProvider.class);
                if (birprov != null) {
                    BirdViewController co = birprov.getBirdView();

                    if (birdViewController != null && birdViewController != co) {
                        birdPanel.setBirdController( null );
                    }
                    if (co != null && co != birdViewController) {
                        birdViewController = co;
                        birdPanel.setBirdController( birdViewController );
                    }
                } // if birprov != null

            } // if instanceof SateliteViewProvider
        }

    } // WindowManagerListener

For Registry.PROP_ACTIVATED property change ask the Registry for active TopComponent. Note we do not check by

if (tc instanceof SateliteViewProvider) 

condition but use its Lookup to retrieve used SatelliteViewProvider instance. Remove any previous view if any. If the view component was changed store the new one and add it to panel.

Retrieving the BirdViewController is similar. Store it and set it to the BirdPanel.

There is left to create the BirdPanel. We show it in the Overview panel. Create JPanel class named BirdPanel. Add one label and one text field (we used JFormattedTextField) for zoomFactor property, a label and two text fields for bird view size and one checkbox for show/hide behavior.

Switch to source editor and add birdController property of BirdViewController type.

When any parameter in the form is changed by the user set the corresponding value of the birdController.

    private void showChkActionPerformed(java.awt.event.ActionEvent evt) {                                        
        if (getBirdController() != null) {
            if (showChk.isSelected()) {
                getBirdController().show();
            }
            else {
                getBirdController().hide();
            }
        }
    }                                       

    private void zoomFactorFieldPropertyChange(PropertyChangeEvent evt)
   {                                               
        if (evt.getPropertyName().equals("value")  
                     &&  getBirdController() != null) {
            double d = 2.0d;
            try {
                d = Double.parseDouble(zoomFactorField.getText());
            }
            catch (NumberFormatException numberFormatException) {
                return;
            }
            getBirdController().setZoomFactor( d ); 
        }
    }                                              

    private void sizeWidthPropertyChange(PropertyChangeEvent evt) {                                         
        if (evt.getPropertyName().equals("value")  
                                   &&  getBirdController() != null) {
            changeBirdSize();
        }
    }                                        

    private void sizeHeightPropertyChange(PropertyChangeEvent evt) {                                          
        if (evt.getPropertyName().equals("value")  
                      &&  getBirdController() != null) {
            changeBirdSize();
        }
    }
   private void changeBirdSize() {
         if (getBirdController()!= null) {
            int w = 200, h = 200;
            try {
                w = Integer.parseInt(sizeWidth.getText());
                h = Integer.parseInt(sizeHeight.getText());
            }
            catch (NumberFormatException numberFormatException) {
                return;
            } 
            getBirdController().setWindowSize( new Dimension(w, h) );
        }
    }

Now you can run the application. It could be useful to add some widgets to the scene to show functionality. How to create scene content or how to add actions is described in other recipes.

Let's Explain!

When the user activates any TopComponent which provides a satellite view and a bird view the OverviewTopComponent uses them. The user can move the grey rectangle in the satellite view to move visible area of the scene. He can make visible the bird view (magnifying lens) in the scene by checking Visible box and change its size or zoom.

Notes/Tips

Because the BirdViewController does not provide getter methods for its properties it would be useful to store its state and show previous values in the form again.

Create private inner class BirdViewState in the BirdPanel.

    private static class BirdViewState {
        double zoomFactor = 2.0d;
        Dimension size = DIMENSION_STD;
        boolean visible = false;
        public BirdViewState() {
        }
        private static final Dimension DIMENSION_STD = 
                                 new Dimension(200, 200);
    } // BirdViewState

Declare actual state and static Map for pairs (controller, state).

    private BirdViewState birdViewState = new BirdViewState(); 
    private static Map<BirdViewController, BirdViewState> birdStates =
                       new HashMap<BirdViewController, BirdViewState>();

In the setBirdController() method set the actual state to null. It will be restored/created by the next request by getBirdViewState() call.

    public void setBirdController(BirdViewController birdController) {
        ...
        this.birdViewState = null;  // to find or create by next request
        birdStateToForm();
    }

The birdStateToForm() method asks for state and sets its value to form.

    public void birdStateToForm() {
        BirdViewState state = getBirdViewState();
        zoomFactorField.setText( "" + state.zoomFactor );
        sizeWidth.setText( "" + state.size.width );
        sizeHeight.setText( "" + state.size.height );
        showChk.setSelected( state.visible );
    }

In the getBirdViewState() method check if the state was stored. If yes return it. If no create new one and register it.

    public BirdViewState getBirdViewState() {
        if (this.birdController != null) {
           this.birdViewState = birdStates.get( this.birdController );
        } 
        if (this.birdViewState == null) {
           this.birdViewState = new BirdViewState();
           if (this.birdController != null) {
                birdStates.put(this.birdController, this.birdViewState);
            }
        }
        return birdViewState;
    }

Store changed value after you set it to the controller.

           getBirdController().setZoomFactor( d );
           this.birdViewState.zoomFactor = d;

Similar for size and visible properties.

image:Nbpcook_07_01_simple_app.png

Figure 7.1 Simple visual application


Notes/Tips

The scene has more initializations and behavoiurs and your program will grow. Consider to extract it to your own subclass of the Scene or ObjectScene. You must create layers, add actions, selection provider etc. For ObjectScene usage see next section.

The example project simple_scene uses a technique described in this text. For copying into your module use the next projects where a special scene class is used and contains basic actions.

Notes/Tips

The Scene class is sufficient to paint or animate some simple scheme. If you visualize (and manage) any domain objects the ObjectScene class is more powerful. You can store and bind the domain object with associated widget by method

     objectScene.addObject(domainObject, itsWidget);

Notes/Tips

Official Visual Library 2.0 - Examples are stored on this page http://platform.netbeans.org/graph/examples.html


Text and sources were created under NB 6.8 and will be upgraded.

Navigation

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo