JavaOne Hands-On LabSave Time—Build Desktop Applications Quickly with the NetBeans PlatformLAB-5540Copyright 2009 Sun Microsystems |
The NetBeans Platform provides a reliable and flexible application architecture for desktop applications. Though it is known principally as the basis of NetBeans IDE, the end result does not need to look anything like it. It can save you years of development time. The NetBeans Platform gives you a time-tested architecture for free, together with a range of useful Swing components. An architecture that encourages sustainable development practices is provided out of the box, because the NetBeans Platform architecture is modular, making it easy to create applications that are robust and extensible.
This Lab will show you the most important APIs of NetBeans Platform. You will port a small Swing application to a new application based on the NetBeans Platform.
Copyright 2009 Sun Microsystems, Inc. All rights reserved. Sun, Sun Microsystems,
the Sun logo, Solaris, Java, the Java Coffee Cup logo, JavaOne, the JavaOne logo,
and all Solaris-based and Java-based marks and logos are trademarks or registered
trademarks of Sun Microsystems, Inc. in the United States and other countries.
This hands-on lab assumes you have some basic knowledge of, or programming experience in, the following technologies:
You will need to refer to the accompanying presentation 5540_netbeansrcp.pdf during the lab.
Please install the following set of software. If you have any questions on installation, please feel free to send questions to the lab forum mentioned below.
In addition to the contents of this lab's ZIP file, you should have the following installed on your computer:
A Java SE software installation, version 1.5.0_14 or higher. The version can be found by running: java -version
NetBeans IDE 6.7 - Java or All distribution. You can download it from netbeans.org
If java is not in your default execution path, you will need to set JAVA_HOME to point to the root of its installation on your system.
This exercise shows how to port an existing application to the NetBeans Platform.
The NetBeans Platform consists of many different modules that, together, form a complex application. Therefore, you should always choose only those pieces that are necessary for your application. By the end of this exercise, attendees will understand the different parts of the NetBeans Platform. They will integrate their own branding to the NetBeans Platform, making their application unique.
NetBeans is an open source project that is mostly known because of the NetBeans IDE that is built on top of it. However, NetBeans is more then just an IDE. It is also a rich-client platform that provides components for easy and fast development of new desktop applications. There is also a vibrant community around the NetBeans project. The community uses the NetBeans Platform in many projects that leverage the features and spread the NetBeans framework into areas where you wouldn't expect it to be at all. You can look at several screenshots of applications based on the NetBeans Platform.
List of APIs Used in this ExerciseIn this exercise, you will port a Swing application to an application based on the NetBeans Platform. You will see that such a transition can be relatively simple and fast. It should be quite an interesting experience as well, while in the next exercises you'll see even more of the NetBeans Platform's features.
Step 1: Opening the Anagram Swing Application
When NetBeans has started, select File->Open Project (Ctrl-Shift-O) and browse to the AnagramGame directory that is located in <lab_root>/exercises/exercise1.

After the project has opened, invoke Run->Run Project (F6). You will see the Anagram Game running. This the Swing Application which we would like to port to an application built on top of the NetBeans Platform in the following exercises.

Step 2: Creating a New NetBeans Platform Application
Invoke File->New Project (Crtl-Shift-N) and choose the NetBeans Modules category, then select NetBeans Platform Application.


When the project opens in IDE, select the JavaOne 2009 Anagram Application
node in the Projects tab. Invoke Properties from a pop-up menu on this node.
These Properties allows you to customize the new application.
If you select the Libraries node then you can specify what NetBeans modules will be available
in your NetBeans Platform application. These modules are divided in clusters e.g. platform10.

Command Line Parsing API
Common Annotations
JavaHelp Integration
JUnit 4
KeyMap Options
Output Window
Print
Step 3: Brand the application
In the Project Properties - JavaOne 2009 Anagram Application dialog, select the Build node. Now you can change the application's title and icon. Click Browse button and choose anagram48.png icon <lab_root>/exercises/exercise1 directory. This icon you will see in the application status bar when the application is running.
![]()
Now we would like to show a splash screen while the new Anagram application is launching. To change the default NetBeans Platform splash screen to your splash window select Splash Screen node and browse to <lab_root>/exercises/exercise1/anagram.png. Let's also refine color of text and progress bar on the splash screen.

