Õ¾ÄÚËÑË÷: ÇëÊäÈëËÑË÷¹Ø¼ü´Ê
µ±Ç°Ò³Ãæ: ͼÊéÊ×Ò³ > SWT: The Standard Widget Toolkit

9.2 Classes Table, TableItem, and TableColumn - SWT: The Standard Widget Toolkit

Previous Section  < Day Day Up >  Next Section

9.2 Classes Table, TableItem, and TableColumn

9.2.1 Example

graphics/09inf03.gif

9.2.2 Table, TableItem, and TableColumn Hierarchies

graphics/09inf04.gif

9.2.3 Table Styles

Style

Description

SWT.SINGLE

Create a single-select table

SWT.MULTI

Create a multiselect table

SWT.CHECK

Create a table with check boxes

SWT.FULL_SELECTION

The selection is expanded to fill an entire row

SWT.HIDE_SELECTION

The selection is hidden when focus is lost


9.2.4 Table Events

Event

Description

SWT.Selection

A table item was selected

SWT.DefaultSelection

A table item was default selected


9.2.5 TableItem Styles (none)

Style

Description


9.2.6 TableItem Events (none)

Event

Description


9.2.7 TableColumn Styles

Style

Description

SWT.LEFT

The table column is left-justified

SWT.RIGHT

The table column is right-justified

SWT.CENTER

The table column is centered


9.2.8 TableColumn Events

Event

Description

SWT.Selection

The table column was selected

SWT.Move

The table column was moved

SWT.Resize

The table column was resized


Tables are selectable controls that are capable of displaying vertical rows of items. Each row is represented by an instance of TableItem. Table items are automatically added when created and are positioned in the parent using the location constructor parameter.

Tables are analogous to lists but are more flexible. Although lists can contain only strings, tables can contain strings and images. Tables are also capable of displaying multiple columns. A table that is displaying columns uses instances of TableColumn to represent each column.

Tables can optionally include headers and grid lines. The header portion of a table resembles a row of push buttons displayed at the top of the control. Each button in the header is the width of the corresponding table column. Grid lines refer to a horizontal and/or vertical pattern that is drawn to accentuate the rows and columns. This pattern is often composed of a matrix or grid of lines drawn between the items or by alternating the background color of the rows.[5]

[5] This is the case on GTK where the native table control does not draw lines. Because the native control is used to draw the table, grid lines are drawn using the native support. If the native control does not have this capability, grid lines will not be drawn.

Table shares many of the same concepts, limitations, and behaviors of List and Tree.

Tables Always Have Scroll Bars

Due to the same limitation that affects trees and for the same reasons, tables always have scroll bars (see Classes Tree and TreeItem for a full explanation).


Like List and Tree, Table can allow either a single item or multiple items to be selected at a time and supports scroll bars and borders. If you are familiar with the sections Classes Tree and TreeItem and Class List, you will find the material in this section easy to follow. The API of class Table is very similar to those classes.

Users are familiar with tables because they are used everywhere on the desktop. For example, the Windows XP Task Manager uses a table with multiple columns to show tasks and their status.

A Table Is Not a Spreadsheet

Despite the fact that tables have rows and columns, Table is not a general-purpose spreadsheet class. If you are expecting the features and capabilities of something like Microsoft Excel, you will be disappointed. Native tables just aren't that sophisticated. Nevertheless, they are useful in many contexts. The class TableEditor, found in the package org.eclipse.swt.custom, provides the rudimentary capability to place a control within a Table cell. This can be used to do "in-place editing," for example, as we do in the FileExplorer example in Part III.


9.2.9 Full Row Selection

When the user selects a table item, some platforms require the user to select either the text or icon in order to select the item.[6] On other platforms, the user can select anywhere within the same row. This behavior is platform-specific but can be configured by creating a table with the style SWT.FULL _SELECTION. When this style is provided, selecting any column on the same row as a table item selects the item. Tables often indicate SWT.FULL _SELECTION by drawing the selection highlight over the entire row. It is important to note that SWT.FULL_SELECTION is a hint and may not be honored on some platforms.

[6] For example, Microsoft Windows forces you to do this, whereas the Macintosh does not.

9.2.10 Hiding the Selection

When a table loses focus, the selection is either unchanged or draws in some manner to indicate that focus is no longer in the control. The SWT.HIDE _SELECTION style causes a table to hide its selection when focus is lost, drawing as though it were not selected. The SWT.HIDE_SELECTION style is a hint that may not be honored on some platforms.

9.2.11 Tables in List Mode

