Search |
||
Creative use of the NetBeans Visual Library: the Light TablePosted by fabriziogiudici on August 21, 2007 at 11:24 AM PDT
The Visual Library is one of the coolest things that the NetBeans guys delivered with NetBeans 6. It is a rich API which allows you to create a sort of "blackboard" where objects can be added, removed, edited, moved, resized, and connected in a visual graph. The cream on the cake is that you can use the Visual Library even in regular Swing applications by just adding the related JAR to the classpath, since it has no dependencies on the NetBeans core.
The Visual Library is deeply used inside NetBeans: it's at the core of ![]() Now I'm going to tell you how I was able to implement the LightTable in a matter of hours (tests excluded) yesterday night with the Visual Library. WARNING: this blog assumes you're confident with the basic concepts of Swing and the DataSystem and Nodes API of NetBeans. You're going to see all the relevant code in the sketches below; in any case, the sources can be checked out with Subversion from https://bluemarine-incubator.dev.java.net/svn/bluemarine-incubator/trunk... The binary code isn't available in blueMarine yet (hey, I just wrote it last night! Give me the time to test it... ;-) - it will be available soon by means of the Update Centers and will be part of the next round of blueMarine demos I'll give starting from the next month. Some blueMarine APIs Of course I've been facilitated by the consolidation of the blueMarine APIs, that are a set of NetBeans modules for manipulating photos (and - with the latest refactoring - any kind of media type). Since I'd like to focus on the Visual Library and not on blueMarine, I'm just telling you what the few blueMarine classes you'll see in the code listings are about:
The SceneThe Scene is the container for the "blackboard", that is the container of all the graphics objects (that are called "Widgets"). While Roumen's screencast introduced the regular Scene class, I'm going to use an ObjectScene, which provides some additional features:
ObjectScene with the capability of add and remove DataObjects from it:/** This object manages a set of thumbnailed nodes. */ Just a few comments:
ObjectScene, you just get the Swing components out of it:
The view is the blackboard renderer itself, and you just need to place it in a Swing JWindow or such (in most cases you'd put it into a JScrollPane first); the satelliteView is an optional component that provides a "bird's eye" view of the blackboard.As those components are just Swing components, you can integrate them with things such as drag and drop. For instance, the following code enables dropping DataObjects directly on the LightTable:private final DropTarget dropTarget = new DropTarget() Creating a Widget The Visual Library comes with a lot of pre-made Widgets, such as LabelWidget (which contains a text), ImageWidget (which contains an image), up to ComponentWidget, which contains a JComponent. This is really flexible for most cases; nevertheless you can subclass Widget if you want to do something special.Which is precisely what I need. In spite of the fact that a Thumbnail is an image, ImageWidget is not ok for me, since rendering Thumbnails is somewhat complex because of their asynchronous behaviour. So I'm going with the creation of a custom Widget with specialized rendering capabilities:Keep in mind that you aren't forced to use Nodes with the Visual Library: but the next code samples will demonstrate why it's a good thing to have them behind the scenes.Rendering happens in the paintWidget() method, where you can retrieve a Graphics2D object and paint all the stuff. Since a Scene can be zoomed in and out, it's important that you deal properly with the current scale. The second thing to implement is the capability of automatically update the Widget when the Thumbnail state changes. Since this capability is pretty important throughout blueMarine, I've already told you that Nodes coming out from a ThumbnailTracker have automatic update capabilities. So what I need now is just a NodeListener:private final NodeListener iconChangeListener = new NodeAdapter() repaint(), as the similar method in JComponent, just causes the current Widget to be repainted (another method, revalidate(), should be called if you have changed the size of the Widget, which is something I'm not doing here).Now I would like to have a popup menu working on my ThumbnailWidget. By default, they don't have one, but you can specify a PopupMenuProvider for this purpose:As you can see, the code retrieves the context menu of the Node. This is pretty neat, since I'm just transparently getting the actions that have been configured in the NetBeans platform; in other words, I'm being consistent with the fact that whenever I have something that represents a photo, I always get the same functionalities.Furthermore, I can take advantage of the Nodes API. For instance, I'd like to retouch a bit the popup menu. In facts, it contains an "Add to light table" action that I've defined elsewhere - trust me, I'm not giving the code for this since it's not part of the Visual Library stuff. But there's no meaning in executing that action on a Widget that is already in the Light Table. On the contrary, a "Remove from light table" action would make sense. I can easily exchange the "add to..." with the "remove from..." actions by using a FilterNode:private class ActionFilterNode extends FilterNode Now I'd like to have my ThumbnailWidget brought to front when a simple mouse click is performed on it. On this purpose, I can create a custom WidgetAction as follows:private static final WidgetAction.Adapter bringToFrontAction = new WidgetAction.Adapter()I think that the above code is self-explaining. Now I'd like that my ThumbnailWidget can be moved by just clicking and dragging the mouse. This is really easy: I just need to add this in the constructor:getActions().addAction(ActionFactory.createMoveAction());And what about resizing? The Visual Library provides out-of-the box support for resizing a Widget. You just need to add the related action in the Widget constructor:getActions().addAction( ActionFactory.createResizeAction());At this point, by pointing the mouse on the Widget border and dragging, it gets resized. Easy! But it's not good for me: my ThumbnailWidget represents a photo and I don't want arbitrary resizing that changes the aspect ratio of the image. Fortunately I can put a constraint with the following code:A ResizeStrategy lets me override the actual size the will be applied to the Widget:private final ResizeStrategy resizeStrategy = new ResizeStrategy() The code looks a bit tricky, but the point is that I just need to return the new size that I want to apply. I'm basically enforcing the aspect ratio, just caring if the user is moving the mouse mostly horizontally (in this case I'd leave the new width unchanged and compute the height accordingly) or vertically (in this case I'd do the opposite). Also I'm taking the Insets in the computation, since they are usually non zero due to the capability of setting a Border to the Widget.Yes, the Border. I actually want to change the border of my ThumbnailWidget dynamically:
notifyStateChanged() method, that is called whenever the Widget changes state:@OverrideJust keep in mind that Borders for Widgets aren't the same classes as for the plain Swing component, and they have a specific BorderFactory. The details for creating a border are quite boring and I'll leave you to inspect the source code for them.That's enough for this post. I need to run tests on the new component, but I've seen only minor glitches so far and I'm pretty pleased with the small amount of code that the Visual Library required to implement the features I had in mind. The most important point that should be addressed is the persistence of the Light View, that is a way to "remember" the items and their positions. It should be not hard since the Scene exposes methods for enumerating the contained Widgets, but I'll deal with this later - also because this first experience with the Visual Library made me thinking of some other cool thing that I could do with it... :-)And remember that I just scratched the surface of the Visual Library: even if you need more complex renderings, including graphs with nodes, arcs, floating connections, etc... , the Visual Library has probably what you need. Technorati Tags: NetBeans, Visual Library, blueMarine »
Related Topics >>
Netbeans Comments
Comments are listed in date ascending order (oldest first)
|
||
|
|