Introduction · Concepts · Sample Program Code
Color and Fonts Properties · Outliner Sizing · Column and Row Display Properties
Row and Column Visibility · Scrollbar Properties · Setting the Selection Mode
Node Properties · Folder Appearance · Events
Property Listing · Example Program
Outliners (also known as "trees") are standard Graphical User Interface (GUI) components common to most windowing systems which enable the display of hierarchically-organized data. The data items can be organized into columns for easier display. The JCOutliner
component enables Java developers to display hierarchical data such as file systems, catalogs, ordered lists, and organization charts in the form of a tree. Each item is either a folder (a tree branch) or an item (a tree leaf). Each folder or item is displayed with an icon to its left. The appearance of each node is specified by a style. Column labels can also be optionally added. JCOutliner
has many features including column resizing and reordering. There is no equivalent to JCOutliner
in the classes provided with the AWT.
The user can control whether the data contained in a folder is to be displayed. The user can collapse or uncollapse a folder by either double-clicking on the folder, hitting the space key, or clicking on an optional shortcut button displayed to the left of the folder. Typing a character will cause the first item which starts with the character to be made visible and selected. If no item can be found, no action is taken.
The following illustration shows examples of the kinds of data that can be displayed using JCOutliner
.
Example JCOutliner application
The data displayed by the JCOutliner
component is assumed to be in the form of a tree. Each item of data is either a folder (a branch of the tree) or an item (a leaf of the tree).
The end-user can control whether the data contained in a folder is to be displayed or not; if the data is not displayed, the folder is collapsed. The end-user can collapse or un-collapse a folder by either clicking on the folder or clicking on the shortcut button. JCOutliner
follows standard Windows 95 behavior in this regard.
The shortcut button contains a character that indicates whether a folder is collapsed. If the button contains a "+" character, the folder is collapsed. If it contains a "
--"
character, the data contained in a folder is displayed.
The cursor keys can be used within a JCOutliner
to navigate through its various nodes and folders. The
UP and
DOWN cursor keys enable the user to move between items. If the user is over a closed folder and clicks the
RIGHT cursor key, JCOutliner
opens the folder and displays its children. Alternately, clicking the
ENTER key toggles the state of the folder that has focus. The
PAGE UP and
PAGE DOWN keys move focus to the top and bottom of the displayed outline respectively, and the
HOME and
END keys take the user to the top and bottom of the outline respectively.
The JCOutliner
component is a component that displays hierarchical information in the form of a tree. Each item of data in the tree is called a node
; the node data itself consists of one or more text strings called node labels
. The area in which nodes are displayed is called the node area
.
Nodes are of two types: items
and folder nodes
. The only difference between these two types of nodes is that a folder node can have zero or more children. Each node is indented to the right of its parent, and a root node must exist. The root node need not be visible, in which case all of its children are displayed at the right margin. There are two different node types in JCOutliner
: the JCOutlinerNode
object, which represents an item, and the JCOutlinerFolderNode
object, which represents a folder node. The JCOutlinerFolderNode
object is subclassed from the JCOutlinerNode
object, which means that JCOutlinerFolderNode
can use methods defined for JCOutlinerNode
.
The following figure illustrates these components and objects, and the tree concept.
The best way to describe many of the common features in JClass BWT JCOutliner
is to examine the code in a sample program that uses it. The following code builds a simple, interactive Outline using JCOutliner
components:
package jclass.bwt.examples; import jclass.bwt.BWTEnum; import jclass.bwt.JCItemEvent; import jclass.bwt.JCOutliner; import jclass.bwt.JCOutlinerEvent; import jclass.bwt.JCOutlinerFolderNode; import jclass.bwt.JCOutlinerListener; import jclass.bwt.JCOutlinerNode; import jclass.bwt.JCOutlinerNodeStyle; import jclass.contrib.ContribFrame; import jclass.util.JCUtilConverter; import jclass.util.JCVector; import java.awt.*; /** * This example demonstrates the use of a JCOutliner and its events. */ public class outliner extends java.applet.Applet implements JCOutlinerListener { final static String[] column_labels = { "Name", "Title", "Address", "Phone", "Salary" }; final static String dept[] = { "Management", "Accounting", "R&D" }; final static String mgmt_items[] = { "John Kricfalusi|President|983 Nickelodeon Street, Rexdale Ontario|(414) 999-9876|$10,000", "Hikaru Takei|VP|134 Adelaide Street, Suite 204, Toronto Ontario|(416) 594-1026|$23K", "James Q. Doohan|Director|1701 Planetia Blvd., Anytown, U.S.A.||$245,000" }; final static String accounting_items[] = { "Hikaru I. Takei|Payroll|134 Adelaide Street E., Suite 204, Anytown, U.S.A.|(999) 594-1026", "Melissa A. Truman|Receivable|475 Woodview Line, Anytown, U.S.A.|(999) 555-9030|$50,250", "Stephanie L. Truman|Payroll|388 Appleby Road, Anytown, U.S.A.|(999) 555-2642|$85,750" }; final static String rd_items[] = { "James Q. Doohan|Engineer|1701 Planetia Blvd., Anytown, U.S.A.||$245,000", "John F. Kricfalusi|Physicist|983 Nickelodeon Street, Anytown, U.S.A.|(999) 555-9876|$10,000", "Marc Lenard|Engineer|6 Gene Crescent, Anytown, U.S.A.|(999) 555-1212|$10/hr.", "Hikaru I. Takei|Musician|134 Adelaide Street E., Suite 204, Anytown, U.S.A.|(999) 594-1026|50%", "Melissa A. Truman|QA|475 Woodview Line, Anytown, U.S.A.|(999) 555-9030|$50,250", "Stephanie L. Truman|Technical Writer|388 Appleby Road, Anytown, U.S.A.|(999) 555-2642|$85,750", "Bill West|System Analyst|1001 Spumco Way, Anytown, U.S.A.|(999) 555-9966|$17,500" }; final static String[][] item_data = { mgmt_items, accounting_items, rd_items }; Image content_icon; /** * JCOutlinerListener methods */ /* * Adds items to a folder if it is opened, and destroys them * when it is closed. * It simulates the reading of the data from a database. */ public void outlinerFolderStateChangeBegin(JCOutlinerEvent ev) { JCOutlinerFolderNode folder = (JCOutlinerFolderNode) ev.getNode(); JCOutliner outliner = (JCOutliner) ev.getSource(); // Ignore root node if (folder == outliner.getRootNode()) return; // Create and add children to folder else if (ev.getNewState() == BWTEnum.FOLDER_OPEN_ALL) { if (folder.getChildren() != null) return; int pos = ((Integer)folder.getUserData()).intValue(); String[] items = item_data[pos]; JCOutlinerNodeStyle style = new JCOutlinerNodeStyle(); style.setItemIcon(content_icon); for (int i=0; i < items.length; i++) { JCVector label = outliner.getConverter() .toVector(this, items[i], '|', false); JCOutlinerNode newItem = new JCOutlinerNode(label); newItem.setStyle(style); folder.addNode(newItem); } } // Destroy folder's nodes else if (ev.getNewState() == BWTEnum.FOLDER_CLOSED) { folder.setChildren(null); } outliner.folderChanged(folder); } public void outlinerFolderStateChangeEnd(JCOutlinerEvent ev) {} public void outlinerNodeSelectBegin(JCOutlinerEvent ev) {} public void outlinerNodeSelectEnd(JCOutlinerEvent ev) {} public void itemStateChanged(JCItemEvent ev) {} public void init() { Image folder_opened = JCUtilConverter.toImage(this, "../images/foldero.gif"); Image folder_closed = JCUtilConverter.toImage(this, "../images/folderc.gif"); Image top = JCUtilConverter.toImage(this, "../images/top.gif"); content_icon = JCUtilConverter.toImage(this, "../images/content.gif"); // Force outliner to be same size as applet setLayout(new GridLayout(1,1)); setBackground(Color.lightGray); JCOutlinerNodeStyle style = new JCOutlinerNodeStyle(); style.setFolderOpenIcon(top); style.setFolderClosedIcon(top); JCOutlinerFolderNode root = new JCOutlinerFolderNode(null, "Personnel"); root.setStyle(style); JCOutlinerNodeStyle folder_style = new JCOutlinerNodeStyle(); folder_style.setFolderClosedIcon(folder_closed); folder_style.setFolderOpenIcon(folder_opened); folder_style.setShortcut(true); JCOutlinerFolderNode f = null; for (int i=0; i < dept.length; i++) { f = new JCOutlinerFolderNode(null, BWTEnum.FOLDER_CLOSED, dept[i]); f.setUserData(new Integer(i)); f.setStyle(folder_style); root.addNode(f); } JCOutliner outliner = new JCOutliner(root); outliner.getOutliner().setBackground(Color.white); outliner.setPreferredSize(400, 300); outliner.setColumnLabels(column_labels); outliner.setNumColumns(column_labels.length); outliner.getDefaultNodeStyle().setShortcut(true); outliner.addItemListener(this); // Open last folder outliner.setNodeState(f, BWTEnum.FOLDER_OPEN_ALL, true); add(outliner); } public Insets insets() { return new Insets(5,5,5,5); } public static void main(String args[]) { ContribFrame frame = new ContribFrame("Outliner"); outliner o = new outliner(); o.init(); frame.add(o); frame.pack(); frame.show(); } }
When this code is inserted into a program, it produces the following results:
A sample program containing JCOutliner components
This sample code is incorporated into the example file outliner.class provided with JClass BWT. For information on how to run this program, see the " Example Program " section at the end of this chapter.
There are several properties which can be used to customize the display of a JCOutliner
. The Background
and Foreground
properties can be used to set the color of the background and text/foreground elements of a JCOutliner
. Foreground
not only sets the color of any alphanumeric characters contained in the node label, but also of the arrow buttons and of the cursor within the text field.
The display of fonts within a JCOutliner
is controlled by the Font
property. For a listing of available fonts, see
.
The size of a JCOutliner
can be set using the PreferredSize
property which sets the container's preferred size. If either dimension is set to NOVALUE
, it is calculated by the subclass.
The individual PreferredWidth()
and PreferredHeight()
methods each deal with the subclass' preferred width (default: 100
). The subclass should not include the inset sizes in its calculation, as these are added by JCOutliner
.
Whenever possible, the JCOutliner
component is sized to its preferred width when displayed. If this is not possible, the width of the node area is reduced accordingly. If the width of the component is greater than the preferred width, the node area is stretched accordingly. If a multi-column display is defined, the last column is stretched.
The display of the text contained within a JCOutliner
is controlled by the VisibleRows
and the various Column
properties (ColumnAlignments
, ColumnButtons
, ColumnLabels
, ColumnLeftMargin
, ColumnRightMargin
, and ColumnWidths
).
VisbleRows
takes an integer value equal to the number of rows to be displayed. If VisibleRows
is set to 0
(default), the text field attempts to resize itself so that all of its items are visible.
The ColumnAlignments
property is used to set a column's alignment. It uses the parameter align
, which can take one of the following values: TOPLEFT
, TOPCENTER
, TOPRIGHT
, MIDDLELEFT
, MIDDLECENTER
, MIDDLERIGHT
, BOTTOMLEFT
, BOTTOMCENTER
or BOTTOMRIGHT
. By default, ColumnAlignments
is set to MIDDLELEFT
.
To add labels to a column, use the ColumnLabels
property, which takes a string value or a JCString. To create labels that look and behave like buttons, use the ColumnButtons
property instead. This property turns each label into a button that the user can interact with. There are cases when it desirable to allow the user to sort the information contained within an outliner. The ColumnLabelSort
property is used to specify whether a column is sorted when its button is clicked (default: true
).
Instead of adding string values for each label, it is also possible to assign vectors or JCVectors
as labels to the node.
Margin values for JCOutliner
columns can be explicitly set using the ColumnLeftMargin
and ColumnRightMargin
properties. Each sets the column's respective margins as a pixel value. They take an integer value corresponding to the column being set, and the value in pixels of the column margin. By default, both are set to 5
pixels.
To set the width of the columns appearing in a JCOutliner
, use the ColumnWidths
property. If a column's value is set to VARIABLE
, the width of the column is set to the widest value contained within in the column.
The spacing between rows is set by the Spacing
property (default: 0
).
The VisibleRows
property sets the number of rows that are visible in a JCOutliner
. If set to 0
(default), the list will attempt to resize itself so that four items are visible. If it is set to another value, only the number of rows specified will be displayed. VisibleRows
only works if the list is made visible beforehand.
Column visibility in JCOutliner
is set using the NumColumns
property. If set to VARIABLE
(default), all columns are displayed.
If an outline is too large to be displayed within the node area, scrollbars are displayed. The end-user can click on these scrollbars to specify the portion of the tree to be displayed in the node area. By default, horizontal scrollbars, vertical scrollbars, or both appear whenever appropriate. These are separate components which are defined as children of the JCOutliner
component, and are controlled by ScrollbarDisplay
.
The ScrollbarDisplay
property is used to determine under what circumstances the scrollbars are to be displayed. ScrollbarDisplay
can take one of five different values: DISPLAY_ALWAYS
(scrollbars are always displayed), DISPLAY_AS_NEEDED
(scrollbars are displayed as necessary), DISPLAY_VERTICAL_ONLY
(the vertical scrollbar is always displayed), DISPLAY_HORIZONTAL_ONLY
(the horizontal scrollbar is always displayed), or DISPLAY_NONE
(never display scrollbars). By default, ScrollbarDisplay
is set to DISPLAY_AS_NEEDED
.
The ScrollbarOffset
property sets the amount of space between the scrollbar and the component for the JCOutliner
in pixels (default: 5
).
The AutoSelect
property can be used to set the selection mode for an item or items that have focus with a JCOutliner
. If set to true
(default), the node which currently has focus is also selected. If AutoSelect
is set to false
, the node which currently has focus is not automatically selected. The latter setting is useful in situations where the user is expected to use the keyboard rather than the mouse to traverse and select multiple items within a JCOutliner
, as it allows the user to move about the various nodes of the outliner without automatically selecting individual items.
There are two properties that control the display of nodes within a JCOutliner
: NodeHeight
and NodeIndent
.
NodeHeight
is used to explicitly set the height of each node in pixels. By default it is set to 0
, at which point the height of the node is determined using the largest font and image height that appears in the list of node styles.
NodeIndent
is used to set the indentation of each node relative to its parent in pixels (default: 15
).
The appearance of nodes can be changed from the default by using the various properties derived from JCOutlinerNodeStyle
. Several nodes can share a JCOutlinerNodeStyle
instance. The following are a list of node style properties that can be used:
BackgroundSelected
- sets the node's background color when it is selected (default: outliner's foreground color);FolderClosedIcon
- sets the node's icon if it is a closed folder;FolderClosedSelectedIcon
- sets the node's icon if it is a closed folder and it is selected;FolderOpenIcon
- sets the node's icon if it is an open folder;FolderOpenSelectedIcon
- sets the node's icon if it is an open folder and it is selected Font
- sets the node's font (default: outliner's font);Foreground
- sets the node's foreground color (default: outliner's foreground color);ForegroundSelected
- sets the node's foreground color when it is selected (default: outliner's background color);IconSpacing
- sets the horizontal spacing between the icon and the label (default: 5
); ItemIcon
- sets the node's icon if it is not a folder;ItemSelectedIcon
- sets the node's icon if it is not a folder and it is selected;LineColor
- sets the color of the line connecting a folder to its children (default: outliner's foreground color);Shortcut
- sets whether a shortcut button should be drawn beside a folder (default: false
).It should be noted that all nodes should share a common style, so as not to confuse the user.
One additional property, RootVisible
, is used to specify whether the root node is displayed. If true
(default), the root node is drawn.
Normally, two states are defined for a folder: closed and open. A folder is closed if its children are not visible. A folder is open if its children are visible. By default, a folder state change (such as a double-click of the mouse button) toggles between these two states.
It is possible to specify additional folder states that are somewhere between completely closed and completely open using the StateList
property. StateList
sets a list of values used for double-clicking on a folder or clicking its shortcut button. The folder's state is cycled through the list. StateList
can take one of five different values: FOLDER_CLOSED
(the folder is closed and no children are visible), FOLDER_OPEN_NONE
(the folder is open and no children are visible), FOLDER_OPEN_FOLDERS
(the folder is open, but only the folder children are visible), FOLDER_OPEN_ITEMS
(the folder is open, but only the non-folder children are visible, or FOLDER_OPEN_ALL
(the folder is open, and all children are visible).
You can use the setTree()
method to create a node hierarchy by parsing a string list. Each line in the list represents a node's label. Tabs at the start of each line supply the tree hierarchy. Lines with the same indentation level are children. Nodes without children are assumed to be items. To create a folder without children, append the string "(FOLDER)" to the line.
The example below creates three folders and two items under Folder1.
import jclass.bwt.*; import java.awt.*; import java.applet.*; public class treeexample1 extends Applet { String[] outlinerNodes = { "Folder1", " I_am_an_item1", " I_am_an_item2", "Folder2(FOLDER)", "Folder3(FOLDER)"}; public void init() { JCOutliner outliner = new JCOutliner(); outliner.setTree(outlinerNodes); add(outliner); } public static void main(String args[]) { Frame frame = new Frame("Testing"); treeexample1 mytree = new treeexample1(); mytree.init(); frame.setLayout(new GridLayout(1,1)); frame.add(mytree); frame.pack(); frame.show(); } }
When this code is inserted into a program, it produces the following results:
A sample program using the setTree() method
As noted above, if a node has no children, it is assumed to be an item. If we add an extra tab before i_am_an_item2, this will change i_am_an_item1 into a folder. For example:
import jclass.bwt.*; import java.awt.*; import java.applet.*; public class treeexample2 extends Applet { String[] outlinerNodes = { "Folder1", " I_am_nolonger_an_item1", " I_am_an_item2", "Folder2(FOLDER)", "Folder3(FOLDER)"}; public void init() { JCOutliner outliner = new JCOutliner(); outliner.setTree(outlinerNodes); add(outliner); } public static void main(String args[]) { Frame frame = new Frame("Testing"); treeexample2 mytree = new treeexample2(); mytree.init(); frame.setLayout(new GridLayout(1,1)); frame.add(mytree); frame.pack(); frame.show(); } }
When this code is inserted into a program, it produces the following results:
A sample program using the setTree method
A class can be notified when the user presses the
ENTER
key or double-clicks a node within an JCOutliner
by implementing the JCActionListener
interface and registering itself with the outliner via addActionListener
, as the following code demonstrates:
public interface JCActionListener { public void actionPerformed(JCActionEvent e); } public class JCActionEvent { // Returns the component where the event originated. public Object getSource() // Returns the event type: ACTION_PERFORMED. public int getId() }
A class can be notified when the user selects an item in a JCOutliner
by implementing the JCItemListener
interface and registering itself with the outliner via addItemListener
:
public interface JCItemListener { public void itemStateChanged(JCItemEvent e); } public class JCItemEvent { // Returns the component where the event originated. public Object getSource() // Returns the event type: ITEM_STATE_CHANGED. public int getId() // Returns the node where the event occurred. public Object getItem() // Returns the state change type which generated the event: SELECTED or DESELECTED public int getStateChange() }
To receive additional information, a class can implement the JCOutlinerListener
interface, and register itself with the outliner via addItemListener
.
public interface JCOutlinerListener extends JCNodeListener { // Invoked before an node is selected. The event's values can be modified via its setXXX methods. public void outlinerNodeSelectBegin(JCOutlinerEvent e); // Invoked after an node is selected. Any changes made to the event are ignored. public void outlinerNodeSelectEnd(JCOutlinerEvent e); // Invoked before a folder's state is changed. The event's values can be modified via its setXXX methods. public void outlinerFolderStateChangeBegin(JCOutlinerEvent e); // Invoked after a folder's state is changed. Any changes made to the event are ignored. public void outlinerFolderStateChangeEnd(JCOutlinerEvent e); }
It will then be passed to JCOutlinerEvents
:
public class JCOutlinerEvent extends JCItemEvent { // Gets the node whose state will be changed. public JCOutlinerNode getNode() // Gets the node's current state public int getState() // Gets the node's new state. public int getNewState() // Sets the node's new state. This is ignored if the node is not a folder. public void setNewState(int v) // Gets the current AllowChange value. public boolean getAllowChange() // Determines whether the selection or state change should be allowed (default: true). public void setAllowChange(boolean v) }
Enhanced printing functionality has been enable under JDK 1.1. The JCOutliner.print()
method will print the outliner on multiple pages, with repeating header, outliner and all nodes open. Printed outliners do not display scrollbars.
For example, to print an outliner based on a java.awt.Button press, you could write the following code:
public boolean handleEvent(Event event) { if (event.id == Event.ACTION_EVENT) { JCOutliner.print();
The JCOutlinerPrinter class provides methods for more detailed control of print output from a JCOutliner application or applet. To obtain the JCOutlinerPrinter object associated with the outliner, use:
JCOutlinerPrinter outlinerPrinter = outliner.getOutliner().getOutlinerPrinter();
The method setOutlinerOnEachPage()
determines whether the outliner column is repeated on each page when more than one page is required to print all of the columns in the outliner.
The method setPrintAllNodes()
prints all nodes open if true
and as is if false
.
The following methods define printed page sizes:
getPageDimensions(); getPageWidth(); getPageHeight();
These methods retrieve page information from the printer.
Page margins are set using the setPageMargins()
method. This method uses the awt.Insets class to set the margins as in the following example:
outlinerPrinter.setPageMargins(new Insets(54,36,36,54));
By default, JCOutliner sets one margins in pixels based on the printer resolution. To specify margin units in inches, use the variable MARGIN_IN_INCHES
in the setMarginUnits()
method:
outlinerPrinter.setMarginUnits(JCOutlinerPrinter.MARGIN_IN_INCHES);
You can retrieve page margins based on the Insets of the page using the getPageMargins()
method.
Use getPageResolution() to get the printer page resolution. The default is 72 pixels per inch.
The JCOutliner.print() method will handle basic printing tasks. However, you can use JCOutlinerPrinter class's methods to create your own code to handle custom printing tasks.
The code below demonstrates how to use the JCOutlinerPrinter class to print a range of pages.
public void print() { PrintJob job = getToolkit().getPrintJob(getFrame(), "Print", null); if(job == null) return; Dimension pd = job.getPageDimension(); outlinerPrinter.setPageDimensions(pd.width, pd.height); int pages = outlinerPrinter.getNumPages(); Graphics gc; for(int p = 1; p <= pages; p++) { gc = job.getGraphics(); if(gc != null) { outlinerPrinter.drawPage(gc, p); gc.dispose(); } } job.end(); }
Headers and footers are applied using JCOutlinerPrintListener
receiving JCOutlinerPrintEvent
events. A JCOutlinerPrintEvent
is posted for each page during printing, and provides a graphic object clipped to the allowable paint region and the page number of the current page:
public JCOutlinerPrintEvent(JCOutlinerInterface outliner, Graphics gc, int page, int type) public Graphics getGraphics() public int getPage()
The JCOutlinerPrintListener
requires that two methods are defined:
public void printPageHeader(JCOutlinerPrintEvent
e); public void printPageFooter(JCOutlinerPrintEvent
e);
The following code would produce a footer:
public void printPageFooter(JCOutlinerPrintEvent
e) {
Graphics gc = e.getGraphics();
Rectangle r = gc.getClipRect();
FontMetrics fm = gc.getFontMetrics();
String page = "Page " + e.getPage();
String note = "Use JCOutlinerPrintListener to customize the footer!";
// Pad the footer text to the right
gc.drawString(page, 0, r.height/2);
gc.drawString(note, r.width - fm.stringWidth(note), r.height/2);
}
When more than one page is required to print all of the nodes, setHeaderOnEachPage()
controls whether the header is repeated at the top of each page.
The following summarizes the properties of JCOutliner
. Complete reference documentation is available online in standard
javadoc format in
jclass.bwt.JCOutliner.html.
Demonstration programs and example code containing JCOutliner
come with JClass BWT. The examples can be viewed in applet form by launching index.html within the /jclass/bwt/examples directory.
outliner.class can also be run as a stand-alone Java application from the command prompt by typing:
java jclass.bwt.examples.outliner
JCOutliner contains classes that enable end-users to print applications using the outliner. Since printing is not available under JDK 1.0, these classes apply to JDK 1.1 applications only.