第19章 表格
19.1 表格和滚动
例19-1 表格和滚动窗格
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Test extends JFrame {
public Test() {
Container contentPane = getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(new JTable(10,10));
contentPane.add(new JScrollPane(new JTable(10,10)));
}
public static void main(String args[]) {
GraphicJavaWindowHandler.launch(new Test(),
"Tables and Scrollpanes",100,100,850,700);
}
}
class GraphicJavaWindowHandler extends WindowAdapter {
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
}
19.2 表格模型
19.2.1 表格数据模型
19.2.2 TableModel接口
19.2.3 AbstractTableModel
例19-2 AbstractTableModel的一个简单扩展
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import java.util.*;
public class Test extends JFrame {
JTable table = new JTable(
new AbstractTableModel() {
int rows = 100, cols = 10;
public int getRowCount() { return rows; }
public int getColumnCount() { return cols; }
public Object getValueAt(int row, int col) {
return "(" + row + "," + col + ")";
}
});
public Test() {
getContentPane().add(new JScrollPane(table),
BorderLayout.CENTER);
}
public static void main(String args[]) {
GJApp.launch(
new Test(), "A Simple Model",300,300,450,300);
}
}
class GJApp extends WindowAdapter {
static private JPanel statusArea = new JPanel();
static private JLabel status = new JLabel(" ");
static private ResourceBundle resources;
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
launch(f,title,x,y,w,h,null);
}
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h,
String propertiesFilename) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
statusArea.setBorder(BorderFactory.createEtchedBorder());
statusArea.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
statusArea.add(status);
status.setHorizontalAlignment(JLabel.LEFT);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
if(propertiesFilename != null) {
resources = ResourceBundle.getBundle(
propertiesFilename, Locale.getDefault());
}
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
static public JPanel getStatusArea() {
return statusArea;
}
static public void showStatus(String s) {
status.setText(s);
}
static Object getResource(String key) {
if(resources != null) {
return resources.getString(key);
}
return null;
}
}
19.2.4 DefaultTableModel
例19-3 使用DefaultTableModel
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import java.util.*;
public class Test extends JFrame {
private int rows=3, cols=5;
private Object[] rowData = new Object[cols];
private DefaultTableModel model = new DefaultTableModel();
private JTable table = new JTable(model);
public Test() {
for(int c=0; c < cols; ++c)
model.addColumn("Column " + Integer.toString(c));
for(int r=0; r < rows; ++r) {
for(int c=0; c < cols; ++c) {
rowData[c] = "(" + r + "," + c + ")";
}
model.addRow(rowData);
}
getContentPane().add(new JScrollPane(table),
BorderLayout.CENTER);
getContentPane().add(new ControlPanel(),
BorderLayout.NORTH);
}
public static void main(String args[]) {
GJApp.launch(new Test(),
"Using DefaultTableModel",150,150,600,350);
}
class ControlPanel extends JPanel {
private JButton rowButton = new JButton("Add Row"),
colButton = new JButton("Add Column");
public ControlPanel() {
add(rowButton);
add(colButton);
rowButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int rowCount = model.getRowCount();
int colCount = model.getColumnCount();
if(colCount > rowData.length)
rowData = new Object[colCount];
for(int c=0; c < colCount; ++c) {
rowData[c] = "(" + rowCount + "," +
c + ")";
}
model.addRow(rowData);
}
});
colButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int colCount = model.getColumnCount();
model.addColumn("Column " + colCount);
// Bug: the call to sizeColumnsToFit()
// should not be necessary
table.sizeColumnsToFit(-1);
}
});
}
}
}
class GJApp extends WindowAdapter {
static private JPanel statusArea = new JPanel();
static private JLabel status = new JLabel(" ");
static private ResourceBundle resources;
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
launch(f,title,x,y,w,h,null);
}
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h,
String propertiesFilename) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
statusArea.setBorder(BorderFactory.createEtchedBorder());
statusArea.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
statusArea.add(status);
status.setHorizontalAlignment(JLabel.LEFT);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
if(propertiesFilename != null) {
resources = ResourceBundle.getBundle(
propertiesFilename, Locale.getDefault());
}
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
static public JPanel getStatusArea() {
return statusArea;
}
static public void showStatus(String s) {
status.setText(s);
}
static Object getResource(String key) {
if(resources != null) {
return resources.getString(key);
}
return null;
}
}
19.2.5 表格模型、缺省绘制器和缺省编辑器
例19-4 使用缺省绘制器和编辑器
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
public class Test extends JFrame {
String[] columnNames = {
"Name", "Check-In Date", "Check-Out Date", "Smoking",
"Fax", "Laptop", "Room Rate", "Photo",
};
Date dayOne = (new GregorianCalendar(2000, 10, 5)).getTime();
Date dayTwo = (new GregorianCalendar(2000, 10, 7)).getTime();
Object[][] data = {
{ "Andrews", dayOne, dayTwo,
new Boolean(true), new Boolean(true),
new Boolean(true), new Double(79.99),
new ImageIcon("tenchi.jpg")},
{ "Anthony", dayOne, dayTwo,
new Boolean(false), new Boolean(false),
new Boolean(false), new Double(69.99),
new ImageIcon("washu.jpg")},
{ "Woodard", dayOne, dayTwo,
new Boolean(true), new Boolean(false),
new Boolean(false), new Double(99.99),
new ImageIcon("sasami.jpg")},
{ "Thomas", dayOne, dayTwo,
new Boolean(false), new Boolean(true),
new Boolean(true), new Double(79.99),
new ImageIcon("aeka.jpg")},
{ "Reed", dayOne, dayTwo,
new Boolean(true), new Boolean(true),
new Boolean(true), new Double(79.99),
new ImageIcon("tenchi.jpg")},
{ "Crenshaw", dayOne, dayTwo,
new Boolean(false), new Boolean(false),
new Boolean(false), new Double(69.99),
new ImageIcon("washu.jpg")},
{ "Royal", dayOne, dayTwo,
new Boolean(true), new Boolean(false),
new Boolean(false), new Double(99.99),
new ImageIcon("sasami.jpg")},
{ "Moore", dayOne, dayTwo,
new Boolean(false), new Boolean(true),
new Boolean(true), new Double(79.99),
new ImageIcon("aeka.jpg")},
};
JTable table = new JTable(new CustomModel(data, columnNames));
public Test() {
getContentPane().add(new JScrollPane(table),
BorderLayout.CENTER);
}
public static void main(String args[]) {
GJApp.launch(
new Test(),
"A Custom Table Model That Specifies Column Classes",
300,300,650,182);
}
}
class CustomModel extends DefaultTableModel {
public CustomModel(Object[][] data, Object[] columnNames) {
super(data, columnNames);
}
public Class getColumnClass(int col) {
// dataVector is a protected member of DefaultTableModel
Vector v = (Vector)dataVector.elementAt(0);
return v.elementAt(col).getClass();
}
public boolean isCellEditable(int row, int col) {
Class columnClass = getColumnClass(col);
return columnClass != ImageIcon.class &&
columnClass != Date.class;
}
}
class GJApp extends WindowAdapter {
static private JPanel statusArea = new JPanel();
static private JLabel status = new JLabel(" ");
static private ResourceBundle resources;
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
launch(f,title,x,y,w,h,null);
}
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h,
String propertiesFilename) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
statusArea.setBorder(BorderFactory.createEtchedBorder());
statusArea.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
statusArea.add(status);
status.setHorizontalAlignment(JLabel.LEFT);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
if(propertiesFilename != null) {
resources = ResourceBundle.getBundle(
propertiesFilename, Locale.getDefault());
}
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
static public JPanel getStatusArea() {
return statusArea;
}
static public void showStatus(String s) {
status.setText(s);
}
static Object getResource(String key) {
if(resources != null) {
return resources.getString(key);
}
return null;
}
}
19.3 表格列
19.3.1 列调整大小模式
例19-5 JTable调整大小模式
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class Test extends JFrame {
Object[] resizeModes = new Object[] {
"JTable.AUTO_RESIZE_OFF",
"JTable.AUTO_RESIZE_NEXT_COLUMN",
"JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS",
"JTable.AUTO_RESIZE_LAST_COLUMN",
"JTable.AUTO_RESIZE_ALL_COLUMNS",
};
int[] resizeConstants = {
JTable.AUTO_RESIZE_OFF,
JTable.AUTO_RESIZE_NEXT_COLUMN,
JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS,
JTable.AUTO_RESIZE_LAST_COLUMN,
JTable.AUTO_RESIZE_ALL_COLUMNS,
};
JTable table = new JTable(6,5);
public Test() {
Container contentPane = getContentPane();
contentPane.add(new ControlPanel(), BorderLayout.NORTH);
contentPane.add(new JScrollPane(table),
BorderLayout.CENTER);
}
class ControlPanel extends JPanel {
JComboBox resizeModeCombo = new JComboBox(resizeModes);
public ControlPanel() {
initializeCombo();
setBorder(BorderFactory.createTitledBorder(
"Resize Mode"));
setLayout(new FlowLayout(FlowLayout.LEFT,2,2));
add(resizeModeCombo);
resizeModeCombo.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
int index =
resizeModeCombo.getSelectedIndex();
table.setAutoResizeMode(
resizeConstants[index]);
}
});
}
private void initializeCombo() {
int resizeMode = table.getAutoResizeMode();
if(resizeMode == JTable.AUTO_RESIZE_OFF)
resizeModeCombo.setSelectedIndex(0);
else if(resizeMode == JTable.AUTO_RESIZE_NEXT_COLUMN)
resizeModeCombo.setSelectedIndex(1);
else if(resizeMode == JTable.AUTO_RESIZE_LAST_COLUMN)
resizeModeCombo.setSelectedIndex(2);
else if(resizeMode == JTable.AUTO_RESIZE_ALL_COLUMNS)
resizeModeCombo.setSelectedIndex(3);
else if(
resizeMode == JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS)
resizeModeCombo.setSelectedIndex(4);
}
}
public static void main(String args[]) {
GJApp.launch(
new Test(), "JTable Resize Modes", 300,300,425,210);
}
}
class GJApp extends WindowAdapter {
static private JPanel statusArea = new JPanel();
static private JLabel status = new JLabel(" ");
static private ResourceBundle resources;
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
launch(f,title,x,y,w,h,null);
}
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h,
String propertiesFilename) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
statusArea.setBorder(BorderFactory.createEtchedBorder());
statusArea.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
statusArea.add(status);
status.setHorizontalAlignment(JLabel.LEFT);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
if(propertiesFilename != null) {
resources = ResourceBundle.getBundle(
propertiesFilename, Locale.getDefault());
}
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
static public JPanel getStatusArea() {
return statusArea;
}
static public void showStatus(String s) {
status.setText(s);
}
static Object getResource(String key) {
if(resources != null) {
return resources.getString(key);
}
return null;
}
}
19.3.2 列宽度
例19-6 指定列宽度
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import java.util.*;
public class Test extends JFrame {
Object[] columnNames =
{"First Name", "MI", "Last Name"};
Object[][] names = {
{ "Lynn", "M.", "Seckinger" },
{ "Carol", "R.", "Seckinger" },
{ "Roy", "D.", "Martin" },
{ "Bill", "O.", "Veryveryveryverylonglastname" },
{ "Richard", "A.", "Tattersall" },
{ "Philip", "B.", "Edwards" },
{ "Moore", "T.", "Moore" },
// shorten scrollbar grip with these ...
{ "Lynn", "M.", "Seckinger" },
{ "Carol", "R.", "Seckinger" },
{ "Roy", "D.", "Martin" },
{ "Bill", "O.", "Veryveryveryverylonglastname" },
{ "Richard", "A.", "Tattersall" },
{ "Philip", "B.", "Edwards" },
{ "Moore", "T.", "Moore" },
};
JTable table = new JTable(names, columnNames);
public Test() {
TableColumn mid = table.getColumn(columnNames[1]);
TableColumn last = table.getColumn(columnNames[2]);
int midWidth = getPreferredWidthForColumn(mid),
lastWidth = getPreferredWidthForColumn(last);
mid.setMinWidth(midWidth);
mid.setMaxWidth(midWidth);
last.setMinWidth(lastWidth);
// sizeColumnsToFit() must be called due to a JTable
// bug ...
table.sizeColumnsToFit(0);
getContentPane().add(new JScrollPane(table),
BorderLayout.CENTER);
}
public int getPreferredWidthForColumn(TableColumn col) {
int hw = columnHeaderWidth(col), // hw = header width
cw = widestCellInColumn(col); // cw = column width
return hw > cw ? hw : cw;
}
private int columnHeaderWidth(TableColumn col) {
TableCellRenderer renderer = col.getHeaderRenderer();
Component comp = renderer.getTableCellRendererComponent(
table, col.getHeaderValue(),
false, false, 0, 0);
return comp.getPreferredSize().width;
}
private int widestCellInColumn(TableColumn col) {
int c = col.getModelIndex(), width=0, maxw=0;
for(int r=0; r < table.getRowCount(); ++r) {
TableCellRenderer renderer =
table.getCellRenderer(r,c);
Component comp =
renderer.getTableCellRendererComponent(
table, table.getValueAt(r,c),
false, false, r, c);
width = comp.getPreferredSize().width;
maxw = width > maxw ? width : maxw;
}
return maxw;
}
public static void main(String args[]) {
GJApp.launch(
new Test(),"Setting Column Widths",300,300,320,140);
}
}
class GJApp extends WindowAdapter {
static private JPanel statusArea = new JPanel();
static private JLabel status = new JLabel(" ");
static private ResourceBundle resources;
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
launch(f,title,x,y,w,h,null);
}
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h,
String propertiesFilename) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
statusArea.setBorder(BorderFactory.createEtchedBorder());
statusArea.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
statusArea.add(status);
status.setHorizontalAlignment(JLabel.LEFT);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
if(propertiesFilename != null) {
resources = ResourceBundle.getBundle(
propertiesFilename, Locale.getDefault());
}
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
static public JPanel getStatusArea() {
return statusArea;
}
static public void showStatus(String s) {
status.setText(s);
}
static Object getResource(String key) {
if(resources != null) {
return resources.getString(key);
}
return null;
}
}
19.4 表格列模型
19.4.1 DefaultTableColumnModel类
19.4.2 列边距
例19-7 设置列边距
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import java.util.*;
public class Test extends JFrame {
JTable table = new JTable(
new AbstractTableModel() {
public int getRowCount() { return 10; }
public int getColumnCount() { return 10; }
public Object getValueAt(int row, int col) {
return "(" + Integer.toString(row) + "," +
Integer.toString(col) + ")";
}
});
public Test() {
Container cp = getContentPane();
cp.add(new JScrollPane(table), BorderLayout.CENTER);
cp.add(new ControlPanel(), BorderLayout.NORTH);
}
class ControlPanel extends JPanel {
private JSlider slider = new JSlider(
JSlider.HORIZONTAL,0,100,
table.getColumnModel().getColumnMargin());
private JLabel label = new JLabel();
public ControlPanel() {
add(new JLabel("Column Margin:"));
add(slider);
add(label);
label.setText(
Integer.toString(
table.getColumnModel().getColumnMargin()));
slider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
table.getColumnModel().setColumnMargin(
slider.getValue());
}
});
table.getColumnModel().addColumnModelListener(
new TableColumnModelListener() {
public void columnMarginChanged(ChangeEvent e) {
TableColumnModel m = table.getColumnModel();
label.setText(
Integer.toString(m.getColumnMargin()));
}
// unfortunately, Swing does not have many
// event adapter classes ...
public void columnAdded(TableColumnModelEvent e) {
}
public void columnMoved(TableColumnModelEvent e) {
}
public void columnRemoved(
TableColumnModelEvent e) {
}
public void columnSelectionChanged(
ListSelectionEvent e) {
}
});
}
}
public static void main(String args[]) {
GJApp.launch(new Test(),
"Column Margins",150,150,500,200);
}
}
class GJApp extends WindowAdapter {
static private JPanel statusArea = new JPanel();
static private JLabel status = new JLabel(" ");
static private ResourceBundle resources;
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
launch(f,title,x,y,w,h,null);
}
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h,
String propertiesFilename) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
statusArea.setBorder(BorderFactory.createEtchedBorder());
statusArea.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
statusArea.add(status);
status.setHorizontalAlignment(JLabel.LEFT);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
if(propertiesFilename != null) {
resources = ResourceBundle.getBundle(
propertiesFilename, Locale.getDefault());
}
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
static public JPanel getStatusArea() {
return statusArea;
}
static public void showStatus(String s) {
status.setText(s);
}
static Object getResource(String key) {
if(resources != null) {
return resources.getString(key);
}
return null;
}
}
19.4.3 隐藏列
例19-8 添加和删除列
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class Test extends JFrame {
JTable table = new JTable(
new Object[][] {
{"Mouse", "Mighty", "M." },
{"Mouse", "Polly", "A." },
{"Doright", "Dudley", "L." }
},
new Object[] {
"Last Name", "First Name", "Middle Initial"
}
);
public Test() {
Container cp = getContentPane();
cp.add(new JScrollPane(table), BorderLayout.CENTER);
cp.add(new ControlPanel(), BorderLayout.NORTH);
}
class ControlPanel extends JPanel {
private JCheckBox checkBox = new JCheckBox(
"First Name Column Showing");
public ControlPanel() {
final TableColumnModel tcm = table.getColumnModel();
final TableColumn firstNameColumn =
table.getColumn("First Name");
checkBox.setSelected(true);
add(checkBox);
checkBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
if(checkBox.isSelected()) {
tcm.addColumn(firstNameColumn);
tcm.moveColumn(2,1);
}
else {
tcm.removeColumn(firstNameColumn);
}
table.sizeColumnsToFit(-1);
}
});
}
}
public static void main(String args[]) {
GJApp.launch(
new Test(), "Showing/Hiding Columns",300,300,450,175);
}
}
class GJApp extends WindowAdapter {
static private JPanel statusArea = new JPanel();
static private JLabel status = new JLabel(" ");
static private ResourceBundle resources;
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
launch(f,title,x,y,w,h,null);
}
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h,
String propertiesFilename) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
statusArea.setBorder(BorderFactory.createEtchedBorder());
statusArea.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
statusArea.add(status);
status.setHorizontalAlignment(JLabel.LEFT);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
if(propertiesFilename != null) {
resources = ResourceBundle.getBundle(
propertiesFilename, Locale.getDefault());
}
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
static public JPanel getStatusArea() {
return statusArea;
}
static public void showStatus(String s) {
status.setText(s);
}
static Object getResource(String key) {
if(resources != null) {
return resources.getString(key);
}
return null;
}
}
19.4.4 锁定左边列
例19-9 锁定表格的左列
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class Test extends JFrame {
Object[][] listings = new Object[][] {
{ "28 Pickelodan", "Mork and Mindy", "Dukes of Hazard",
"I Love Lucy", "Andy Griffith", "Mission Impossible" },
{ "29 Dizey", "Rulan", "<-- Mulan", "<-- Mulan",
"<-- Mulan", "<-- Mulan" },
{ "31 NBT", "Nightly News", "40/20",
"<-- 40/20", "LimeTime", "<-- LimeTime" },
{ "32 AnimalUniverse", "Amazing Animals","Animal Rescues",
"Cute Animals", "Killer Animals",
"Big and Small Animals" },
{ "34 DSPN", "Tuesday Night FootBall",
"<--Tuesday Night FootBall", "<--Tuesday Night FootBall",
"<--Tuesday Night FootBall", "<--Tuesday Night FootBall"},
{ "37 TLC", "Mind Mysteries", "Our World",
"Ancient Wonders", "UFOs", "Ancient Inventions" },
{ "38 THC", "The Civil War", "Stalin",
"Watergate", "Kent State", "WWII" },
};
Object[] columnNames = new Object[] {
"Channel", "7:30", "8:00", "8:30", "9:00", "9:30"
};
TableModel sharedModel = new DefaultTableModel(
listings, columnNames);
JTable table = new JTable(sharedModel),
headerTable = new JTable(sharedModel);
TableColumnModel tcm = table.getColumnModel();
TableColumn firstColumn = tcm.getColumn(0);
public Test() {
Container cp = getContentPane();
setActualPreferredColumnWidths(table);
setActualPreferredColumnWidths(headerTable);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
headerTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
headerTable.getTableHeader().setReorderingAllowed(false);
headerTable.setPreferredScrollableViewportSize(
new Dimension(
firstColumn.getPreferredWidth() +
headerTable.getColumnModel().getColumnMargin(),
0));
cp.add(new ControlPanel(), BorderLayout.NORTH);
cp.add(new JScrollPane(table), BorderLayout.CENTER);
}
class ControlPanel extends JPanel {
JCheckBox checkBox = new JCheckBox("First Column Locked");
public ControlPanel() {
add(checkBox);
checkBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JScrollPane scrollPane = (JScrollPane)
SwingUtilities.getAncestorOfClass(
JScrollPane.class, table);
if(checkBox.isSelected()) {
tcm.removeColumn(firstColumn);
scrollPane.setRowHeaderView(headerTable);
scrollPane.setCorner(
JScrollPane.UPPER_LEFT_CORNER,
headerTable.getTableHeader());
}
else {
tcm.addColumn(firstColumn);
int numCols = tcm.getColumnCount();
tcm.moveColumn(numCols-1, 0);
scrollPane.setRowHeaderView(null);
}
}
});
}
}
public void setActualPreferredColumnWidths(JTable table) {
int columnCount = table.getColumnCount();
for(int i=0; i < columnCount; ++i) {
TableColumn c = table.getColumnModel().getColumn(i);
int w = getActualPreferredColumnWidth(c);
c.setPreferredWidth(w);
}
}
public int getActualPreferredColumnWidth(TableColumn col) {
int hw = columnHeaderWidth(col), // hw = header width
cw = widestCellInColumn(col); // cw = column width
return hw > cw ? hw : cw;
}
private int columnHeaderWidth(TableColumn col) {
TableCellRenderer renderer = col.getHeaderRenderer();
Component comp = renderer.getTableCellRendererComponent(
table, col.getHeaderValue(),
false, false, 0, 0);
return comp.getPreferredSize().width;
}
private int widestCellInColumn(TableColumn col) {
int c = col.getModelIndex(), width=0, maxw=0;
for(int r=0; r < table.getRowCount(); ++r) {
TableCellRenderer renderer =
table.getCellRenderer(r,c);
Component comp =
renderer.getTableCellRendererComponent(
table, table.getValueAt(r,c),
false, false, r, c);
width = comp.getPreferredSize().width;
maxw = width > maxw ? width : maxw;
}
return maxw;
}
public static void main(String args[]) {
GraphicJavaApplication.launch(
new Test(),"Locking the Left-Hand Column",
300,300,600,210);
}
}
class GraphicJavaApplication extends WindowAdapter {
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
}
19.5 表格选取
例19-10 表格选取
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
public class Test extends JFrame {
Object[] selectionModes = new Object[] {
"SINGLE_SELECTION",
"SINGLE_INTERVAL_SELECTION",
"MULTIPLE_INTERVAL_SELECTION",
};
int[] selectionConstants = {
ListSelectionModel.SINGLE_SELECTION,
ListSelectionModel.SINGLE_INTERVAL_SELECTION,
ListSelectionModel.MULTIPLE_INTERVAL_SELECTION,
};
JTable table = new JTable(10,10);
public Test() {
Container contentPane = getContentPane();
contentPane.add(new ControlPanel(), BorderLayout.NORTH);
contentPane.add(new JScrollPane(table),
BorderLayout.CENTER);
}
class ControlPanel extends JPanel {
JComboBox combo = new JComboBox(selectionModes);
public ControlPanel() {
setBorder(BorderFactory.createTitledBorder(
"Selection Modes"));
add(combo);
initializeCombo();
combo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int index = combo.getSelectedIndex();
table.setSelectionMode(
selectionConstants[index]);
}
});
}
private void initializeCombo() {
int mode =
table.getSelectionModel().getSelectionMode();
if(mode == ListSelectionModel.SINGLE_SELECTION) {
combo.setSelectedIndex(0);
}
else if(mode ==
ListSelectionModel.SINGLE_INTERVAL_SELECTION) {
combo.setSelectedIndex(1);
}
else if(mode ==
ListSelectionModel.MULTIPLE_INTERVAL_SELECTION) {
combo.setSelectedIndex(2);
}
}
}
public static void main(String args[]) {
GraphicJavaApplication.launch(
new Test(),"JTable Selection Modes",300,300,450,300);
}
}
class GraphicJavaApplication extends WindowAdapter {
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
}
19.6 绘制和编辑
19.6.1 使用表格单绘制器和编辑器
例19-11 StereoDeckModel类
import javax.swing.*;
import javax.swing.table.*;
class StereoDeckModel extends AbstractTableModel {
String[] columnNames = {
"In Use", "Manufacturer", "Model", "Price", "Dolby",
"Bass", "Volume"
};
Object[][] data = {
{ Boolean.FALSE, "Sony", "1501A",
new Double(129.99), Boolean.TRUE,
Boolean.TRUE, new Integer(50) },
{ Boolean.FALSE, "Phillips", "86A4",
new Double(159.99), Boolean.TRUE,
Boolean.FALSE, new Integer(35) },
{ Boolean.TRUE, "Kenwood", "33-801-A",
new Double(199.99), Boolean.FALSE,
Boolean.TRUE, new Integer(77) },
{ Boolean.FALSE, "Blaupunkt", "7622A",
new Double(229.99), Boolean.TRUE,
Boolean.FALSE, new Integer(19) },
{ Boolean.FALSE, "Akai", "9733",
new Double(259.99), Boolean.TRUE,
Boolean.FALSE, new Integer(68) },
{ Boolean.FALSE, "Sony", "1520B",
new Double(349.99), Boolean.FALSE,
Boolean.FALSE, new Integer(94) },
{ Boolean.FALSE, "Kenwood", "2289B",
new Double(499.99), Boolean.FALSE,
Boolean.FALSE, new Integer(44) },
};
public Object getValueAt(int row, int col) {
return data[row][col];
}
public int getRowCount() {
return data.length;
}
public int getColumnCount() {
return columnNames.length;
}
public String getColumnName(int col) {
return columnNames[col];
}
public Class getColumnClass(int col) {
return data[0][col].getClass();
}
public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
public boolean isCellEditable(int row, int col) {
Class cls = getColumnClass(col);
String name = getColumnName(col);
return (cls == Boolean.class && !name.equals("Dolby")) ||
cls == Integer.class || cls == Double.class;
}
public void updateBulbs(int selectedRow) {
for(int r=0; r < getRowCount(); ++r) {
data[r][0] = new Boolean(r == selectedRow);
}
}
}
例19-12 使用绘制器和编辑器
import java.awt.*;
import java.awt.event.*;
import java.text.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class Test extends JFrame {
JTable table = new JTable(new StereoDeckModel());
public Test() {
initializeInUseColumn();
initializePriceColumn();
initializeVolumeColumn();
sizeColumns();
table.setSelectionMode(
ListSelectionModel.SINGLE_SELECTION);
table.getSelectionModel().addListSelectionListener(
new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
StereoDeckModel model =
(StereoDeckModel)table.getModel();
if(!e.getValueIsAdjusting()) {
model.updateBulbs(table.getSelectedRow());
}
}
});
getContentPane().add(new JScrollPane(table),
BorderLayout.CENTER);
}
private void initializeInUseColumn() {
TableColumn inUseColumn = table.getColumn("In Use");
inUseColumn.setCellRenderer(new BulbRenderer());
inUseColumn.setCellEditor(new BulbEditor());
}
private void initializePriceColumn() {
TableColumn priceColumn = table.getColumn("Price");
JComboBox combo = new JComboBox();
// Combo box items are Numbers ...
combo.addItem(new Double(159.99));
combo.addItem(new Double(169.99));
combo.addItem(new Double(229.99));
combo.addItem(new Double(449.99));
combo.addItem(new Double(699.99));
combo.setRenderer(new ListCellCurrencyRenderer());
priceColumn.setCellRenderer(
new TableCellCurrencyRenderer());
priceColumn.setCellEditor(new PriceEditor(combo));
}
private void initializeVolumeColumn() {
TableColumn volumeColumn = table.getColumn("Volume");
TableCellRenderer renderer = new VolumeRenderer();
TableCellEditor editor = new VolumeEditor();
volumeColumn.setCellRenderer(renderer);
volumeColumn.setCellEditor(editor);
Dimension ps = ((JPanel)renderer).getPreferredSize();
table.setRowHeight(ps.height);
}
public static void main(String args[]) {
GraphicJavaApplication.launch(
new Test(), "Car Stereo Deck", 300,300,559,368);
}
private void sizeColumns() {
TableColumnModel tcm = table.getColumnModel();
for(int i=0; i < tcm.getColumnCount(); ++i) {
TableColumn column = tcm.getColumn(i);
int w = getPreferredWidthForColumn(column);
column.setMinWidth(w);
column.setMaxWidth(w);
}
}
public int getPreferredWidthForColumn(TableColumn col) {
int hw = columnHeaderWidth(col), // hw = header width
cw = widestCellInColumn(col); // cw = column width
return hw > cw ? hw+10 : cw+10;
}
private int columnHeaderWidth(TableColumn col) {
TableCellRenderer renderer = col.getHeaderRenderer();
Component comp = renderer.getTableCellRendererComponent(
table, col.getHeaderValue(),
false, false, 0, 0);
return comp.getPreferredSize().width;
}
private int widestCellInColumn(TableColumn col) {
int c = col.getModelIndex(), width=0, maxw=0;
for(int r=0; r < table.getRowCount(); ++r) {
TableCellRenderer renderer =
table.getCellRenderer(r,c);
Component comp =
renderer.getTableCellRendererComponent(
table, table.getValueAt(r,c),
false, false, r, c);
width = comp.getPreferredSize().width;
maxw = width > maxw ? width : maxw;
}
return maxw;
}
}
class ListCellCurrencyRenderer extends DefaultListCellRenderer {
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean hasFocus) {
JLabel c = (JLabel)
super.getListCellRendererComponent(
list, value, index,
isSelected, hasFocus);
Format format = NumberFormat.getCurrencyInstance();
c.setText(value == null ? "" : format.format(value));
return c;
}
}
class TableCellCurrencyRenderer extends DefaultTableCellRenderer {
public void setValue(Object value) {
Format format = NumberFormat.getCurrencyInstance();
super.setValue(value == null ? "" : format.format(value));
}
}
class GraphicJavaApplication extends WindowAdapter {
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
}
19.6.2 表格单绘制器
例19-13 VolumeRenderer
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
class VolumeRenderer extends JPanel
implements TableCellRenderer {
private JSlider slider = new JSlider();
private JLabel label = new JLabel("value");
public VolumeRenderer() {
slider.setOrientation(SwingConstants.HORIZONTAL);
slider.setPreferredSize(new Dimension(200,30));
slider.putClientProperty("JSlider.isFilled",Boolean.TRUE);
label.setHorizontalAlignment(JLabel.CENTER);
label.setHorizontalTextPosition(JLabel.CENTER);
setLayout(new BorderLayout());
add(label, BorderLayout.NORTH);
add(slider, BorderLayout.CENTER);
slider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
label.setText(
Integer.toString(slider.getValue()));
}
});
}
public Component getTableCellRendererComponent(
JTable table, Object value,
boolean isSelected,
boolean hasFocus,
int row, int col) {
Integer v = (Integer)value;
slider.setValue(v.intValue());
label.setText(v.toString());
slider.setEnabled(isSelected);
label.setEnabled(isSelected);
return this;
}
public JSlider getSlider() {
return slider;
}
public JLabel getLabel() {
return label;
}
}
19.6.3 Default Table Cell Renderer类
例19-14 BulbRenderer
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
class BulbRenderer extends DefaultTableCellRenderer {
private ImageIcon darkBulb = new ImageIcon("button.jpg"),
brightBulb = new ImageIcon("button_lit.jpg");
public BulbRenderer() {
setHorizontalAlignment(JLabel.CENTER);
}
public Component getTableCellRendererComponent(
JTable table, Object value,
boolean isSelected,
boolean hasFocus,
int row, int col) {
Boolean b = (Boolean)value;
setIcon(b.booleanValue() ? brightBulb : darkBulb);
return this;
}
}
19.6.4 表格格式化绘制器
19.6.5 单元编辑器
19.6.6 表格单编辑器
19.6.7 实现TableCellEditor接口
例19-15 AbstractCellEditor
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import javax.swing.tree.*;
import java.awt.event.MouseEvent;
import java.util.EventObject;
abstract public class AbstractCellEditor
implements TableCellEditor {
protected EventListenerList listenerList =
new EventListenerList();
protected Object value;
protected ChangeEvent changeEvent = null;
protected int clickCountToStart = 1;
public Object getCellEditorValue() {
return value;
}
public void setCellEditorValue(Object value) {
this.value = value;
}
public void setClickCountToStart(int count) {
clickCountToStart = count;
}
public int getClickCountToStart() {
return clickCountToStart;
}
public boolean isCellEditable(EventObject anEvent) {
if (anEvent instanceof MouseEvent) {
if (((MouseEvent)anEvent).getClickCount() <
clickCountToStart)
return false;
}
return true;
}
public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
public boolean stopCellEditing() {
fireEditingStopped();
return true;
}
public void cancelCellEditing() {
fireEditingCanceled();
}
public void addCellEditorListener(CellEditorListener l) {
listenerList.add(CellEditorListener.class, l);
}
public void removeCellEditorListener(CellEditorListener l) {
listenerList.remove(CellEditorListener.class, l);
}
protected void fireEditingStopped() {
Object[] listeners = listenerList.getListenerList();
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i] == CellEditorListener.class) {
if (changeEvent == null)
changeEvent = new ChangeEvent(this);
((CellEditorListener)
listeners[i+1]).editingStopped(changeEvent);
}
}
}
protected void fireEditingCanceled() {
Object[] listeners = listenerList.getListenerList();
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==CellEditorListener.class) {
if (changeEvent == null)
changeEvent = new ChangeEvent(this);
((CellEditorListener)
listeners[i+1]).editingCanceled(changeEvent);
}
}
}
}
例19-16 VolumeEditor
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import java.util.EventObject;
class VolumeEditor extends AbstractCellEditor {
VolumeRenderer renderer = new VolumeRenderer();
public VolumeEditor() {
renderer.getLabel().addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
if(e.getClickCount() == 2)
cancelCellEditing();
}
});
}
public Component getTableCellEditorComponent(
JTable table, Object value,
boolean isSelected,
int row, int column) {
JSlider slider = renderer.getSlider();
slider.setValue(((Integer)value).intValue());
return renderer;
}
public boolean stopCellEditing() {
JSlider slider = renderer.getSlider();
setCellEditorValue(new Integer(slider.getValue()));
return super.stopCellEditing();
}
}
例19-17 列出了PriceEdior类
import javax.swing.*;
import java.util.EventObject;
class PriceEditor extends DefaultCellEditor {
public PriceEditor(JComboBox combo) {
super(combo);
}
public boolean isCellEditable(EventObject e) {
JPanel messagePanel = new JPanel();
JPasswordField pwf = new JPasswordField(10);
System.out.println(e);
messagePanel.add(new JLabel("Password:"));
messagePanel.add(pwf);
JOptionPane.showMessageDialog(null,
messagePanel, "Password Required",
JOptionPane.INFORMATION_MESSAGE);
if(pwf.getText().equals("dolby")) {
return true;
}
else {
JOptionPane.showMessageDialog(null,
"Wrong Password!", "Access Failed",
JOptionPane.INFORMATION_MESSAGE);
return false;
}
}
}
19.7 表格行
19.7.1 行高
例19-18 计算和设置行高
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import java.util.*;
public class Test extends JFrame {
Object[] columnNames = {"Name", "Cost/Lb.", "Picture"};
Object[][] rowData = {
{ "cake", "$1.29", new ImageIcon("cake.gif") },
{ "pear", "$1.29", new ImageIcon("pear.gif") },
{ "pineapple", "$1.29", new ImageIcon("pineapple.gif") },
{ "apple", "$1.29", new ImageIcon("apple.gif") },
{ "bread", "$1.29", new ImageIcon("bread.gif") },
};
class RowSizingModel extends DefaultTableModel {
public RowSizingModel(Object[][] data,
Object[] colNames) {
super(data, colNames);
}
public Class getColumnClass(int c) {
if(c == 2) return ImageIcon.class;
else return super.getColumnClass(c);
}
}
JTable table = new JTable(new RowSizingModel(rowData,
columnNames));
public Test() {
table.setRowHeight(getMaxRowHeight());
getContentPane().add(new JScrollPane(table),
BorderLayout.CENTER);
}
public int getMaxRowHeight() {
int columnCount = table.getColumnCount(), h=0, maxh=0;
for(int i=0; i < columnCount; ++i) {
TableColumn column =
table.getColumnModel().getColumn(i);
h = getMaxRowHeightForColumn(column);
maxh = Math.max(h,maxh);
}
return maxh;
}
public int getMaxRowHeightForColumn(TableColumn column) {
int height = 0, maxh = 0, c = column.getModelIndex();
for(int r=0; r < table.getRowCount(); ++r) {
TableCellRenderer renderer =
table.getCellRenderer(r,c);
Component
comp = renderer.getTableCellRendererComponent(
table, table.getValueAt(r,c),
false, false, r, c);
height = comp.getMaximumSize().height;
maxh = height > maxh ? height : maxh;
}
return maxh;
}
public static void main(String args[]) {
GJApp.launch(
new Test(), "Sizing Rows", 300,300,450,300);
}
}
class GJApp extends WindowAdapter {
static private JPanel statusArea = new JPanel();
static private JLabel status = new JLabel(" ");
static private ResourceBundle resources;
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
launch(f,title,x,y,w,h,null);
}
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h,
String propertiesFilename) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
statusArea.setBorder(BorderFactory.createEtchedBorder());
statusArea.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
statusArea.add(status);
status.setHorizontalAlignment(JLabel.LEFT);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
if(propertiesFilename != null) {
resources = ResourceBundle.getBundle(
propertiesFilename, Locale.getDefault());
}
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
static public JPanel getStatusArea() {
return statusArea;
}
static public void showStatus(String s) {
status.setText(s);
}
static Object getResource(String key) {
if(resources != null) {
return resources.getString(key);
}
return null;
}
}
19.7.2 绘制行
例19-19 利用行和列进行绘制
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
public class Test extends JFrame {
JTable table = new JTable(
new AbstractTableModel() {
int rows = 100, cols = 10;
public int getRowCount() { return rows; }
public int getColumnCount() { return cols; }
public Object getValueAt(int row, int col) {
return "(" + Integer.toString(row) + "," +
Integer.toString(col) + ")";
}
});
public Test() {
TableColumn column;
int columnCount = table.getColumnCount();
for(int i=0; i < columnCount; ++i) {
column = table.getColumn(table.getColumnName(i));
if(i % 2 == 0)
column.setCellRenderer(new RowRenderer());
}
getContentPane().add(new JScrollPane(table),
BorderLayout.CENTER);
}
public static void main(String args[]) {
GraphicJavaApplication.launch(
new Test(), "Rendering By Columns and Rows",
300,300,450,300);
}
}
class RowRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected,
boolean hasFocus,
int row, int column) {
if(row % 2 == 0) setForeground(Color.blue);
else setForeground(Color.orange);
return super.getTableCellRendererComponent(table,
value, isSelected, hasFocus,
row, column);
}
}
class GraphicJavaApplication extends WindowAdapter {
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
}
19.8 表格装饰器
例19-20 一个绘制装饰器
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import java.util.*;
public class Test extends JFrame {
JTable table = new JTable(new Object[][] {
{"apple", "$.39"}, {"mango", "$.49"},
{"papaya", "$1.19"}, {"lemon", "$.19"},
{"orange", "$.59"}, {"watermelon", "$.39"},
{"tangerine", "$1.09"}, {"cherry", "$.79"},
{"banana", "$.29"}, {"lime", "$.33"},
{"grapefruit", "$.69"}, {"grapes", "$.49"},
},
new Object[] { "Item", "Price/Lb." });
public Test() {
TableColumn column = table.getColumn("Price/Lb.");
TableCellRenderer renderer = column.getHeaderRenderer();
column.setHeaderRenderer(new RendererDecorator(renderer));
getContentPane().add(new JScrollPane(table),
BorderLayout.CENTER);
}
public static void main(String args[]) {
GJApp.launch(
new Test(), "A Renderer Decorator", 300,300,450,182);
}
}
class RendererDecorator implements TableCellRenderer {
TableCellRenderer realRenderer;
JPanel panel;
JLabel iconLabel = new JLabel(new ImageIcon("money.gif"));
public RendererDecorator(TableCellRenderer r) {
realRenderer = r;
iconLabel.setBorder(BorderFactory.createEtchedBorder());
}
public Component getTableCellRendererComponent(
JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int col) {
Component c = realRenderer.getTableCellRendererComponent(
table, value, isSelected,
hasFocus, row, col);
embellishComponent(c);
return panel;
}
private void embellishComponent(Component c) {
if(panel == null) {
panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(c, BorderLayout.CENTER);
panel.add(iconLabel, BorderLayout.WEST);
}
}
}
class GJApp extends WindowAdapter {
static private JPanel statusArea = new JPanel();
static private JLabel status = new JLabel(" ");
static private ResourceBundle resources;
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
launch(f,title,x,y,w,h,null);
}
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h,
String propertiesFilename) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
statusArea.setBorder(BorderFactory.createEtchedBorder());
statusArea.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
statusArea.add(status);
status.setHorizontalAlignment(JLabel.LEFT);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
if(propertiesFilename != null) {
resources = ResourceBundle.getBundle(
propertiesFilename, Locale.getDefault());
}
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
static public JPanel getStatusArea() {
return statusArea;
}
static public void showStatus(String s) {
status.setText(s);
}
static Object getResource(String key) {
if(resources != null) {
return resources.getString(key);
}
return null;
}
}
例19-21 利用装饰器排序
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class Test extends JFrame {
JTable table = new JTable(new Object[][] {
{"apple", "$.39"}, {"mango", "$.49"},
{"papaya", "$1.19"}, {"lemon", "$.19"},
{"orange", "$.59"}, {"watermelon", "$.39"},
{"tangerine", "$1.09"}, {"cherry", "$.79"},
{"banana", "$.29"}, {"lime", "$.33"},
{"grapefruit", "$.69"}, {"grapes", "$.49"},
},
new Object[] { "Item", "Price/Lb." });
public Test() {
final SortDecorator decorator =
new SortDecorator(table.getModel());
table.setModel(decorator);
JTableHeader hdr = (JTableHeader)table.getTableHeader();
hdr.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
TableColumnModel tcm = table.getColumnModel();
int vc = tcm.getColumnIndexAtX(e.getX());
int mc = table.convertColumnIndexToModel(vc);
decorator.sort(mc);
//table.repaint();
}
});
getContentPane().add(new JScrollPane(table),
BorderLayout.CENTER);
}
public static void main(String args[]) {
GJApp.launch(
new Test(),"A Sort Decorator",300,300,450,250);
}
}
class SortDecorator implements TableModel, TableModelListener {
private TableModel realModel;
private int indexes[];
public SortDecorator(TableModel model) {
if(model == null)
throw new IllegalArgumentException(
"null models are not allowed");
this.realModel = model;
realModel.addTableModelListener(this);
allocate();
}
public Object getValueAt(int row, int column) {
return realModel.getValueAt(indexes[row], column);
}
public void setValueAt(Object aValue, int row, int column) {
realModel.setValueAt(aValue, indexes[row], column);
}
public void tableChanged(TableModelEvent e) {
allocate();
}
public void sort(int column) {
int rowCount = getRowCount();
for(int i=0; i < rowCount; i++) {
for(int j = i+1; j < rowCount; j++) {
if(compare(indexes[i], indexes[j], column) < 0) {
swap(i,j);
}
}
}
}
public void swap(int i, int j) {
int tmp = indexes[i];
indexes[i] = indexes[j];
indexes[j] = tmp;
}
public int compare(int i, int j, int column) {
Object io = realModel.getValueAt(i,column);
Object jo = realModel.getValueAt(j,column);
int c = jo.toString().compareTo(io.toString());
return (c < 0) ? -1 : ((c > 0) ? 1 : 0);
}
private void allocate() {
indexes = new int[getRowCount()];
for(int i=0; i < indexes.length; ++i) {
indexes[i] = i;
}
}
// TableModel pass-through methods follow ...
public int getRowCount() {
return realModel.getRowCount();
}
public int getColumnCount() {
return realModel.getColumnCount();
}
public String getColumnName(int columnIndex) {
return realModel.getColumnName(columnIndex);
}
public Class getColumnClass(int columnIndex) {
return realModel.getColumnClass(columnIndex);
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
return realModel.isCellEditable(rowIndex, columnIndex);
}
public void addTableModelListener(TableModelListener l) {
realModel.addTableModelListener(l);
}
public void removeTableModelListener(TableModelListener l) {
realModel.removeTableModelListener(l);
}
}
class GJApp extends WindowAdapter {
static private JPanel statusArea = new JPanel();
static private JLabel status = new JLabel(" ");
static private ResourceBundle resources;
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
launch(f,title,x,y,w,h,null);
}
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h,
String propertiesFilename) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
statusArea.setBorder(BorderFactory.createEtchedBorder());
statusArea.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
statusArea.add(status);
status.setHorizontalAlignment(JLabel.LEFT);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
if(propertiesFilename != null) {
resources = ResourceBundle.getBundle(
propertiesFilename, Locale.getDefault());
}
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
static public JPanel getStatusArea() {
return statusArea;
}
static public void showStatus(String s) {
status.setText(s);
}
static Object getResource(String key) {
if(resources != null) {
return resources.getString(key);
}
return null;
}
}
19.9 表格头部
19.9.1 JTableHeader
19.9.2 列头部绘制器和头部工具提示
例19-22 一个多行表格列头部和头部工具提示
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class Test extends JFrame {
String longTitle = "Last Name / Maiden Name (if divorced)";
MultilineHeaderRenderer multilineRenderer =
new MultilineHeaderRenderer(longTitle);
JTable table = new JTable(
new Object[][] {
{ "Lynn", "M.", "Seckinger" },
{ "Carol", "R.", "Seckinger" },
{ "Roy", "D.", "Martin" },
{ "Richard", "A.", "Tattersall" },
{ "Philip", "B.", "Edwards" },
{ "Moore", "T.", "Moore" },
// shorten scrollbar grip with these ...
{ "Lynn", "M.", "Seckinger" },
{ "Carol", "R.", "Seckinger" },
{ "Roy", "D.", "Martin" },
{ "Richard", "A.", "Tattersall" },
{ "Philip", "B.", "Edwards" },
{ "Moore", "T.", "Moore" },
},
new Object[] {"First Name", "MI", longTitle});
public Test() {
TableColumn middleColumn = table.getColumn("MI"),
lastColumn = table.getColumn(longTitle);
lastColumn.setHeaderRenderer(multilineRenderer);
TableCellRenderer hdrRenderer =
middleColumn.getHeaderRenderer();
Component hdrComponent =
hdrRenderer.getTableCellRendererComponent(table,
"MI", false, false, 0, 0);
if(hdrComponent instanceof JComponent) {
JComponent c = (JComponent)hdrComponent;
c.setToolTipText("Middle Initial");
}
table.getTableHeader().setToolTipText("Table Header!");
getContentPane().add(
new JScrollPane(table), BorderLayout.CENTER);
}
public static void main(String args[]) {
GJApp.launch(new Test(),
"Multi-Line Column Headers",300,300,300,250);
}
}
class MultilineHeaderRenderer implements TableCellRenderer {
MultilineHeader mll;
JScrollPane scrollPane;
public MultilineHeaderRenderer(String title) {
mll = new MultilineHeader(title);
scrollPane = new JScrollPane(mll);
scrollPane.setHorizontalScrollBarPolicy(
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setVerticalScrollBarPolicy(
JScrollPane.VERTICAL_SCROLLBAR_NEVER);
scrollPane.setBorder(null);
}
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row, int col) {
mll.setText((String)value);
return scrollPane;
}
}
class MultilineHeader extends JTextArea {
public MultilineHeader(String s) {
super(s);
}
public void updateUI() {
super.updateUI();
// turn on wrapping and disable editing and highlighting
setLineWrap(true);
setWrapStyleWord(true);
setHighlighter(null);
setEditable(false);
// make the text area look like a table header
LookAndFeel.installColorsAndFont(this,
"TableHeader.background",
"TableHeader.foreground",
"TableHeader.font");
LookAndFeel.installBorder(this, "TableHeader.cellBorder");
}
}
class GJApp extends WindowAdapter {
static private JPanel statusArea = new JPanel();
static private JLabel status = new JLabel(" ");
static private ResourceBundle resources;
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
launch(f,title,x,y,w,h,null);
}
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h,
String propertiesFilename) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
statusArea.setBorder(BorderFactory.createEtchedBorder());
statusArea.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
statusArea.add(status);
status.setHorizontalAlignment(JLabel.LEFT);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
if(propertiesFilename != null) {
resources = ResourceBundle.getBundle(
propertiesFilename, Locale.getDefault());
}
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
static public JPanel getStatusArea() {
return statusArea;
}
static public void showStatus(String s) {
status.setText(s);
}
static Object getResource(String key) {
if(resources != null) {
return resources.getString(key);
}
return null;
}
}
19.9.3 JTable属性
19.9.4 表格事件
19.9.5 表格模型事件
例19-23 表格模型事件处理
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
public class Test extends JFrame {
JTable table = new JTable(10,10);
public Test() {
Container contentPane = getContentPane();
contentPane.add(new JScrollPane(table),
BorderLayout.CENTER);
table.getModel().addTableModelListener(
new TableModelListener() {
public void tableChanged(TableModelEvent e) {
int firstRow = e.getFirstRow(),
column = e.getColumn();
String properties = " source=" + e.getSource() +
" firstRow= " +
(firstRow == TableModelEvent.HEADER_ROW ?
"HEADER_ROW" :
Integer.toString(firstRow)) +
" lastRow= " + e.getLastRow() +
" column= " +
(firstRow == TableModelEvent.ALL_COLUMNS ?
"ALL_COLUMNS" :
Integer.toString(column));
String typeString = new String();
int type = e.getType();
switch(type) {
case TableModelEvent.DELETE:
typeString = "DELETE"; break;
case TableModelEvent.INSERT:
typeString = "INSERT"; break;
case TableModelEvent.UPDATE:
typeString = "UPDATE"; break;
}
properties += " type=" + typeString;
JOptionPane.showMessageDialog(Test.this,
e.getClass().getName() +
"[" + properties + "]");
}
});
}
public static void main(String args[]) {
GraphicJavaApplication.launch(new Test(),
"Handling Table Model Events",300,300,450,220);
}
}
class GraphicJavaApplication extends WindowAdapter {
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
}
19.9.6 TableColumnModel事件
例19-24 列模型事件的处理
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
public class Test extends JApplet {
JTable table = new JTable(
new AbstractTableModel() {
int rows = 10, cols = 10;
public int getRowCount() { return rows; }
public int getColumnCount() { return cols; }
public Object getValueAt(int row, int col) {
return "(" + Integer.toString(row) + "," +
Integer.toString(col) + ")";
}
}
);
public void init() {
Container contentPane = getContentPane();
contentPane.add(new JScrollPane(table),
BorderLayout.CENTER);
table.getColumnModel().addColumnModelListener(
new TableColumnModelListener() {
public void columnAdded(TableColumnModelEvent e) { }
public void columnMarginChanged(ChangeEvent e) { }
public void columnRemoved(TableColumnModelEvent e) { }
public void columnSelectionChanged(
ListSelectionEvent e) { }
public void columnMoved(TableColumnModelEvent e) {
String s = "Column Moved From " +
e.getFromIndex() + " To " +
e.getToIndex();
showStatus(s);
}
});
}
}
19.9.7 列表选取事件
例19-25 行选取事件的处理
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class Test extends JFrame {
JTable table = new JTable(10,10);
public Test() {
Container contentPane = getContentPane();
contentPane.add(new JScrollPane(table),
BorderLayout.CENTER);
table.getSelectionModel().addListSelectionListener(
new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if(e.getValueIsAdjusting()) {
System.out.println("Selection Model " +
"adjusting ...");
}
else {
System.out.println("Selection Model:" +
e.toString());
}
}
});
}
public static void main(String args[]) {
GJApp.launch(new Test(),
"Handling Row Selection",300,300,450,220);
}
}
class GJApp extends WindowAdapter {
static private JPanel statusArea = new JPanel();
static private JLabel status = new JLabel(" ");
static private ResourceBundle resources;
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h) {
launch(f,title,x,y,w,h,null);
}
public static void launch(final JFrame f, String title,
final int x, final int y,
final int w, int h,
String propertiesFilename) {
f.setTitle(title);
f.setBounds(x,y,w,h);
f.setVisible(true);
statusArea.setBorder(BorderFactory.createEtchedBorder());
statusArea.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
statusArea.add(status);
status.setHorizontalAlignment(JLabel.LEFT);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
if(propertiesFilename != null) {
resources = ResourceBundle.getBundle(
propertiesFilename, Locale.getDefault());
}
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
static public JPanel getStatusArea() {
return statusArea;
}
static public void showStatus(String s) {
status.setText(s);
}
static Object getResource(String key) {
if(resources != null) {
return resources.getString(key);
}
return null;
}
}
19.9.8 JTable类总结
19.9.9 AWT兼容
19.10 本章回顾
略