When you create table items but do not create any table columns, Table acts like List. This kind of table is said to be operating in "list mode." However, even though you did not create a table column, the user still sees a column of items, just like the column of strings that is displayed by a list. This can be a bit confusing at first because there is clearly a column of items on the screen but a table column was not created. It helps in this case to think of the table as a fancy kind of list, one that is capable of displaying both icons and strings. List does not require you to create a list column in order to display strings, so neither does Table.

The following program creates a table with 1,000 items but does not create a table column.






public static void main(String[] args) {

    Display display = new Display();

    Shell shell = new Shell(display);

    Table table = new Table(shell, SWT.BORDER);

    for (int i = 0; i < 1000; i++) {

        TableItem item = new TableItem(table, SWT.NULL);

        item.setText("Item " + i);

    }

    table.setSize(200, 200);

    shell.pack();

    shell.open();

    while (!shell.isDisposed()) {

        if (!display.readAndDispatch()) display.sleep();

    }

    display.dispose();

}


9.2.12 Getting the Items

Using getItems(), you can retrieve the items that you created in a table.

getItems() Returns the items, which is an array of table items. The array that is returned is a copy so that modifying this array will not affect the control.

getItem(int index) Returns the item at an index. If the index is out of range, an IllegalArgumentException ("Index out of bounds") is thrown.

getItemCount() Returns the number of items in the control.

Where Is the setItems() Method?

The reason that there isn't a setItems() method for Table is a direct result of the rule that widgets are always created with a parent. When a table item is created, it is already inserted into the table. When a table item is disposed, it is removed from the table and is no longer valid. Given these two conditions and the fact that an item can have only one parent, there are no possible items for hypothetical setItems() method to insert.


9.2.13 Headers and Grid Lines

Headers and grid lines are properties of tables. Although it is possible to show both when a table is in list mode, it generally is not very useful. You will use both when we describe Tables with Multiple Columns later in this chapter.

setHeaderVisible(boolean visible) Sets the visibility state of the header.

getHeaderVisible() Returns the visibility state of the header.

getHeaderHeight() Returns the height of the header. If the header is not visible, the height is zero. On all platforms, the header is considered to be within the client area of the table.[7] This means that you may need to get the height of the header in order to compute the preferred size of a table.

[7] Although table headers seem as though they should be "trimming," the underlying implementation of tables on many platforms uses a native header control. This control is a child of the table and is positioned within the client area of the table. Because SWT answers the client area by querying the operating systems, the header is not part of the trim.

setLinesVisible(boolean visible) Sets the visibility state of the grid lines.

getLinesVisible() Returns the visibility state of the grid lines.

9.2.14 Item Height

You can find out the height of an item within a table control using getItemHeight().

getItemHeight() Returns the height of an item in the control. This value can be different from the height of the font that is used by the control, because some platforms include spacing between items.

The getItemHeight() method is often used to compute the initial size of a control, in this case, a table. Refer to the section Lines and the Line Delimiter in Class Text for an example of this. The code to compute the initial size for a table is equivalent but uses getItemHeight() and getHeaderHeight() instead of getLineHeight().






int height =

    rows * table.getItemHeight() + table.getHeaderHeight();

int width = columns * fm.getAverageCharWidth();

table.setSize(table.computeSize(width, height));


9.2.15 Tables with Multiple Columns

To have multiple columns in a table, you must create instances of TableColumn to represent each column. As soon as you create the first table column, the table is no longer operating in list mode. This means that you are responsible for setting the widths of the columns so that the user can see the data that they will contain.

The following program creates a table with 1,000 items and creates a single table column. The table column is set to be 100 pixels wide so the user can see the strings. Otherwise, the code is identical to the example code in Tables in List Mode.






public static void main(String[] args) {

    Display display = new Display();

    Shell shell = new Shell(display);

    Table table = new Table(shell, SWT.BORDER);

    TableColumn column = new TableColumn(table, SWT.NONE);

    column.setWidth(100);

    for (int i = 0; i < 1000; i++) {

        TableItem item = new TableItem(table, SWT.NULL);

        item.setText("Item " + i);

    }

    table.setSize(200, 200);

    shell.pack();

    shell.open();

    while (!shell.isDisposed()) {

        if (!display.readAndDispatch()) display.sleep();

    }

    display.dispose();

}


A table that has one table column is not particularly useful (although were the header to be visible, a program could use it to invoke a sort operation). On some platforms, tables use the column width to determine when scroll bars are needed. This means that in the above example, if a table item were to contain a string that was wider than 100 pixels, it would be clipped. This does not happen to a table that is operating in list mode. Because there are no table columns, there is nothing to clip.

