Managing layers
Explains how to use layers.
Explains how to organize objects into various layers in a manager.
Explains how to create, access, and modify layers.
Explains how to place objects in specific layers and make them visible and selectable.
Describes how to implement a listener for a layer.
Describes how to implement triple buffering for applications with a static background.
Describes how to cache any layers without the constraints of triple buffering and how to combine this feature with triple buffering.
Describes how to change the drawing order to get certain objects in front of others.
Layers in a manager
Layers are storage places for graphic objects in a manager. Each layer, with its graphic objects, is unique to a single
manager and can only be controlled by this manager.
When you store graphic objects in layers, you indicate their placement throughout multiple layers. When you display graphic objects stored in multiple layers, you present layer contents in a series of one or several views, with each view controlled by and specific to the same manager.
Various methods let you manipulate layers or the objects that they own. When redrawing takes place, a layer with the number N is placed in front of layers with numbers from N-1 to zero.
Inherent to the notion of layers is the concept of visual hierarchy among graphic objects stored in layers and displayed in views. In general, graphic objects of a more static nature, such as objects that might serve as shading or background for your Rogue Wave JViews programs, should be put in a lower layer of the manager. Those graphic objects of a dynamic nature, such as objects with which users interact, should typically be put in a higher layer so that they are not hidden.
Setting up layers
Layers are handled internally by the class
IlvManagerLayer. Layers can be accessed by their index or by their instance (a pointer to an
IlvManagerLayer ). By default, a manager is created with one layer. However, you can specify how many layers you want to create for a manager in the second parameter of the
IlvManager constructor.
Once the manager has been created, you can modify the number of layers using the following methods:
void addLayer(int index)
void removeLayer(int index, boolean redraw)
and retrieve the number of layers with:
int getLayersCount()
Layers and their graphic objects
When an object is added to a manager, you can specify the index of the layer where it should be inserted.
The following method adds the specified graphic object to the specified layer:
void addObject(IlvGraphic obj, int layer, boolean redraw)
To retrieve the index of the layer that contains a certain graphic object, use the following method:
int getLayer(IlvGraphic obj)
To change the layer, use the following method:
void setLayer(IlvGraphic obj, int newLayer, boolean redraw)
There are two essential properties that you can specify for the objects within a layer: visibility and scalability.
Visibility
With the following methods, you can indicate whether the objects within a certain layer should be visible to the user:
void setVisible(int layer, boolean value, boolean redraw)
boolean isVisible(int layer)
You can also decide whether a layer is visible or not within a particular view. Refer to the following methods:
void setVisible(IlvManagerView view, int layer, boolean set, boolean redraw)
boolean isVisible(IlvManagerView view, int layer)
Finally, you can have a visible layer in a view temporarily hide itself depending on certain conditions, generally depending on the zoom factor. This can be achieved through an
IlvLayerVisibilityFilter that is called each time the
IlvManager needs to redraw a layer. You should implement this interface and return whether or not the layer is visible with the
isVisible method. To be active, this filter must be registered on the corresponding
IlvManagerLayer using the
addVisibilityFilter method.
Selectability
You can specify whether objects within a layer can be selected or not using the following methods. Objects that cannot be selected cannot be modified:
boolean isSelectable(int layer)
void setSelectable(int layer, boolean v)
For more methods dealing with layers, see the class
IlvManager in the reference documentation.
Listener for layer changes in a manager
A class must implement the
ManagerLayerListener interface to be notified that layers have been inserted, removed, or moved in a manager. This interface contains four methods:
which is called when a layer is added to a manager.
which is called when a layer is moved in a manager.
which is called when a layer is removed from a manager.
which is called for other changes in a layer.
To be notified of layer modifications, a class implementing this interface must register itself using the following method of the class IlvManager :
void addManagerLayerListener(ManagerLayerListener l)
Convenience class for listener
The class IlvManagerLayerAdapter is a convenience class. It implements the ManagerLayerListener interface with empty methods. This is useful if you want to implement a manager layer listener that needs only to listen to some, but not all, of the events.
Triple buffering layers
Certain applications can use layers to display a static background on top of which “live” graphic objects will be drawn and manipulated by the user.
In this type of application, the graphic objects taking part in the background are static and are not modified by the user or the application. Thus, it is possible to draw just once for all of the layers constituting the graphic background. This increases the drawing speed of the application.
The process is called
triple buffering. This term is used because the layers will be drawn in an additional off screen image. Thereafter, when the view needs to be redrawn, this image is used instead of redrawing the graphic objects.
NOTE Unlike
double buffering, triple buffering is not engaged to remove flickering but to increase the drawing speed. Double and triple buffering can be used together.
For an instance of IlvManagerView, it is possible to indicate that a certain number of layers will be part of the triple buffering.
This is done using the following method of IlvManagerView :
void setTripleBufferedLayerCount(int n)
When this method is called, layers with indices between 0 and n-1 (the nth background layers) will be triple buffered.
Once the method is called and the view has been painted once, further modifications to graphic objects will not be rendered on the screen, since only the triple buffer image will be displayed.
Note that the triple buffer will be updated only when:
The transformer of the view changes (you are zooming or panning the view).
You add or remove layers.
You change the number of triple-buffered layers.
The triple-buffered layer visibility changes.
You add graphic objects to or remove them from the triple-buffered layers.
You call
applyToObject to make changes to the triple-buffered graphic objects on the triple-buffered layers.
NOTE Some interactors, such as the reshape interactor, call this function. Therefore, when you reshape a graphic object on a triple-buffered layer with the mouse, the triple buffer is invalidated.
You change the visibility of the graphic objects on the triple-buffered layers.
You change the triple-buffered layer on which the graphic objects are positioned.
If for any reason you need to update the triple buffer, you can use these methods:
void invalidateTripleBuffer(boolean repaint)
void invalidateTripleBuffer(IlvRect rect, boolean repaint)
To summarize, an application will use triple buffering when the contents of background layers are static, and when the application does not require the user to zoom and pan frequently.
Caching layers
Triple buffering is used to cache a set of layers for one view. The constraint is that these layers must be contiguous from layer 0 to layer n. If you want cache layers that are not contiguous or a layer whose index is not 0, since JViews 8.1,
IlvManagerView allows you to cache any layer for the view concerned.
To enable or disable a layer cache for the view, you can call the following method:
void setLayerCached(int layer, boolean enabled)
To know if a given layer is cached or not, call the following method:
boolean isLayerCached(int layer)
When a layer for a view is cached, it will first draw into a buffered image of the same size as the view. When the view needs to be repainted, the buffered image is displayed on the screen. The buffered image must be transparent so that layers behind it are not hidden.
You can enable the cache on any layer. Usually, caches are enabled on layers having many static graphic objects, that is, objects whose drawing does not change frequently, such as layers containing map (cartographic) information. However, this does not mean that the content of the cached layers cannot be changed. It just means that the speed benefit of the cache is higher when the content of the layer changes rarely. When you make a change to a graphic object such as inserting, removing, or applying an operation (see
applyToObject), the cache is automatically invalidated.
If you hesitate between enabling the layer cache and using triple buffering, the following facts can help you make the choice:
If the layers you want to cache or to buffer are contiguous and their indexes are from 0 to n, you should use triple buffering. In this case, triple buffering gives better performance than layer caches because the latter have to handle transparency.
If the layers you want to cache or to buffer are not contiguous, you have to use layer caches.
You can also use both features for the same view. You can triple buffer contiguous layers from 0 to n, and in addition you can cache any layer above layer n. In this way, you will get the best performance.
NOTE With some very rare configurations (Java ™ SE and OS), the transparent buffered image might not give good performance. In this case, you can perform a test to see if layer caches can improve performance.
Manipulating the drawing order
When several objects overlap partially, some objects appear in front of other objects. This effect is called drawing order or Z-order. Objects of layer N are placed in front of objects of layers N-1 to zero. Moving objects from one layer to another is one way of influencing the drawing order.
If there are several objects within the same layer, then these objects again have a drawing order. Each layer has a spatial data structure called quadtree which allows you to determine very quickly which objects are at which position. By default, the quadtree is enabled and determines the drawing order automatically in order to achieve optimal performance. In this case, the drawing order cannot be influenced.
If you want to specify the drawing order of objects within the same layer, you must first enable the Z-ordering option of the layer, by using the following method:
setZOrdering(boolean enable)
When Z-ordering is enabled for the layer, you can specify the drawing order of the objects within the layer:
setIndex(IlvGraphic object, int index)
Note that the index is always a continuous range from 0 to N. This means that if you set the index of an object, the index of other objects will shift by +1 or -1 to adjust the index range. The current index can be retrieved by
getIndex(IlvGraphic object)
When Z-ordering is enabled, objects with a higher index appear in front of objects of the same layer with a lower index.
NOTE The drawing order between different layers takes precedence over the drawing order within each layer: An object that is in a higher-numbered layer is drawn in front of another object in a lower-numbered layer even if the Z-order index of the first object is smaller than Z-order index of the second object. Therefore, the Z-order index determines only the drawing order of objects within the same layer.
Scenarios for experts
There are basically three scenarios:
The quadtree is enabled and Z-ordering is disabled. This results in the highest performance. In particular the hit-test (determining which objects are at a given position) is optimally fast. However, it is not possible to influence the drawing order within each layer.
The quadtree is enabled and Z-ordering is enabled. This is slightly slower, depending on how many objects overlap in average. The hit-test uses the quadtree and is still fast. It is possible to specify the drawing order completely.
The quadtree is disabled. No matter whether Z-ordering is enabled or disabled, it results in the same speed, which is a large magnitude slower than when the quadtree is enabled. When the quadtree is disabled, it is also possible to specify the drawing order.
A test with 10000 objects showed that enabling Z-ordering slows down the hit-test in average by a factor of 1.2-5, but disabling the quadtree slows down the hit-test by a factor of 20-70. These factors depend on the number of objects, and the factors are negligible if you have only a very few objects. Furthermore, if Z-ordering is enabled, the slowdown is mainly influenced by the overlapping depth (the number of objects that are overlapping cover exactly the same location): the higher the overlapping depth, the larger the slowdown of enabled Z-ordering.
Copyright © 2018, Rogue Wave Software, Inc. All Rights Reserved.