Step 4: Creating a main module in a NetBeans Platform application
Now we have branded the wrapper of the application. We can run empty NetBeans platform
but it has no content yet. We need to add a effective module that provides a functionality to the application.
Switch again into Projects tab and select a node Modules under
JavaOne 2009 Anagram Application. Invoke a pop-up menu by right click on this node.
We will have to create new module and add it to our application.
Then we will copy the sources from Anagram Swing
application into the new module because we want to modify the behavior and look of the Swing
application rapidly.
Invoke the same pop-up menu and choose Add New...
item. Type a name of Platform Module, e.g. Anagram JavaOne 2009.

On the next panel you have to provide a Code Name Base. The Code Name Base must be a unique name which identifies the module among other modules or libraries in the NetBeans Platform for NetBeans Module System which loads NetBeans modules. Type Code Name Base org.javaone.anagram.

Step 5: Copy sources from Anagram Swing application into the NetBeans Platform application

Now Copy the lib and ui packages from original Anagram into org.javaone.anagram package in new Anagram Javaone 2009 project. The NetBeans IDE will automatically refactor packages to make them compilable.
Let's try to launch the application now. The application should run but still without any new content. We need to attach the new Anagram module to open new Anagram Game when the application is started.
Step 6: Attach existing Anagram frame into the NetBeans Platform application
We want to start a new game on each start of the application, the window with this game
should cover the whole size of the application, in the same
way as was done in the original Swing application.
To make that happen, we will use a template Window Component from
predefined templates suitable for building application on the NetBeans Platform.
The Window Component creates a new singleton Window integrated into
NetBeans Window System.
Invoke New > Window Component on org.javaone.anagram package

On the "Basic Settings" panel of New Window wizard dialog we can customize behaviour of this UI component.
On the last panel just tell some prefix of classes which will be created to handle behavior of this Window Component, e.g. AnagramGame.
We have the Window Component (i.e. AnagramGameTopComponent) and UI component of Anagram Game (i.e. Anagram.class frame). Now we need to place Anagram's UI into the new Window Component. If it is not opened already then open the AnagramGameTopComponent source in UI designer, simply by double clicking on AnagramGameTopComponent node in Projects tab.
In the UI designer place a new Panel by dragging the Panel from the Palette to the free space in AnagramGameTopComponent. Make this panel to cover whole free area and set BorderLayer as layout of this component.

Change the name of the JPanel component to anagramPanel in Properties window Code > Variable Name.