When you use a table that has multiple columns, often you will decide to show the table header. By default, the header is not visible. Showing the header allows the user to resize the columns.

Here is a more realistic example that creates a table with a header and multiple columns. To ensure that the table and table columns are a reasonable size, the table columns are packed after all of the items have been created. Figure 9.5 shows the result running on Macintosh OS X.






static final int COLUMNS = 8, ROWS = 8;

public static void main(String[] args) {

    Display display = new Display();

    Shell shell = new Shell(display);

    Table table = new Table(shell, SWT.BORDER);

    table.setHeaderVisible(true);

    table.setLinesVisible(true);

    for (int i = 0; i < COLUMNS; i++) {

        TableColumn column=new TableColumn(table,SWT.NONE);

        column.setText("Column " + i);

    }

    for (int i = 0; i < ROWS; i++) {

        TableItem item = new TableItem(table, SWT.NULL);

        for (int j = 0; j < COLUMNS; j++) {

            item.setText(j, "Item " + i + "-" + j);

        }

    }

    for (int i = 0; i < COLUMNS; i++) {

        TableColumn column = table.getColumn(i);

        column.pack();

    }

    table.pack();

    shell.pack();

    shell.open();

    while (!shell.isDisposed()) {

        if (!display.readAndDispatch()) display.sleep();

    }

    display.dispose();

}


Figure 9.5.

graphics/09fig05.gif


9.2.16 Text and Images in a Table Column

TableColumn, like many other widgets in SWT, supports the standard API to set and get text and images. TableColumn supports mnemonic characters in strings but does not wrap or support the SWT.WRAP style.

setText(String string) Sets the text for the column. The string cannot contain line delimiters. Mnemonics characters, indicated by '&', are supported.

getText() Returns the text. This is an empty string if the text has never been set.

setImage(Image image) Sets the image for the column.

getImage() Returns the item image. This is null if the image has never been set.

9.2.17 The Width of a Table Column

When a table column is created, like the other widgets in SWT, its width is zero. You can use setWidth() or pack() to resize a table column.

setWidth(int width) Sets the width of the column.

getWidth() Returns the width of the column.

pack() Sets the width of the column to be wide enough to show the maximum of the contents of the header item and the column of data in the table. For very large tables, this method can be time-consuming because it may need to measure all the data in the column.

When to Set the Width of a Table Column

Generally, it's a bad idea to set the width of a table column after the table has been displayed. The problem with doing this is that the user can resize the same column, leading to a situation where you and the user are fighting over the width. A friendly user interface always lets the user win.


9.2.18 Alignment in a Table Column

When a table column is created, the alignment of the column can be configured using one of the styles SWT.LEFT, SWT.CENTER, or SWT.RIGHT, just like Label and Button. Alignment in TableColumn differs from alignment in the other widgets because it applies to the entire column, not just the text or image in the header.

After the column has been created, the setAlignment() method can be used to change alignment.

setAlignment(int alignment) Sets the alignment for the column to be either left-, center-, or right-aligned, depending on the argument.

getAlignment() Returns the alignment for the column.

The default alignment style for a table column is SWT.LEFT. Unlike Button alignment, TableColumn alignment is not part of the platform look and feel, so you should feel free to change it to suit your needs.

The First Column in a Table Is Always Left-Aligned

Due to a restriction in Microsoft Windows, the alignment of the first column in a table cannot be changed. To create programs that are portable to other platforms, this restriction is enforced by SWT on every platform. To work around this problem, application programs can create a zero-sized first column.


9.2.19 Text and Images in a Table Item

TableItem, like TreeItem and other widgets, supports the standard API to set text and images. Unlike TreeItem, when the table has multiple columns, you can set the text and image for each individual cell. TableItem does not support mnemonics, wrapping, or the SWT.WRAP style.

setText(String string) Sets the text for the table item. This is the same as setText(0, string).

setText(int index, String string) Sets the text that will be displayed in the column (of the table item) that is specified by the given column index. The string cannot contain line delimiters or mnemonics characters.

getText() Returns the table item text. This is the same as getText(0).

getText(int index) Returns the text of the column (of the table item) that is specified by the given column index. This is an empty string if the text has never been set.

setImage(Image image) Sets the image for the item. This is the same as setImage(0, image).

The First Image Defines the Size of All Images in the Control

Due to a Windows limitation, just like ToolBar, TabFolder, and Tree, Table scales the images it displays to be the size of the first image inserted into the control.


setImage(int index, Image image) Sets the image that will be displayed in the column (of the table item) that is specified by the given column index.

getImage() Returns the TableItem image. This is the same as get-Image(0).

getImage(int index) Returns the image of the column (of the table item) that is specified by the given column index. This is null if the image has never been set.

TableItem provides two convenience methods that allow you to set multiple strings and images at the same time. They are currently no faster than setting the individual properties but may be optimized in the future.

setText(String[ ] strings) Sets the text for each column of the table item to the corresponding string in the array.

setImage(Image[ ] images) Sets the image for each column of the table item to the corresponding image in the array.

9.2.20 Checked and Grayed Table Items

Like Tree, Table supports checked and grayed check boxes. In order to check or gray the check box for an item, Table must have been created with the SWT.CHECK style.

setChecked(boolean checked) Sets the checked state of the item. The checked state of an item usually takes the form of a small check box, located before the icon or text for the item. If the table was not created with the SWT.CHECK style, nothing is checked.

getChecked() Returns the checked state of the item. If the table was not created with the SWT.CHECK style, false is returned.

setGrayed(boolean grayed) Sets the grayed state of the item. When the grayed state is true, the check box portion of the item draws using a grayed look. Note that the item is not disabled and can still be selected by the user. If the table was not created with the SWT.CHECK style, nothing is grayed.

getGrayed() Returns the grayed state of the item. If the table was not created with the SWT.CHECK style, false is returned.

9.2.21 TableItem Foreground, Background, and Font

Table supports the ability to set the foreground color, background color, and font of a table item. Unlike TreeItem (which does not support columns), TableItem allows you to set the color and font of an individual cell.

setForeground(Color color) Sets the foreground color of the item. This method sets the color for the every cell in the item.

setForeground(int index, Color color) Sets the foreground color of the item at a column index. If the color is null, the default foreground color of the item is restored.

getForeground() Returns the foreground color of the item.

getForeground(int index) Returns the foreground color of the item at a column index. If the color has not been set, the foreground color for the item is returned. If the item does not have a foreground color, the foreground color for the table is returned.

setBackground(Color color) Sets the background color of the item. This method sets the color for the every cell in the item.

setBackground(int index, Color color) Sets the background color of the item at a column index. If the color is null, the default background color of the item is restored.

getBackground() Returns the background color of the item.

getBackground(int index) Returns the background color of the item at a column index. If the color has not been set, the background color for the item is returned. If the item does not have a background color, the background color for the table is returned.

setFont(Font font) Sets the font that is used to draw the text in the item. If the font is null, the default font is restored.

setFont(int index, Font font) Sets the font of the item at a column index. If the font is null, the default font of the item is restored.

getFont() Returns the font that is used to draw text in the item. If the font has not been set, the default font is returned.

getFont(int index) Returns the font of the item at a column index. If the font has not been set, the font for the item is returned. If the item does not have a font, the font for the table is returned.

9.2.22 Removing Table Items

Table items are removed using the remove() and removeAll() methods.[8] Removing a table item has the same affect as disposing of it. However, it is much faster to remove a range of table items rather than dispose of them one at a time. For this reason, and because tables are index-based controls, it makes sense for Table to define remove() operations.

[8] By now, you should be familiar with the conventions of SWT, so it should not seem strange to you that Table has remove() methods but no add() methods. The reason that Table does not define add() methods is because table items are added when they are created. (See the Where Is the setItems() Method? box.)

remove(int index) Removes the item at an index. If the index is out of range, an IllegalArgumentException ("Index out of bounds") is thrown.

remove(int start, int end) Removes items from start to end, inclusive. If an index is out of range, an IllegalArgumentException ("Index out of bounds") is thrown.

remove(int[ ] indices) Removes items using an array of indices. If an index is out of range, an IllegalArgumentException ("Index out of bounds") is thrown.

remove(TableItem item) Returns the item at an index. This method removes the item from the control.

removeAll() Removes all the items from the control.

9.2.23 The Selection

Table supports the same kind of selection API as List, with the significant difference that parameters that are Strings in class List are TableItems in class Table. Tables cannot, by definition, contain duplicate instances of TableItem.[9] As you would expect, the strings and icons within different instances of TableItem can be the same, causing the two objects to look the same, despite the fact that they are not identical.

[9] This just is not possible, because there is no add() operation.

setSelection(int index) Selects the item at an index. Indices that are out of range are ignored. Any previous selection is cleared. The control is scrolled to bring the new selection to the attention of the user. If the control has a focus indicator, the focus indicator is assigned to the new selection.

setSelection(int start, int end) Selects all items in the range start to end, inclusive. If the control is single-select and the range contains more than one item, all of the indices are ignored. Once the previous selection has been cleared and the new items have been selected, the control is scrolled to show the new selection, and the focus indicator is assigned.

setSelection(int[ ] indices) Selects items using an array of indices. If the array is empty, the selection is cleared. If the control is single-select and the array contains more than one item, all of the indices are ignored. Once the previous selection has been cleared and the new items have been selected, the control is scrolled to show the new selection, and the focus indicator is assigned.

setSelection(TableItems[ ] items) Selects items using an array of items. This method behaves the same as though setSelection(indices) were called using an array of indices composed of the indices of each item in the control.

getSelection() Returns the selection as an array of items. This is a copy so that modifying the array has no effect on the control.

getSelectionCount() Returns the number of selected items.

getSelectionIndex() Returns the index of the item that is selected, based on the following rules.

  1. If no items are selected, –1 is returned.

  2. If the item that has the focus indicator is selected, that index is returned.

  3. Otherwise, the index of the first selected item is returned.

getSelectionIndices() Returns the selection as an array of indices. This is a copy so that modifying the array has no effect on the control.

isSelected(int index) Returns true if the item at the index is selected. If the item is not selected or the index is out of range, false is returned.

9.2.24 Deselecting and Selecting Items

To manipulate the selection of individual items without affecting the current selection, Table defines the equivalent List API. The methods in this section differ from the setSelection() methods in Table in the same significant ways.

  1. They do not clear the previous selection before acting.

  2. They do not cause the table to scroll.

deselect(int index) Deselects the item at an index. Indices that are out of range are ignored.

deselect(int start, int end) Deselects items in range start to end, inclusive. Indices that are out of range are ignored.

deselect(int[ ] indices) Deselects items using an array of indices. Indices that are out of range are ignored.

deselectAll() Deselects all items in the control.

select(int index) Selects the item at an index. Indices that are out of range are ignored.

select(int start, int end) Selects items in range start to end, inclusive. Indices that are out of range are ignored.

select (int[ ] indices) Selects items using the array of indices. This method behaves the same as though select(index) were called from a loop, using indices. Indices that are out of range are ignored.

selectAll() Selects all items in the control. If the control is single-select, the selection is not changed.

9.2.25 Scrolling

Because Table and List are index-based, scrolling in a table is equivalent to scrolling in a list. Both use the "top index" concept.

setTopIndex(int index) Scrolls to show the item indicated by the index parameter at the top of the control. Indexing starts at zero. If the index is out of range, the control scrolls to show the closest index that is within range. Depending on the platform and the number of items, it may not be possible for the particular item to become placed at the top of the control. This can happen when the platform does not allow the control to scroll so that white space follows the last item.

getTopIndex() Returns the line that is at the top of the control. The top index can change for many reasons other than calling setTopIndex(). For example, setSelection() can scroll the control to show the new selection.

Tables, lists, trees, and text controls all define showSelection(). Tables define the method showItem() that has an equivalent method in class Tree.

showSelection() Scrolls to show the selection. The selection is made visible somewhere inside the control. If the selection is already visible, nothing happens. Because the control may be scrolled, this method is used to bring the selection to the attention of the user.

showItem(TableItem item) Scrolls to show the item. As with showSelection(), the item is made visible but exact location of the item in the table is unspecified.

9.2.26 Search and Hit Test Operations

Tables provide a number of search operations that allow you to find the index of an item and determine the item that is underneath a point. The term hit testing is used to describe this kind of operation. Hit testing for controls was discussed in Getting the Cursor Control in the Display chapter.

indexOf(TableItem item) Returns the zero-based index of the item. If the item is not found, –1 is returned.

getItem(Point point) Returns the item under a point. The point is in the coordinate system of the control. If the table supports the SWT.FULL_SELECTION style, the search includes every column of the table. Otherwise, only the first column is searched.

9.2.27 Implementing Your Own Hit Test Operations

Sometimes you might need to find out the row and column of the item where the mouse was pressed in a table with multiple columns. Unfortunately, the getItem(Point point) method does not do what you want. For tables that are not created with SWT.FULL_SELECTION, only the first column is searched. Fortunately, table items allow you to determine their bounds. Using this, you can write your own hit test operation.

getBounds(int index) Returns the rectangle covered by the cell in the given column of the table item. The result is relative to the origin of the table.

