|
Bookshelf Index
Chapter 18, Tables
By Matthew Robinson and Pavel Vorobiev
Introduction |
Download Chapter 18| Download Chapter 22 << NEXT >>
Running the Code
Figure 18.6 shows StocksTable with data
retrieved from a database. Try loading data for different dates
in
your
database. A sample Microsoft Access database, market.mdb,
containing
some real
market data, can be found in the \swing\Chapter18
directory.
18.7 Stocks Table: Part VI - Column Addition and Removal
JTable allows us to dynamically add and remove
TableColumns on the fly.
Recall that the TableColumnModel
interface provides the methods addColumn()
and removeColumn() to
programmatically add or remove a TableColumn
respectively. In
this
section we add dynamic column
addition and removal to our StocksTable
application.

Click Figure 18.6 for full-scale image. JTable
with
dynamic
column addition and removal.
The Code: StocksTable.java
see \Chapter18\6
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import java.text.*;
import java.sql.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class StocksTable
extends JFrame
{
// Unchanged code from
//section 18.5
public StocksTable() {
// Unchanged code from section 18.5
header.setReorderingAllowed(true);
m_table.getColumnModel(
).addColumnModelListener(
m_data.new ColumnMovementListener());
// Unchanged code from section 18.5
}
protected JMenuBar createMenuBar() {
// Unchanged code from section 18.5
JMenu mView = new JMenu("View");
mView.setMnemonic('v');
TableColumnModel model =
m_table.getColumnModel();
for (int k = 0; k <
stocktabledata.m_columns.length;
k++) {
jcheckboxmenuitem item =
new jcheckboxmenuitem(
stocktabledata.m_columns[k].m_title);
item.setselected(true);
tablecolumn column =
model.getcolumn(k);
item.addactionlistener(
new columnkeeper(column,
stocktabledata.m_columns[k]));
mview.add(item);
}
menubar.add(mview);
return menubar;
}
// unchanged code from section 18.5
class columnkeeper
implements actionlistener
{
protected tablecolumn m_column;
protected columndata m_coldata;
public columnkeeper(tablecolumn
column, columndata coldata) {
m_column = column;
m_coldata = coldata;
}
public void
actionperformed(
actionevent e) {
jcheckboxmenuitem item =
(jcheckboxmenuitem)e.getsource();
tablecolumnmodel model =
m_table.getcolumnmodel();
if (item.isselected()) {
model.addcolumn(m_column);
}
else {
model.removecolumn(m_column);
}
m_table.tablechanged(new
tablemodelevent(m_data));
m_table.repaint();
}
}
public static void main(string argv[]) {
new stockstable();
}
}
// unchanged code from section 18.5
class stocktabledata
extends abstracttablemodel
{
// unchanged code from section 18.5
protected simpledateformat m_frm;
protected vector m_vector;
protected java.util.date m_date;
protected int m_columnscount =
m_columns.length;
// unchanged code from section 18.5
public int getcolumncount() {
return m_columnscount;
}
// unchanged code from section 18.5
class columnlistener
extends mouseadapter
{
// unchanged code from section 18.4
public void mouseclicked(mouseevent e) {
// unchanged code from section 18.4
for (int i=0; i <
m_columnscount; i++) {
tablecolumn column =
colmodel.getcolumn(i);
column.setheadervalue(
getcolumnname(column.getmodelindex()));
}
m_table.gettableheader().repaint();
// unchanged code from section 18.4
}
}
class columnmovementlistener
implements tablecolumnmodellistener
{
public void columnadded(
tablecolumnmodelevent e) {
m_columnscount++;
}
public void columnremoved(
tablecolumnmodelevent e) {
m_columnscount--;
}
public void columnmarginchanged(
changeevent e) {}
public void columnmoved(
tablecolumnmodelevent e) {}
public void columnselectionchanged(
listselectionevent e) {}
}
// unchanged code from section 18.5
}
// class stockcomparator
//unchanged from section 18.4
|
Understanding the Code
Class StocksTable
The StocksTable constructor now adds an instance of
StockTableData.ColumnMovementListener
(see below) to our table's TableColumnModel
to listen for column additions and removals.
Our createMenuBar() method now adds several checkbox
menu
items
to
a new View menu---one
for each column. Each of these check box menu items recieves a
ColumnKeeper
instance (see below) as ActionListener.
Class StocksTable.ColumnKeeper
This inner class implements the ActionListener
interface
and serves to keep track of when the user removes and adds
columns to
the
table. The constructor receives a TableColumn
instance
and a
ColumnData object. The
actionPerformed()
method adds
this column to the
model with the addColumn()
method if the corresponding menu item is checked, and removes
this
column from
the model with removeColumn()
if it is unchecked. To update the table to properly reflect these
changes, we
call its tableChanged()
method followed by a repaint()
request.
Class StockTableData
StockTableData now contains instance variable
m_columnsCount to keep
track of the current column count. This variable is decremented
and
incremented
in the columnRemoved()
and columnAdded()
methods of inner class ColumnMovementListener.
It is also used in the StockTableData.ColumnListener
class's mouseClicked()
method for properly setting header values for the visible columns
only.
Class StockTableData.ColumnMovementListener
This class implements TableColumnModelListener to
increment and decrement StockTableData's
m_columnsCount
variable when a column addition or removal occurs, respectively.
An
instance
of
this inner class is added to our table's
TableColumnModel
in the
StocksTable constructor.
Running the Code
Figure 18.7 shows the new View menu
with an unchecked Change % menu item, and the corresponding
column
hidden.
Reselecting this menu item will place the column back in the
table at
the end
position. Verify that each menu item functions similarly.
18.8 Custom
Models, Editors, and Renderers
In constructing our StocksTable application we
talked mostly about displaying and retrieving data in
JTable. In
this section we will construct a
basic expense report application, and in doing so we will
concentrate
on table
cell editing. We will also see how to implement dynamic addition
and
removal
of
table rows.
The editing of data generally follows
this scheme:
Create an
instance of
the
TableCellEditor interface. We can use
the DefaultCellEditor class or
implement our own. The DefaultCellEditor
class takes a GUI component as a parameter to its constructor:
JTextField, JCheckBox or
JComboBox.
This
component will be used for editing.
If we are
developing a
custom editor, we need to implement the
getTableCellEditorComponent()
method which will be called each time a cell is about to be
edited.
In our
table
model we
need to implement the setValueAt(Object value,
int nRow, int nCol) method which will be called to change
a
value in
the
table when an edit ends. This is where we can perform any
necessary
data
processing and validation.
The data model for this example is
designed as follows (where each row represents a column in our
JTable):
| Name |
Type |
Description |
| Date |
String |
Date of
expense |
| Amount |
Double |
Amount of expense |
| Category |
Integer |
Category from pre-defined
list |
| Approved |
Boolean |
Sign of approval for
this expense. |
| Description |
String |
Brief description |

Click Figure 18.7 for full-scale image.
An expense report app
illustrating custom cell editing, rendering, and row
addition/removal.
Note: Since
the only math that is done with our Amount values is addition,
using
Doubles is fine. However, in more
professional implementations we may need to use rounding
techniques or a custom renderer to remove unneccessary fractional amounts.
The Code:
ExpenseReport.java
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import java.text.SimpleDateFormat;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class ExpenseReport extends JFrame
{
protected JTable m_table;
protected ExpenseReportData m_data;
protected JLabel m_title;
public ExpenseReport() {
super("Expense Report");
setSize(570, 200);
m_data = new ExpenseReportData(this);
m_table = new JTable();
m_table.setAutoCreateColumnsFromModel(
false);
m_table.setModel(m_data);
m_table.setSelectionMode(
ListSelectionModel.
SINGLE_SELECTION);
for (int k = 0; k <
ExpenseReportData.
m_columns.length; k++) {
TableCellRenderer renderer;
if (k==ExpenseReportData.COL_APPROVED)
renderer = new CheckCellRenderer();
else {
DefaultTableCellRenderer textRenderer =
new DefaultTableCellRenderer();
textRenderer.setHorizontalAlignment(
ExpenseReportData.m_columns[
k].m_alignment);
renderer = textRenderer;
}
TableCellEditor editor;
if (k==ExpenseReportData.COL_CATEGORY)
editor = new DefaultCellEditor(
new JComboBox(
ExpenseReportData.CATEGORIES));
else if (k==ExpenseReportData.
COL_APPROVED)
editor = new DefaultCellEditor(
new JCheckBox());
else
editor = new DefaultCellEditor(
new JTextField());
TableColumn column = new TableColumn(k,
ExpenseReportData.m_columns[k].m_width,
renderer, editor);
m_table.addColumn(column);
}
JTableHeader header =
m_table.getTableHeader();
header.setUpdateTableInRealTime(false);
JScrollPane ps = new JScrollPane();
ps.setSize(550, 150);
ps.getViewport().add(m_table);
getContentPane().add(ps,
BorderLayout.CENTER);
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p,
BoxLayout.X_AXIS));
ImageIcon penny =
new ImageIcon("penny.gif");
m_title = new JLabel("Total: $",
penny, JButton.LEFT);
m_title.setForeground(Color.black);
m_title.setAlignmentY(0.5f);
p.add(m_title);
p.add(Box.createHorizontalGlue());
JButton bt = new JButton(
"Insert before");
bt.setMnemonic('b');
bt.setAlignmentY(0.5f);
ActionListener lst =
new ActionListener() {
public void actionPerformed(
ActionEvent e) {
int row = m_table.getSelectedRow();
m_data.insert(row);
m_table.tableChanged(
new TableModelEvent(
m_data, row, row,
TableModelEvent.ALL_COLUMNS,
TableModelEvent.INSERT));
m_table.repaint();
}
};
bt.addActionListener(lst);
p.add(bt);
bt = new JButton("Insert after");
bt.setMnemonic('a');
bt.setAlignmentY(0.5f);
lst = new ActionListener() {
public void actionPerformed(
ActionEvent e) {
int row = m_table.getSelectedRow();
m_data.insert(row+1);
m_table.tableChanged(new
TableModelEvent(
m_data, row+1, row+1,
TableModelEvent.ALL_COLUMNS,
TableModelEvent.INSERT));
m_table.repaint();
}
};
bt.addActionListener(lst);
p.add(bt);
bt = new JButton("Delete row");
bt.setMnemonic('d');
bt.setAlignmentY(0.5f);
lst = new ActionListener() {
public void actionPerformed(
ActionEvent e) {
int row = m_table.getSelectedRow();
if (m_data.delete(row)) {
m_table.tableChanged(new
TableModelEvent(
m_data, row, row,
TableModelEvent.ALL_COLUMNS,
TableModelEvent.INSERT));
m_table.repaint();
calcTotal();
}
}
};
bt.addActionListener(lst);
p.add(bt);
getContentPane().add(p,
BorderLayout.SOUTH);
calcTotal();
WindowListener wndCloser =
new WindowAdapter() {
public void windowClosing(
WindowEvent e) {
System.exit(0);
}
};
addWindowListener(wndCloser);
setVisible(true);
}
public void calcTotal() {
double total = 0;
for (int k=0; k=
m_vector.size())
return false;
m_vector.remove(row);
return true;
}
}
|
Page
1
2
3
4
5
6
7
8
9
10
11
<< NEXT >>
Download Chapter 18| Download Chapter 22]
|