NetBeans Platform 6.9: Working with Window System

(For more resources on NetBeans, see here.)

Window System

Large desktop applications need to provide many different views for visualizing data. These views have to be managed and shown and the NetBeans Platform handles these requirements for you out of the box via its docking framework.

While it once might have been sufficient for a docking framework to provide static fixed window layouts, today the user expects far more flexibility. Windows should be able to be opened, movable, and, generally, customizable at runtime. The user tends to assume that the positions of views are modifiable and that they persist across restarts of the application. Not only that, but applications are assumed to be so fiexible that views should be detachable from the application's main window, enabling them to be displayed on multiple monitors at the same time. While once the simple fact of the availability of menus and toolbars was sufficient, today a far more dynamic handling is needed so that window content can be adapted dynamically. Connected to these expectations of flexibility, plugins are increasingly becoming a standard technology, with the user assuming their windows to be pluggable, too.

In short, the requirements for window management have become quite complex and can only be met by means of an external docking framework, otherwise all these various concerns would need to be coded (and debugged, tested, and maintained) by hand. The NetBeans Platform provides all of these features via its docking framework, known as the NetBeans Window System. It also provides an API to let you programmatically access the window system. Together, the window system and its API fulfill all the requirements described above, letting you concentrate on your domain knowledge and business logic rather than on the work of creating a custom window management facility for each of your applications.

This part of the article teaches you the following:

  • How to define views
  • How to position views in the main window

Rest is covered in the second part of this article series.

Creating a window

The NetBeans Window System simplifies window management by letting you use a default component for displaying windows. The default component, that is, the superclass of all windows, is the TopComponent class, which is derived from the standard JComponent class. It defines many methods for controlling a window and handles notification of main window system events.

The WindowManager is the central class controlling all the windows in the application. Though you can implement this class yourself, this is seldom done as normally the default WindowManager is sufficient. Similarly, you typically use the standard TopComponent class, rather than creating your own top-level Swing components. In contrast to the TopComponent class, the default WindowManager cannot manage your own top-level Swing components, so these cannot take advantage of the Window System API.

Now let's create a TopComponent and let it be an editor for working with tasks. This is done easily by using the New Window wizard.

  1. In the Projects window, right-click the TaskEditor module project node and choose New | Window.
  2. On the first page of the wizard select Editor for Window Position and Open on Application Start. Click Next.

  3. In the next page of the wizard, type TaskEditor in Class Name Prefix. This prefix is used for all the generated files. It is possible to specify an icon that will be displayed in the tab of the new window, but let's skip that for the moment. Click Finish and all the files are generated into your module source structure.

  4. Next, open the newly created TaskEditorTopComponent and drag the TaskEditorPanel from the Palette, which is where you put it at the end of the last chapter, onto the form.
  5. The size of the component automatically adjusts to the required size of he panel. Position the panel with the preferred spacing to the left and top and activate the automatic resizing of the panel in horizontal and vertical direction. The form should now look similar to the following screenshot:

  6. Start the application. You now see a tab containing the new TaskEditor Window, which holds your form.

Examining the generated files

You have used a wizard to create a new TopComponent. However, the wizard did more than that. Let's take a look at all the files that have been created and at all the files that have been modified, as well as how these files work together.

The only Java class that was generated is the TopComponent that will contain the TaskEditor, shown as follows:

@ConvertAsProperties(dtd = "-//com.netbeansrcp.taskeditor//TaskEditor//
EN", autostore = false)
public final class TaskEditorTopComponent extends TopComponent {
private static TaskEditorTopComponent instance;
/** path to the icon used by the component and its open action */
// static final String ICON_PATH = "SET/PATH/TO/ICON/HERE";
private static final String PREFERRED_ID = "TaskEditorTopComponent";
public TaskEditorTopComponent() {
// setIcon(ImageUtilities.loadImage(ICON_PATH, true));

/**This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
javax.swing.GroupLayout layout = new javax.swing.
Alignment.LEADING).addGap(0, 555, Short.MAX_VALUE));
.addGap(0, 442, Short.MAX_VALUE)
}// </editor-fold>

// Variables declaration - do not modify
// End of variables declaration
* Gets default instance. Do not use directly: reserved for
*.settings files only,
* i.e. deserialization routines; otherwise you could get a
non-deserialized instance.
* To obtain the singleton instance, use {@link #findInstance}.
public static synchronized TaskEditorTopComponent getDefault() {
if (instance == null) {
instance = new TaskEditorTopComponent();
return instance;
* Obtain the TaskEditorTopComponent instance. Never call {
@link #getDefault} directly!
public static synchronized TaskEditorTopComponent findInstance() {
TopComponent win = WindowManager.getDefault().findTopComponent
if (win == null) {
warning("Cannot find " + PREFERRED_ID + " component.
It will not be located properly in the window system.");
return getDefault();
if (win instanceof TaskEditorTopComponent) {
return (TaskEditorTopComponent) win;
warning("There seem to be multiple components with the '" +
+ "' ID. That is a potential source of errors and
unexpected behavior.");
return getDefault();

public int getPersistenceType() {
return TopComponent.PERSISTENCE_ALWAYS;

public void componentOpened() {
// TODO add custom code on component opening
public void componentClosed() {
// TODO add custom code on component closing

void writeProperties(java.util.Properties p) {
// better to version settings since initial version
as advocated at
p.setProperty("version", "1.0");
// TODO store your settings

Object readProperties(java.util.Properties p) {
if (instance == null) {
instance = this;
return instance;

private void readPropertiesImpl(java.util.Properties p) {
String version = p.getProperty("version");
// TODO read your settings according to their version
protected String preferredID() {

As expected, the class TaskEditorTopComponent extends the TopComponent class.

Let's look at it more closely:

  • For efficient resource usage, the generated TopComponent is implemented as a singleton. A private constructor prohibits its incorrect usage from outside by disallowing direct instantiation of the class. The static attribute instance holds the only instance in existence. The static method getDefault creates and returns this instance if necessary on demand. Typically, getDefault should never be called directly. Instead of this, you should use findInstance, which delegates to getDefault if necessary. findInstance tries to retrieve the instance using the Window Manager and the ID of the TopComponent before falling back to the singleton instance. This ensures the correct usage of persistent information.
  • The constructor creates the component tree for the TaskEditorTopComponent by calling the method init Components(). This method contains only code generated via the NetBeans "Matisse" Form Builder and is read-only in the NetBeans Java editor. You can change the code in this method using the Form Builder's Property Sheet, as will be shown later.
  • The static property PreferredID holds the TopComponent ID used for identification of the TopComponent. As indicated by its name, the ID can be changed by the Window System, if name clashes occur. The ID is used throughout all the configuration files.
  • The methods componentOpened() and componentClosed() are part of the lifecycle of the TopComponent.
  • You learn about the method getPersistenceType() later, in the section about the persistence of TopComponents.

What does the Java code do and not do?
The Java code only defines the visual aspects of the TaskEditorTopComponent and manages the singleton instance of this component. In no way does the code describe how and where the instance is shown. That's the task of the two XML files, described below.

Two small XML files are created by the wizard. The first is the TopComponent's settings file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE settings PUBLIC "-//NetBeans//DTD Session settings 1.0//EN"
<settings version="1.0">
<module name="com.netbeansrcp.taskeditor" spec="1.0"/>
<instanceof class=""/>
<instanceof class="com.netbeansrcp.taskeditor.
<instance class="com.netbeansrcp.taskeditor.TaskEditorTopComponent"

The settings file describes the persistent instance of the TopComponent. As you can see, the preceding configuration describes that the TopComponent belongs to the module TaskEditor in the specification version "1.0" and that it is an instance of the types TopComponent and TaskEditorTopComponent. Also described is that the instance that is created is done so using the method call TaskEditorTopComponent.getDefault().

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tc-ref PUBLIC "-//NetBeans//DTD Top Component in Mode Properties
2.0//EN" "">
<tc-ref version="2.0" >
<module name="com.netbeansrcp.taskeditor" spec="1.0"/>
<tc-id id="TaskEditorTopComponent"/>
<state opened="true"/>

The WSTCREF (window system creation file) describes the position of the TopComponent within the main window. This becomes clearer with the following file. The other important information in the WSTCREF file is the opened state at application start.

Typically, you do not have to change these two configuration files by hand. This is not true for the following file, the layer.xml, which you often need to change manually, to register new folders and files in the filesystem.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.2//EN" "http://">
<folder name="Actions">
<folder name="Window">
<file name="com-netbeansrcp-taskeditor.TaskEditorAction.instance">
<attr name="component"
<attr name="displayName"
<attr name="instanceCreate" methodvalue="
<folder name="Menu">
<folder name="Window">
<file name="TaskEditorAction.shadow">
<attr name="originalFile" stringvalue="Actions/Window/com
<folder name="Windows2">
<folder name="Components">
<file name="TaskEditorTopComponent.settings"
<folder name="Modes">
<folder name="editor">
<file name="TaskEditorTopComponent.wstcref"

The layer.xml is integrated into the central registry (also known as the SystemFileSystem) using the via a registration entry in the module's manifest file. The SystemFileSystem is a virtual filesystem for user settings. Each module can supply a layer file for merging configuration data from the module into the SystemFileSystem.

The Window System API and the Actions API reserve a number of folders in the central registry for holding its configuration data. These folders enable specific subfolders and files relating to window system registration to be added to the filesystem.

  • Let's have a look at the folder Windows2. Windows2 contains a folder named Components, which contains a virtual file with the name of the TopComponent and the extension .settings. This .settings file redirects to the real settings file. It is used to make the configuration known to the Window System.
  • In addition, the Windows2 folder contains a folder named Modes, which contains a folder named editor. Modes represent the possible positions at which TopComponents can be shown in the application. The editor folder contains a .wstcref file for our TopComponent, which refers to the real WSTCREF file. This registers the TopComponent in the mode editor, so it shows up where typically editor windows are opened, which is the central part of the main window.
  • Next , take a look at the folder Actions. It contains a folder named Window which contains a file declaring the action opening the TaskEditorTopComponent. The name is typically following Java class naming conventions with dots replaced by dashes and ending in .instance. The declaration of the virtual file itself consists of three critical parts. The attribute component describes how to create the component (methodvalue declares which method to call). The attribute displayName describes the default action name as shown in the example, in menu items. A possible declaration is the bundle value which describes the bundle and key to use to retrieve the display name. The attribute instanceCreate uses a static method call to create a real action to use.
  • The folder Menu describes the application main menu. The folder Window contains a .shadow file. The attribute originalFile uses the full path in the SystemFileSytem to delegate to the original action declaration. As described above, .shadow files are used as symbolic links to real-defined virtual files. This declaration adds the action to the real menu bar of the application.

As a result, important parts of the Window System API are not called programmatically, but are simply used declaratively. Declarative aspects include configuration and the positioning of windows, as well as the construction of the menu.

In addition, you discovered that the wizard for creating TopComponents always creates singleton views. If you would like to change that, you need to adapt the code created by the wizard. For the time being, it is sufficient to use the singleton approach, particularly as it is more resource-friendly.

(For more resources on NetBeans, see here.)

Automatic window lifecycle management

A further major advantage of the NetBeans Window System is that it provides a WindowManager that controls the lifecycle of all the windows defined in the application. The WindowManager notifies all TopComponents about state changes using callback methods, listed as follows:

componentOpened() It is called after the TopComponent has been opened. If multiple TopComponents are opened into the same position (called mode), the NetBeans Window System uses a tabbed container, with one TopComponent per tab. Of all available TopComponents found within a shared tabbed container, only the content of the selected TopComponent is visible.
componentShowing() It notifies the component that its content is now visible. This TopComponent is now either selected or is the only component in a separate container.
componentActivated() It is called after the TopComponent has gained the input focus or has become the selected component.
componentDeactivated() It is called after the TopComponent has lost the input focus.
componentHidden() It notifies the TopComponent that its content is no longer visible.
componentClosed() It is called after the TopComponent has been closed.

Let's illustrate this lifecycle via an example that logs all the callback methods to the output window of NetBeans IDE, which is your development environment on top of the NetBeans Platform.

  1. Create a new NetBeans Platform application and name it WindowSystemExamples.
  2. Add a new module named LifeCycle, with Code Name Base com.netbeansrcp.lifecycle.
  3. Add a TopComponent, with Class Name Prefix prefix LifeCycleDemo, making sure to indicate that it should be automatically opened in the editor area at application startup.
  4. Override the lifecycle methods as follows:

    public void componentOpened() {

    protected void componentShowing() {

    protected void componentActivated() {

    protected void componentDeactivated() {

    protected void componentHidden() {

    public void componentClosed() {

Start the new application. The TopComponent LifeCyleDemoTopComponent is automatically opened at startup. Select the TopComponent and inspect the output in the NetBeans IDE Output Window. You should see the following:


The TopComponent has passed the first half of its lifecycle and is now activated.

Close the LifeCyleDemoTopComponent and inspect the output again, to understand the second half of the TopComponent lifecycle. You should see the following output:


You have learned that the TopComponent's lifecycle is automatically controlled by the NetBeans Platform. Between the start and the end of the TopComponent's lifecycle are six different states, all managed by the NetBeans Platform, and with notifications sent via callbacks.

Programmatically managing the Window lifecycle

You can manage the lifecycle of a TopComponent programmatically. For this purpose, the TopComponent provides the following methods:

  • open(): Opens the TopComponent
  • requestVisible(): Requests to select to TopComponent
  • requestActive(): Requests to transfer the input focus to the TopComponent

Let's now modify the LifeCycleDemoTopComponent for demonstration purposes.

  1. Add a JButton to the TopComponent, as follows:

  2. Implement an ActionEventListener as follows:

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
    RequestProcessor.getDefault().post(new java.lang.Runnable() {
    public void run() {
    java.awt.EventQueue.invokeLater(new java.lang.Runnable() {
    public void run() {;
    }, 3000);
    RequestProcessor.getDefault().post(new java.lang.Runnable() {
    public void run() {
    java.awt.EventQueue.invokeLater(new java.lang.Runnable() {
    public void run() {
    }, 6000);

  3. Restart the application. When you click the button, the LifecycleDemoTopComponent is closed via the close() method, called above in the first line of the code you entered.

The RequestProcessor provides a thread pool. The default instance of this pool lets you execute a Runnable after a short delay, thanks to the post() method. As the TopComponent's lifecycle method should be called from the AWT event thread, you do not call them directly in the run() method, but by posting a new Runnable to the EventQueue, which in the end calls the Window System API methods.

The argument 3000 ensures that the execution of the Runnable is delayed for 3000 ms so that the TopComponent is opened again after 3 s.

After six seconds the second Runnable posted to the EventQueue is executed and requestActive() is called for your LifecycleDemoTopComponent. Your TopComponent is now shown in the foreground, if it had been behind other windows previously.

You have learned how to manage the lifecycle of a TopComponent. Via the example you have seen how to open a TopComponent and make it focusable.

Positioning of windows

The NetBeans Window System divides the available space in the main window into areas that are called "modes". Each mode represents a specific area of the main window, providing a container for windows in a predefined position in the frame. You can add windows, that is, TopComponents, to a mode, either declaratively or programmatically.

A standard layout is provided by the NetBeans Window System, corresponding to the layout of NetBeans IDE. For example, the predefined modes correspond to the names used in the corresponding positions in NetBeans IDE, such as "editor" and "explorer". If needed, you can define your own modes, too. No wizard is provided for this purpose in NetBeans IDE, so you need to create the mode definition files yourself manually.

In the previous section you learned about the layer.xml file. To create a default layout for an application, each TopComponent needs to be declaratively registered within the Windows2 | Modes folder, within a subfolder named after the mode in which the TopComponent should be docked.

To demonstrate declarative registration of TopComponents, edit the layer.xml in the LifeCycle module, changing the folder name Windows2 | Modes | editor to Windows | Modes | rightSlidingSide, as shown in the following code snippet:

<folder name="Windows2">
<folder name="Components">
<file name="LifecycleDemoTopComponent.settings"
<folder name="Modes">
<folder name="rightSlidingSide">
<file name="LifecycleDemoTopComponent.wstcref"

Select Clean and Build on the application node in the Projects window, to remove the build folder containing the last used window layout, and start the application again. When the application starts up, notice that the LifecycleDemoTopComponent is not opened in the editor mode. Instead, it is represented by a button on the right sidebar of the application (as shown in the screenshot below). That is the rightSlidingSide mode, providing a container for minimized windows.

As you have seen, providing a default layout via declarative registrations of TopComponents is rather easy. You only need to create an entry in the layer.xml for the TopComponent, in a folder with the name of the desired mode, within the Windows2 | Modes folder.

Sometimes declarative registration alone is too static for your business needs. Fortunately, positioning of TopComponents can also be done programmatically. In the next example, you create a TopComponent that moves to new modes via a click of a button.

  1. Add to the WindowSystemExamples application a new module named Modes, with the Code Name Base com.netbeansrcp.modes.
  2. Within the module, create a TopComponent called ModesDemo, which is opened when the application starts into the "editor" mode.

Add two JButtons to the TopComponent with the texts Back and Forward, as well as a JLabel with an empty initial text. The TopComponent should look as shown in the following screenshot:

In the Source view, add the following code:

private static final String[] MODES = new String[] {
"properties", "commonpalette", "rightSlidingSide",
"bottomSlidingSide", "output", "debugger", "navigator",
"explorer", "leftSlidingSide", "editor"
private void changeMode(boolean next) {
Mode currentMode = WindowManager.getDefault().findMode(this);
String currentModeName = currentMode.getName();

String nextModeName = "editor";
for (int i = 0; i < MODES.length; i++) {
String modeName = MODES[i];
if (modeName.equals(currentModeName)) {
if (next) {
nextModeName = (i + 1 < MODES.length) ? MODES[i + 1]
: MODES[0];
else {
nextModeName = (i - 1 >= 0) ? MODES[i - 1] :
MODES[MODES.length - 1];
Mode nextMode = WindowManager.getDefault().findMode(nextModeName);
if (nextMode != null) {
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {

The static string array contains the names of the most important modes. These modes can also be identified dynamically, by calling WindowManager.getDefault().getModes().

The ActionListener delegates the call to the method changeMode() and gives the desired back/forward direction. This method determines via WindowManager.getDefault ().findMode (this) the mode in which the TopComponent is displayed, as well as the name of the current mode.

The string array is then searched and dockInto(this) is called to dock the TopComponent into a different mode.

How to revert to the default layout?
As the layout of the NetBeans Platform is persisted when the application shuts down, first perform a Clean and Build on the application project. With the removal of the build folder, the layout settings are also deleted, so that the default layout is used when the application starts again.

Using the two buttons, you can let the TopComponent be docked in some of the most commonly used modes (as shown in the screenshot below).

You have programmatically docked a TopComponent into various places within the available modes in the application. In the process, you have learned how TopComponents can be docked dynamically, that is, at runtime, into desired positions. Both the declarative and the programmatic approaches to docking should now be familiar to you.


In this article we learned how to create new windows, that is, TopComponents, and also learned how to position them. In the next part we will learn how to customize the default window layout, how to group views so that they open and close as a unit and how to change the persistence of views across restarts of the application.

Further resources on this subject:

You've been reading an excerpt of:

NetBeans Platform 6.9 Developer's Guide

Explore Title