getImageBounds(int index) Returns the rectangle covered by the image in the cell in the given column of the table item. The result is relative to the origin of the table.

The following fragment adds an SWT.MouseDown listener to a table. This listener uses getBounds() and Rectangle operations to determine the row and column in the table where the mouse was pressed.






table.addListener(SWT.MouseDown, new Listener() {

    public void handleEvent(Event event) {

        Rectangle rect = table.getClientArea();

        int itemCount = table.getItemCount();

        int columnCount = table.getColumnCount();

        int i = table.getTopIndex();

        while (i < itemCount) {

            TableItem item = table.getItem(i);

            for (int j = 0; j < columnCount; j++) {

                Rectangle bounds = item.getBounds(j);

                if (bounds.y > rect.height) return;

                if (bounds.contains(event.x, event.y)) {

                    System.out.println(item.getText(j));

                    return;

                }

            }

            i++;

        }

    }

});


9.2.28 Working with Large Tables

Tables that are virtual allow you to configure table items on demand. When the data for each table item is required, the table requests it from your program. The advantage of virtual tables is that they request only the data that they need. Performance is improved by putting the cost of configuring items where it is unnoticed and not bothering to configure items that are unreferenced.

SWT Under Construction

At the time of writing of this book, extensive investigation is being performed to determine whether native virtual table support can be made available via the SWT API. Until that investigation is complete, you can use the coding patterns described in this section to get some of the same benefits.

There is also a movement within the community to write an emulated Table class, which could provide virtual support as well as remove some of the other restrictions of native tables.


The following program creates a large table and fills it with strings, one page of data at a time. While Table is being filled, a progress bar shows the number of table items that have been created. The function that fills the table is called fillTable(). Several alternate implementations of the fillTable() method follow the main body of the code.






static final int COLUMNS = 3, ROWS = 100000, PAGE = 100;

static final String[][] DATA = new String[ROWS][COLUMNS];

static {

    for (int i = 0; i < ROWS; i++) {

        for (int j = 0; j < COLUMNS; j++) {

            DATA[i][j] = "Item " + i + "-" + j;

        }

    }

}



public static void main(String[] args) {

    Display display = new Display();

    Shell shell = new Shell(display);

    RowLayout layout = new RowLayout(SWT.VERTICAL);

    layout.fill = true;

    shell.setLayout(layout);

    final Table table = new Table(shell, SWT.BORDER);

    table.setLayoutData(new RowData(400, 400));

    table.setHeaderVisible(true);

    for (int i = 0; i < COLUMNS; i++) {

        TableColumn column=new TableColumn(table,SWT.NONE);

        column.setText("Column " + i);

        column.setWidth(128);

    }

    final ProgressBar progress =

        new ProgressBar(shell, SWT.NONE);

    progress.setMaximum(ROWS - 1);

    shell.pack();

    shell.open();

    fillTable(table, progress, PAGE);

    while (!shell.isDisposed()) {

        if (!display.readAndDispatch()) display.sleep();

    }

    display.dispose();

}


Performance Improvements in Table in R3.0

Even though R3.0 will not have shipped by the time this book is completed, many performance improvements have already been made in the Table class. If you try to run any of the examples in this section in R2.1.x, you will be disappointed.


Using setRedraw() When Creating Table Items

The simplest way to improve performance when filling a table is to use setRedraw(). Many operating systems use setRedraw() to optimize drawing and defer expensive calculations when adding (the native equivalent of) table items. For a complete description of setRedraw(), see Turning off Redraw in the Control Fundamentals chapter.

Here is an implementation of fillTable() that uses setRedraw() to turn off drawing while the table items are created.






static void fillTable(

    final Table table,

    final ProgressBar progress,

    final int page) {

    table.setRedraw(false);

    for (int i = 0; i < ROWS; i++) {

        TableItem item = new TableItem(table, SWT.NULL);

        for (int j = 0; j < COLUMNS; j++) {

            item.setText(j, DATA[i][j]);

        }

        if (i % page == 0) progress.setSelection(i);

    }

    table.setRedraw(true);

    progress.setSelection(0);

}


Creating TableItems in an Idle Handler

One technique that avoids making the user wait for a large table is to create table items in an "idle handler" (see Using asyncExec() from the User Interface Thread in the chapter Display). Because asyncExec() runnables are executed when the event loop is idle, priority is given to the user interface thread.