Now, switch into editing source of AnagramGameTopComponent (use the Source button on the top-left corner of editor area). There add new line to the constructor
public AnagramGameTopComponent() {
initComponents();
anagramPanel.add(new Anagrams().getContentPane(), BorderLayout.CENTER);//TODO:[add] place panel to the TC
setName(NbBundle.getMessage(AnagramGameTopComponent.class, "CTL_AnagramGameTopComponent"));
setToolTipText(NbBundle.getMessage(AnagramGameTopComponent.class, "HINT_AnagramGameTopComponent"));
...
Step 7: Customize face of the application
How to remove the toolbar? It's obvious that the toolbar isn't necessary
for the Anagram application. NetBeans Platform allows to declare many of UI
components in particular layer.xml files. Each module can have such
layer.xml in which it declates own UI component. But at least but not last,
the module can also hide UI components of other modules.
In our case, we can delete the declaration of
Toolbar in the layer file.
Expand the Important Files in of Anagram JavaOne 2009 module, choose
node this layer in context under XML Layer node. Expland this node and find Toolbars sub-node. Then
delete it. It removes the toolbars from Anagram application.
In the same way you can modify the toolbars, icons, actions in toolbar.
But in our case we don't need the toolbar at all.
How to clear up menus? Find the node Menu Bar under the this layer in context node. Delete all menu items with the exception of Help > About and File > Exit. You can also move the Help menu to highest level out from Help submenu
In this exercise, you learned how to create a NetBeans Platform Application from an existing Swing application. You also learned how to brand your application, together with some basics on how to extend the application with NetBeans IDE.
In the following exercises, we will learn about the basics of building applications using the NetBeans Platform, visualizing application data in a tree-like component, and how to add new actions to our application.
At a later point, we will look at the modularization of applications built on top of the NetBeans Platform and how to publish our module to public or private locations.
In this exercise we will learn about the basics of building applications using the NetBeans Platform, visualizing application data in a tree-like component, registering your own actions into NetBeans Options framework and else notable skeletons.
We've learned how to brand a NetBeans Platform application to our business needs. We know how to port a Swing Application to the NetBeans Platform. Next, we would like to extend it with a new features.
There are many ways of visualizing data in a NetBeans Platform application. One of the options
is to show your data in a tree-like structure with nodes showing values. With the NetBeans Platform,
you can use the Nodes API to create your tree-like structure and Explorer & Property Sheet API to show it in
the application.
To manipulate the data you'll need some actions. That's where the Actions API comes to play.
The Actions API is widely used in NetBeans Platform in many other places.
javax.swing.Action and register it.nodes, which are a variant of JavaBeans
that may have adjustable property sets; provide interfaces to other capabilities and actions;
be visually displayed in the Explorer with full hierarchy support; and other features.nodes - the most prominent in NetBeans being
the Project and Files tabs on the left side of the main window.
The Explorer API provides UI components to render nodes in trees,
lists, combo boxes, menus, tree tables. These components handle things like cut/copy/paste,
drag and drop, displaying popup menus for nodes, which contain the actions
the clicked node provides from getActions(). The Anagram application can start a new Anagram Game on each launch of application. But it's not enough. We would like to allow users to start more games then only once. To do so, we need a new action which opens a new game window and start an new instance of Anagram game.
NetBeans Platform support offers a template for creating new action in NetBeans module. Invoke File->New File (Crtl-N) or from a pop-up on the org.javaone.anagram sources package. Select Action in Module Development category.
On the next panel choose a Always enabled option. It will create action that will be available all the time. The other option "context-sensitive" action would create action that is enabled only under some circumstances. For example when you select a node in Explorer or when a particular file is opened in Editor.
On the last panel set prefix of action name, e.g. NewGame and then
set a display name of this action in the menu bar, e.g.&New Game.
NetBeans Platform allows to specify mnemonics of menu items, buttons, labels,
etc. by the & character before the character of the mnemonic.
It means that in our case you can invoke the New Game action by N in menu.
Open the class NewGame in editor. There is generated a method actionPerformed() which will be called on each invocation of File->&New Game in the menu bar.
The method actionPerformed() should open a next window in the Editor area like the initial
Window Component does. Only descendants of org.openide.windows.TopComponent are allowed to be
placed in NetBeans Window System. Thus we need to create new instance of TopComponent and then
open it in the Editor mode.
public void actionPerformed(ActionEvent e) {
Mode editorMode = WindowManager.getDefault ().findMode ("editor");
assert editorMode != null && WindowManager.getDefault ().isEditorMode (editorMode);
TopComponent tc = new GameTopComponent (new Anagrams ());
tc.open();
tc.requestActive();
}
private class GameTopComponent extends TopComponent {
private Anagrams game;
public GameTopComponent (Anagrams game) {
initComponents ();
this.game = game;
add (game.getContentPane (), BorderLayout.CENTER);
}
private void initComponents() {
this.setLayout (new BorderLayout ());
}
@Override
public String getDisplayName() {
return "Anagram Game";
}
@Override
public int getPersistenceType () {
return PERSISTENCE_NEVER;
}
@Override
protected String preferredID () {
return Integer.toString (System.identityHashCode (game));
}
}
Implementation of New Game Action allows users of Anagram application to start another Anagram games when one is finished.
public Anagrams() {
wordLibrary = WordLibrary.getDefault();
passed = 0;
timer = new Timer ();
startTime = System.currentTimeMillis ();
initComponents();
// saveScore.setVisible(false);
// saveScore.setEnabled(false);
lScoreTitle.setText("Time: ");
lScore.setForeground(Color.green);
timer.schedule (new TimerTask () {
Strings. It will make them persistent across
restarts.
NbPreferences.forModule(Anagrams.class) to acquire a storage
for storing scores. On this storage we will call both methods getInt, setInt
for storing and loading score values.
private void saveScoreActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveScoreActionPerformed
// setup the text of the dialog
NotifyDescriptor.InputLine nd = new NotifyDescriptor.InputLine ("What is your name?", "Save Score");
nd.setInputText(System.getProperty("user.name"));
DialogDisplayer.getDefault().notify(nd);
if (NotifyDescriptor.CANCEL_OPTION.equals(nd.getValue())) {
// no name
return;
}
saveScore.setEnabled(false);
String name = nd.getInputText();
Preferences pref = NbPreferences.forModule(Anagrams.class);
int best = pref.getInt(name, -1);
if (best > passed) {
NotifyDescriptor.Confirmation nd2 = new NotifyDescriptor.Confirmation(name +
" achieved a better score " + best +
". Overwrite?", "Overwrite best score");
DialogDisplayer.getDefault().notify(nd2);
if (NotifyDescriptor.YES_OPTION.equals(nd2.getValue())) {
pref.putInt(name, passed);
}
} else {
pref.putInt(name, passed);
}
lScore.setText(name + " has the best score " + pref.getInt(name, 0));
}
How to add new library into module's libraries? Either go to project properties select Libraries
and then press the Add Dependency... button or select Add Dependency...
from popup on Libraries node under your module's project. You can type name of an class in a library or
the library name to find it easier in the list of APIs.
Step 3: Visualize Best Scores
public void actionPerformed(ActionEvent e) {
Mode explorerMode = WindowManager.getDefault ().findMode("explorer");
}
public void actionPerformed(ActionEvent e) {
Mode explorerMode = WindowManager.getDefault ().findMode("explorer");
TopComponent tc = new ExplorerTopComponent ();
explorerMode.dockInto(tc);
}
public void actionPerformed(ActionEvent e) {
Mode explorerMode = WindowManager.getDefault ().findMode("explorer");
TopComponent tc = new ExplorerTopComponent ();
explorerMode.dockInto(tc);
tc.open();
tc.requestActive();
}
nodes, nodes are based on best scores achieved in the Anagram Game. The root node is a simple ″Best Scores″ root node.
This node has own children, each child is one of best scores.
public final class ShowScore implements ActionListener {
public void actionPerformed(ActionEvent e) {
Mode explorerMode = WindowManager.getDefault ().findMode("explorer");
TopComponent tc = new ExplorerTopComponent ();
explorerMode.dockInto(tc);
tc.open();
tc.requestActive();
}
private class ExplorerTopComponent extends TopComponent implements ExplorerManager.Provider {
private ExplorerManager em;
public ExplorerTopComponent () {
initComponents ();
em = new ExplorerManager();
em.setRootContext(new BestScoresNode());
}
private void initComponents() {
this.setLayout (new BorderLayout ());
TreeView tv = new BeanTreeView ();
tv.setRootVisible(true);
add (tv, BorderLayout.CENTER);
}
@Override
public String getDisplayName() {
return "Best Scores";
}
@Override
public int getPersistenceType () {
return PERSISTENCE_NEVER;
}
public ExplorerManager getExplorerManager() {
return em;
}
@Override
protected String preferredID () {
return Integer.toString (System.identityHashCode(em));
}
}
private class BestScoresNode extends AbstractNode {
private String displayName;
public BestScoresNode(String name, Children ch) {
super(ch);
this.displayName = name;
}
public BestScoresNode(String name, int score, Children ch) {
super(ch);
this.displayName = name + " has the best score " + score;
}
public BestScoresNode() {
super(new BestScoresChildren());
this.displayName = "Best Scores";
}
@Override
public String getDisplayName() {
return displayName;
}
}
private class BestScoresChildren extends Children.Keys<String> {
private Preferences pref;
public BestScoresChildren () {
try {
pref = NbPreferences.forModule(Anagrams.class);
String[] keys = pref.keys();
if (keys != null && keys.length > 0) {
setKeys(keys);
} else {
setKeys(Collections.singleton(""));
}
} catch (BackingStoreException ex) {
Exceptions.printStackTrace(ex);
}
}
@Override
protected Node[] createNodes(String key) {
if (key.length() == 0) {
return new Node[] { new BestScoresNode("No scores", Children.LEAF) };
} else {
return new Node[] { new BestScoresNode(key, pref.getInt(key, -1), Children.LEAF) };
}
}
}
}
In this exercise we enhanced the simple functionality of the Anagram Game with new actions that makes the game more usable and interesting. We created new action that allows to run more games. User can save their best scores too. And the best scores are visualized in nice tree-like structure. All these new features benefited from the NetBeans APIs.
In the previous exercise we prepared the JavaOne 2009 Anagram Application built on
top of NetBeans Platform. It allows to start new game and store, visualize the best results.
We will create new module Word Scrambler to improve the functionality of this application.
Word Scrambler will serve as admin module for the Anagram Application.
We prepared this module for you as its functionality is very complex to be covered in the HOL.
What does Word Scrambler provide? It can read a text from file, makes pairs of
scrambled and unscrambled words from the read text. And in addition it makes words with fixed length
by a given parameter that express the complexity.
We need to provide some UI for calling this code and then establish a way to exchange
words between Anagram Application and Word Scrambler.
Create new Window Component in org.javaone.scrambler package in Word Scrambler module like in Exercise 1, Step 6. Component should be docked into editor mode. It should open on application start. Use prefix AnalyzeText.
AnalyzeTextTopComponent that was created by the Window Component wizard.
Use Design button and sketch out UI. The UI should like on following picture:
| Swing Component | Text | Variable Name |
|---|---|---|
| JLable | File | lFile |
| JTextField | <none> | tfFile |
| JButton | &Browse | bBrowse |
| JButton | &Analyze | bAnalyze |
| JButton | &Upload to Anagram Game | bUpload |
| JLabel | Word Scrambler has 4 complexity | lComplexity |
| JList | <No words> | lWords |
private File textFile;
private Scrambler scrambler;
actionPerformed event for the Browse button.JFileChooser when you press Browse button.
private void bBrowseActionPerformed(java.awt.event.ActionEvent evt) {
JFileChooser chooser = new JFileChooser();
chooser.setFileSelectionMode (JFileChooser.FILES_ONLY);
chooser.setMultiSelectionEnabled (false);
chooser.setFileHidingEnabled (true);
chooser.setDialogTitle ("Select a text file");
if (chooser.showOpenDialog (this) == JFileChooser.APPROVE_OPTION) {
textFile = chooser.getSelectedFile ();
tfFile.setText(textFile.getPath());
bAnalyze.setEnabled(true);
}
}
private void bAnalyzeActionPerformed(java.awt.event.ActionEvent evt) {
File f = new File(tfFile.getText());
if (! f.exists()) {
NotifyDescriptor.Message nd = new NotifyDescriptor.Message
("The file " + f.getPath() + " doesn't exist!", NotifyDescriptor.ERROR_MESSAGE);
DialogDisplayer.getDefault().notify(nd);
bUpload.setEnabled(false);
bAnalyze.setEnabled(false);
return;
}
String text = File2String.file2string(f);
scrambler = new Scrambler(text, pref.getInt(ScramblerComplexityOptionsPanelController.SCRAMBLER_COMPLEXITY, 4));
lWords.setListData(scrambler.getWords());
bUpload.setEnabled(true);
bAnalyze.setEnabled(false);
}




private final Preferences pref = NbPreferences.forModule(ScramblerComplexityPanel.class);
void load() {
int complex = pref.getInt(ScramblerComplexityOptionsPanelController.SCRAMBLER_COMPLEXITY, 4);
jComboBox1.setSelectedItem(Integer.toString(complex));
}
void store() {
String complex = (String) jComboBox1.getSelectedItem();
pref.putInt(ScramblerComplexityOptionsPanelController.SCRAMBLER_COMPLEXITY, new Integer (complex));
AnalyzeTextTopComponent.getDefault().setComplexity(complex);
}
boolean valid() {
return true;
}
public static final String SCRAMBLER_COMPLEXITY = "scrambler_complexity";
void setComplexity(String complex) {
lComplexity.setText("Word Scrambler has " + complex + " complexity.");
boolean canAnalyze = new File(tfFile.getText()).exists();
bAnalyze.setEnabled(canAnalyze);
bUpload.setEnabled(false);
}
public AnalyzeTextTopComponent() {
initComponents();
setComplexity(pref.get(ScramblerComplexityOptionsPanelController.SCRAMBLER_COMPLEXITY, "4"));
bAnalyze.setEnabled(false);
bUpload.setEnabled(false);
setName(NbBundle.getMessage(AnalyzeTextTopComponent.class, "CTL_AnalyzeTextTopComponent"));
setToolTipText(NbBundle.getMessage(AnalyzeTextTopComponent.class, "HINT_AnalyzeTextTopComponent"));
}
private final Preferences pref = NbPreferences.forModule(ScramblerComplexityPanel.class);
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.javaone.scrambler;
import org.javaone.anagram.lib.WordLibrary;
/**
*
* @author jirka
*/
public class AdditionalWordLibrary extends WordLibrary {
private final String[] words;
private final String[] scramblers;
private final int size;
public AdditionalWordLibrary (final String [] words, final String [] scramblers) {
this.words = words;
this.scramblers = scramblers;
this.size = words.length;
}
@Override
public String getWord(int idx) {
assert idx < size;
return words[idx];
}
@Override
public String getScrambledWord(int idx) {
assert idx < size;
return scramblers[idx];
}
@Override
public int getSize() {
return size;
}
@Override
public boolean isCorrect(int idx, String userGuess) {
assert idx < size;
return words [idx].equalsIgnoreCase(userGuess);
}
}
private void bUploadActionPerformed(java.awt.event.ActionEvent evt) {
// upload to Anagram Game
WordLibrary wd = new AdditionalWordLibrary (scrambler.getWords(), scrambler.getScrambledWords());
WordLibrary.setDefault(wd);
bUpload.setEnabled(false);
bAnalyze.setEnabled(false);
}
<file name="Tools_hidden"/>In this exercise we created new module that allows to manage the words in the anagram game. You learned how to design new top component and how to use a module as library. You should know how to add new panel to Options and how to store and load their values.
Every NetBeans module has the capability to create a NetBeans package
which contains the project's binaries, together with meta-data describing
the author of the plugin and the the license. As well, the meta-data
contains a name and a description of the plugin and the category to which it
belongs.
You can find more information at DevFaqWhatIsNbm.
NetBeans Autoupdate functionality provides several services to the IDE: download and install available updates of installed modules, search and then install new features from subscribed Update Centers, browsing and manipulating the modules in IDE installation.
Update Center is a place with own URL containing a set of NetBeans NBM Package files (NBMs)
and a descriptor (a XML based file) describing these NBMs. Such Update Center
Descriptors can be add into IDE as new NetBeans Update Centers.
NetBeans uses Update Centers for delivering new features for NetBeans IDE and
also for delivering updates to allow users to keep the IDE up to date.
The Plugin Portal is a web application that allows the NetBeans community to contribute to the NetBeans plugin eco-system by adding plugins and also commenting on and rating the existing plugins.
Each NetBeans project has Make NBM action in own project's
popup. This action allows you build own NBM package from project.
You can deliver the NBM file to others: send via mail, publish on you weblog, etc.
For installing an NBM into a NetBeans Platform application, use the Plugin Manager,
invoke Tools | Plugins in the application.
Invoke Create NBM and build NBM file from the project. Look at Output tab
. There is info where the NBM was created.--userdir,
best would be to use a command line client. Invoke something like:
[jirka@rechtacek-nb kenai]$ cd $NETBEANS_INSTALLATION_DIR
[jirka@rechtacek-nb nb_all]$ cd netbeans/bin/
[jirka@rechtacek-nb nbbuild]$ ./netbeans --userdir /tmp/testnbm
Congratulations! You have successfully completed Lab-5540: Save Time—Build Desktop Applications Quickly with the NetBeans Platform Hands-on lab.
Where to send questions or feedbacks on this lab and public discussion forums:
You can send technical questions via email to the authors of this Hands-on lab (and experts on the subject) or you can post the questions to the web.
Please post questions that are relevant only to this hands-on lab.
You can send your other questions to the public users alias: