一个JTable对应一个有一个TableModel来管理它的数据,Jtable需要放入一个JscrollPane中来正常显示,当然也可以只显示表格内容、或者只显示表头。
final GameListTable gameTable = new GameListTable();
GameListTableModel model = new GameListTableModel();
gameTable.setModel(model);
JScrollPane scrollPane = new JScrollPane(gameTable);
gbc.fill = GridBagConstraints.BOTH;
gbc.gridx = 0;
gbc.gridy = 1;
mContainer.add(scrollPane, gbc);
TableModel中管理表格中数据,当编辑表格时,会触发Model中的setValueAt方法,可以在这里触发数据库保存操作,当显示表格数据时,表格会逐行调用getValueAt方法将该方法返回值放入表格中。另外还有一些方法,如getRowCount确定表格显示多少行数据,getColumnName表格表头的名字,isCellEditable如果需要一个单元格无法编辑,则实现该方法,在指定的row和column时返回false。DefaultTableModel中已经实现了大部分的常用方法,例如removeRow和insertRow,其中使用dataVector这个变量保存表格每一行的值,具体可以参看jdk源码。
import java.util.Date;
import java.util.List;
import java.util.Vector;
import javax.swing.table.DefaultTableModel;
import com.aquar.game.database.Company;
import com.aquar.game.database.EnumGameType;
import com.aquar.game.database.Game;
import com.aquar.game.dataserver.DataHandler;
import com.aquar.game.ulti.Ultility;
public class GameListTableModel extends DefaultTableModel {
public static final int COL_NAME = 0;
public static final int COL_TYPE = COL_NAME + 1;
public static final int COL_DATE = COL_TYPE + 1;
public static final int COL_COMPANY = COL_DATE + 1;
public static final int COL_DATA = COL_COMPANY + 1;
// not edit the cell by default
private boolean editable = false;
public GameListTableModel() {
initColNames();
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public void initData(List<Game> gameList) {
dataVector.clear();
if (gameList != null) {
for (Game game : gameList) {
Vector rowVector = new Vector();
rowVector.add(COL_NAME, game.getName());
rowVector.add(COL_TYPE, game.getType());
rowVector.add(COL_DATE, game.getReleaseDate());
rowVector.add(COL_COMPANY, game.getCompany());
rowVector.add(COL_DATA, game);
dataVector.add(rowVector);
}
}
fireTableDataChanged();
}
@SuppressWarnings("unchecked")
private void initColNames() {
columnIdentifiers.add("Name");
columnIdentifiers.add("Type");
columnIdentifiers.add("Date");
columnIdentifiers.add("Company");
}
@Override
public int getRowCount() {
return super.getRowCount();
}
@Override
public Object getValueAt(int row, int column) {
Object ret = "";
Vector rowVector = (Vector) dataVector.elementAt(row);
Object data = rowVector.elementAt(column);
if (data != null) {
if (COL_TYPE == column) {
int type = (int) data;
ret = EnumGameType.getEnum(type);
} else if (COL_DATE == column) {
ret = Ultility.getDateStr((Date) data);
} else {
ret = data;
}
} else {
}
return ret;
}
@Override
public void setValueAt(Object aValue, int row, int column) {
Object oldValue = getValueAt(row, column);
// not change anything.
if (oldValue != null && oldValue.equals(aValue)) {
return ;
}
// Get the Object of line.
Vector rowVector = (Vector) dataVector.elementAt(row);
Game game = (Game) rowVector.elementAt(COL_DATA);
switch (column) {
case COL_NAME:
game.setName(aValue.toString().trim());
break;
case COL_TYPE:
if (aValue instanceof EnumGameType) {
EnumGameType type = (EnumGameType) aValue;
game.setType(type.ordinal());
}
break;
case COL_DATE:
if (aValue instanceof Date) {
game.setReleaseDate((Date) aValue);
}
break;
case COL_COMPANY:
if (aValue instanceof Company) {
Company company = (Company) aValue;
game.setCompany(company);
}
break;
default:
break;
}
DataHandler.getInstance().save(game);
}
@Override
public boolean isCellEditable(int row, int column) {
boolean ret = false;
if (editable) {
if (column == COL_DATE) {
} else {
ret = super.isCellEditable(row, column);
}
} else {
}
return ret;
}
public boolean isEditable() {
return editable;
}
public void setEditable(boolean editable) {
this.editable = editable;
}
public Object getSelectObject(int row) {
Object ret = null;
if (row < dataVector.size()) {
Vector rowVector = (Vector) dataVector.elementAt(row);
ret = rowVector.elementAt(COL_DATA);
}
return ret;
}
}
当表格处于编辑状态时,会调用CellEditor来提供编辑入口,通过自定义CellEditor可以设置不同的单元格编辑框的样式,可以是JcomboBox、JtextField、JcheckBox等文本输入控件。可以按照对象类型设置所有某个对象类型的单元格都是一种CellEditor也是按照列来分别设置不同的列使用不同的编辑器。
private void initTable(final GameListTable gameTable) {
EnumGameType[] types = EnumGameType.values();
JComboBox<EnumGameType> typeBox = new JComboBox<EnumGameType>(types);
gameTable.getColumnModel().getColumn(GameListTableModel.COL_TYPE).setCellEditor(new CustomCellEditor(typeBox));
JComboBox<Company> companyBox = new JComboBox<>();
List<Company> companies = DataCache.getInstance().getComanies();
if (companies != null) {
companyBox.setModel(
new DefaultComboBoxModel<Company>(
(Company[]) companies.toArray(new Company[companies.size()])));
}
gameTable.getColumnModel().getColumn(GameListTableModel.COL_COMPANY).setCellEditor(new CustomCellEditor(companyBox));
gameTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
gameTable.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if (e.getClickCount() == 2) {
int col = gameTable.columnAtPoint(e.getPoint());
int row = gameTable.rowAtPoint(e.getPoint());
if (GameListTableModel.COL_DATE == col) {
Window parentWindow = SwingUtilities
.windowForComponent(mContainer);
DatePickerDialog dialog = new DatePickerDialog(parentWindow);
dialog.setVisible(true);
if (dialog.isChanged()) {
gameTable.setValueAt(dialog.getDateValue().getTime(), row, col);
}
}
}
super.mousePressed(e);
}
});
}
TableCellEditor是一个接口,只有一个方法getTableCellEditorComponent,该方法返回的Component将会显示在表格的某一个格子中,供用户编辑输入。一般只需要继承DefaultCellEditor,对已经实现的功能根据特殊需要就行覆盖即可。在实现Combobox时,默认情况下,Combobox不会选择表格的当前值作为选项列表的默认值,需要在方法getTableCellEditorComponent中,将表格的当前值选择上。
import java.awt.Component;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JTable;
/**
* @author Edison
* Custom a TableCellEditor for get right select when edit.
*/
public class CustomCellEditor extends DefaultCellEditor {
public CustomCellEditor(JComboBox comboBox) {
super(comboBox);
// TODO Auto-generated constructor stub
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
// TODO Auto-generated method stub
Component com = super.getTableCellEditorComponent(table, value, isSelected, row, column);
if (com instanceof JComboBox<?>) {
((JComboBox<?>) com).setSelectedItem(value);
Object obj = ((JComboBox) com).getSelectedItem();
System.out.println(obj);
}
return com;
}
}
当表格没有在编辑状态时,表格使用CellRender来显示表格的每一个单元格,同样可以根据数据类型或者列来设置每一列甚至某个单元格的样式。
import javax.swing.JTable;
public class GameListTable extends JTable {
public GameListTable() {
// exit edit status when lose focus.
putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
setDefaultRenderer(Object.class, new CustomCellRender());
setRowHeight(26);
}
}
CellRender一般都是JLabel对象,只需要继承DefaultTableCellRenderer类覆盖其中的getTableCellRendererComponent方法,该方法返回的控件在显示表格时会被调用,因此在其中可以对显示文字样式、背景色进行调整,返回控件即可。
import java.awt.Color;
import java.awt.Component;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
public class CustomCellRender extends DefaultTableCellRenderer {
private Color oddLineColor = new Color(45, 210, 150);
private Color evenLineColor = new Color(210, 150, 40);
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
// TODO Auto-generated method stub
Component com = super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
row, column);
if (row % 2 == 0) {
com.setBackground(oddLineColor);
} else {
com.setBackground(evenLineColor);
}
return com;
}
}