Creating table items this way is somewhat slower than the equivalent code that fills the table in the user interface thread. This is due to the overhead of the runnables and the fact that setRedraw() cannot be used without causing the table to flash. However, this approach has the advantage that the user can browse the items that have been created so far while the table is still being filled. A smarter version of fillTable() could also allow the user to cancel the operation.

This implementation of fillTable() uses asyncExec() to create a table item when the event loop is idle.






static void fillTable(

    final Table table,

    final ProgressBar progress,

    final int page) {

    final Display display = table.getDisplay();

    Runnable runnable = new Runnable() {

        int index = 0;

        public void run() {

            if (table.isDisposed()) return;

            int end = Math.min(index + page, ROWS);

            while (index < end) {

                TableItem item =

                    new TableItem(table, SWT.NULL);

                for (int j = 0; j < COLUMNS; j++) {

                    item.setText(j, DATA[index][j]);

                }

                index++;

            }

            if (end == ROWS) end = 0;

            progress.setSelection(end);

            if (index < ROWS) display.asyncExec(this);

        }

    };

    display.asyncExec(runnable);

     }


Creating Table Items in Another Thread

This approach is similar to using asyncExec() from the user interface thread. It has similar behavior and performance characteristics. However, the approach differs because it uses syncExec() and does not favor the user interface thread. If asyncExec() were to be used instead, the table-filling thread would never be blocked waiting on the user interface thread because asyncExec() does not wait. Threading, syncExec(), and asyncExec() are discussed in great detail in the Multithreaded Programming section of the chapter Display.

The following fillTable() implementation uses syncExec() to create items, a page at a time, in the user interface thread.






static void fillTable(

    final Table table,

    final ProgressBar progress,

    final int page) {

    final Display display = table.getDisplay();

    Thread thread = new Thread() {

        public void run() {

            int index = 0;

            while (index < ROWS) {

                if (table.isDisposed()) return;

                final int start = index;

                final int end=Math.min(index + page, ROWS);

                display.syncExec(new Runnable() {

                    public void run() {

                        if (table.isDisposed()) return;

                        for (int i = start; i < end; i++) {

                            TableItem item =

                             new TableItem(table,SWT.NULL);

                            for (int j=0; j<COLUMNS; j++) {

                                item.setText(j,DATA[i][j]);

                            }

                        }

                        int value = end == ROWS ? 0 : end;

                        progress.setSelection(value);

                    }

                });

                index = end;

            }

        }

    };

    thread.start();

}


Each of the above strategies will be applicable in some situation. Even when the virtual table support becomes available in SWT, these solutions are still applicable for data that is streamed.

9.2.29 Table Events

SWT.Selection (SelectionEvent)

The SWT.Selection event (typed event SelectionEvent) is sent whenever the user selects an item with the mouse or the keyboard. The relevant event fields during a selection event for Table are as follows.

Public Fields of Class Event That Are Valid during SWT.Selection

Field

Description

detail

Set to SWT.CHECK when the user selected the check box part of the item

item

The primary item that was affected when the selection changed. Typically, this item is selected but can be unselected when the detail is SWT.CHECK or in a multiselect table when the user changes the selection by deselecting the item.


SWT.DefaultSelection (SelectionEvent)

The SWT.DefaultSelection event (typed event SelectionEvent) is sent whenever the user performs the platform-specific operation that indicates default selection. On most platforms, default selection occurs when the user double-clicks on an item or presses the <Enter> key. The relevant event fields during a default selection event for Table are as follows.

Public Fields of Class Event That Are Valid during SWT.DefaultSelection

Field

Description

detail

Set to SWT.CHECK when the user selected the check box part of the item

item

The item that was affected to change the selection. Typically, this item is selected but can be unselected when the detail is SWT.CHECK or in a multiselect table when the user changes the selection by deselecting the item.


9.2.30 Using SWT.Selection with a Check Box Table

The following program uses the SWT.Selection event along with the item and detail fields to detect when a table item has been either checked or unchecked.






public static void main(String[] args) {

    Display display = new Display();

    Shell shell = new Shell(display);

    Table table = new Table(shell, SWT.CHECK | SWT.BORDER);

    for (int i = 0; i < 32; i++) {

        TableItem item = new TableItem(table, SWT.NULL);

        item.setText("Item " + i);

    }

    table.setSize(200, 200);

    table.addListener(SWT.Selection, new Listener() {

        public void handleEvent(Event event) {

            if (event.detail == SWT.CHECK) {

                TableItem item = (TableItem) event.item;

                System.out.println(

                   item + " checked " + item.getChecked());

            }

        }

    });

    shell.pack();

    shell.open();

    while (!shell.isDisposed()) {

        if (!display.readAndDispatch()) display.sleep();

    }

    display.dispose();

}


9.2.31 TableColumn Events

SWT.Selection (SelectionEvent)

The SWT.Selection event (typed event SelectionEvent) is sent whenever the user selects a column header with the mouse or the keyboard. Selection events contain meaningful values in only the display, widget, and type fields.

Using SWT.Selection to Sort Items in a Table

Sorting items in a table using a table column selection to initiate the sort is a very common user interface metaphor. The following program creates a table with two columns of data. Each item of data is stored in the class MyData.






static class MyData {

    String string1, string2;

    public MyData(String string1, String string2) {

        this.string1 = string1;

        this.string2 = string2;

    }

}


When the table is created, the setData() method is used to associate instances of MyData with TableItem. The sort() method sorts data by column in either ascending or descending order. The first part of the method creates an array of MyData using getData() to retrieve instances of MyData from the items in the table. The column parameter indicates the column in the table that should be sorted. After the data has been sorted, it is assigned back to each table item, and the string for the item is updated.






static void sort(

    Table table,

    final int column,

    final boolean descend) {



    int count = table.getItemCount();

    MyData[] list = new MyData[count];

    for (int i = 0; i < count; i++) {

        Object data = table.getItem(i).getData();

        list[i] = (MyData) data;

    }

    Arrays.sort(list, new Comparator() {

        public int compare(Object a, Object b) {

            MyData d1 = (MyData) (descend ? b : a);

            MyData d2 = (MyData) (descend ? a : b);

            switch (column) {

                case 0 :

                   return d1.string1.compareTo(d2.string1);

                case 1 :

                   return d1.string2.compareTo(d2.string2);

            }

            return 0;

        }

    });

    for (int i = 0; i < list.length; i++) {

        TableItem item = table.getItem(i);

        item.setText(0, list[i].string1);

        item.setText(1, list[i].string2);

        item.setData(list[i]);

    }

}


The main program creates the table and two table columns. The current sorting order (ascending or descending) is stored as a boolean in each column using setData(). When a column is selected, the index of the column that was selected is computed and the sorting retrieved. Finally, the column is sorted by inverting the current sorting order.






static int ROWS = 10000;

public static void main(String[] args) {

    Display display = new Display();

    Shell shell = new Shell(display);

    final Table table = new Table(shell, SWT.BORDER);

    table.setHeaderVisible(true);

    for (int i = 0; i < 2; i++) {

        TableColumn column =

            new TableColumn(table, SWT.NONE);

        column.setText("Column " + i);

        column.setData(new Boolean(false));

    }

    Random r = new Random();

    table.setRedraw(false);

    for (int i = 0; i < ROWS; i++) {

        TableItem item = new TableItem(table, SWT.NULL);

        MyData data =

            new MyData(

                "A" + r.nextInt(1000),

                "B" + r.nextInt(1000));

        item.setText(0, data.string1);

        item.setText(1, data.string2);

        item.setData(data);

    }

    sort(table, 0, false);

    table.setRedraw(true);

    for (int i = 0; i < table.getColumnCount(); i++) {

        final TableColumn column = table.getColumn(i);

        column.pack();

        column.addListener(SWT.Selection, new Listener() {

            public void handleEvent(Event event) {

                int index = table.indexOf(column);

                if (index != -1) {

                    Boolean b = (Boolean) column.getData();

                    boolean value = b.booleanValue();

                    sort(table, index, !value);

                    column.setData(new Boolean(!value));

                }

            }

        });

    }

    table.setSize(200, 200);

    shell.pack();

    shell.open();

    while (!shell.isDisposed()) {

        if (!display.readAndDispatch()) display.sleep();

    }

    display.dispose();

}


SWT.DefaultSelection (SelectionEvent)

The SWT.DefaultSelection event (typed event SelectionEvent) is sent whenever the user performs the platform-specific operation that indicates default selection. On most platforms, default selection occurs when the user double-clicks on a column header. Default selection events contain meaningful values in only the display, widget, and type fields.

SWT.Move (ControlEvent)

The SWT.Move event (typed event MoveEvent) is sent whenever a column is moved. Move events contain meaningful values in only the display, widget, and type fields.

SWT.Resize (ControlEvent)

The SWT.Resize event (typed event ControlEvent) is sent whenever a column is resized. Resize events contain meaningful values in only the display, widget, and type fields.

    Previous Section  < Day Day Up >  Next Section