最近自己尝试着模仿着实现一款非常有名的进销库存管理系统(智慧记)里面的一个功能。功能如下下图所示。
JTable
tableA的第一列(品名规格)放的是自定义JPanel控件,JPanel上面放的是JTextfield和JButton,点击每一行第一列的JButton会弹出弹出一个JDialog,选择JDialog上面表格tableB的多行数据,插入到表格tableA里去。
1、一开始的表格tableA如下
http://s2/mw690/002kk4Nzzy6ETAx9Cc991&690
2、点击JButton后界面如下
http://s3/mw690/002kk4Nzzy6ETAAiHN882&690
3、选中tableB的多行数据
http://s12/mw690/002kk4Nzzy6ETAD1mjxbb&690
4、点击确定的时候一次性插入选中的数据到tableA中
http://s13/mw690/002kk4Nzzy6ETAFKsSU1c&690
这个问题我首先查了jdk文档,发现API里并没有提供一种方法可以直接实现这个操作,于是上网查了很长时间资料,最后终于解决了这个问题,下面我详细的谈谈我实现这个功能的过程,并提供我实现这个功能的可以直接运行的源代码。
要解决这个问题,要先弄清楚TableModel、TableCellRenderer、TableCellEditor接口的作用,
TableModel为JTable提供显示的数据、维数、表格中的数据类型、显示的列标题以及单元格·是否允许被编辑用的。TableCellRenderer(单元格渲染器)接口,就是用来绘制展示当前cell单元数值内容的,你可以用文字、数值或者图片来表示内容,我们现在要绘制的就是一个带有一个JButton和一个JTextField的JPanel。就是上图tableA里的那个第一列的自定义控件。TableCellEditor(单元格编辑器)接口, 主要是用来当用户点击在具体cell时进行编辑的组件,所以TableCellEditor除了具有TableCellRenderer一样的绘制功能外还可以进行交互动作,例如在cell上出现下拉框、勾选框甚至通过按钮弹出更复杂的对话框让用户进行输入编辑。我们现在就是要通过这个接口,实现给单元格里的JButton添加事件,从而使其能够弹出上图那个JDialog。
实现这个功能我用了3个类。大家先运行下下面的代码,然后在代码后面,我尝试着讲解了是如何一步步得到最后这段可以运行的代码的。
JTableTestCellEdit完整的代码如下:
package specialtable;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.EventObject;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.EventListenerList;
import javax.swing.table.TableCellEditor;
public class JTableTestCellEdit extends JPanel implements
TableCellEditor,ActionListener{
private static final long serialVersionUID
= 5860619160549087886L;
//EventListenerList:保存EventListener
列表的类。
private EventListenerList
listenerList = new EventListenerList();
//ChangeEvent用于通知感兴趣的参与者事件源中的状态已发生更改。
private ChangeEvent changeEvent =
new ChangeEvent(this);
JButton edit_btn;
JTextField edit_txf;
JTableTest jTableTest;
public
JTableTestCellEdit(){
super();
setLayout(new
BorderLayout());
edit_btn = new
JButton("...");
edit_txf = new
JTextField();
add(edit_txf);
add(edit_btn,BorderLayout.EAST);
edit_btn.setBackground(Color.white);
edit_btn.setPreferredSize(new
Dimension(20,getHeight()));
edit_btn.addActionListener(this);
}
JTableTestCellEdit(JTableTest
jTableTest){
this();
this.jTableTest =
jTableTest;
}
public void
addCellEditorListener(CellEditorListener l)
{
listenerList.add(CellEditorListener.class,l);
}
public void
removeCellEditorListener(CellEditorListener l)
{
listenerList.remove(CellEditorListener.class,l);
}
private void
fireEditingStopped(){
CellEditorListener
listener;
Object[]listeners
= listenerList.getListenerList();
for(int i
= 0; i < listeners.length; i++){
if(listeners[i]==
CellEditorListener.class){
//之所以是i+1,是因为一个为CellEditorListener.class(Class对象),
//接着的是一个CellEditorListener的实例
listener=
(CellEditorListener)listeners[i+1];
//让changeEvent去通知编辑器已经结束编辑
// //在editingStopped方法中,JTable调用getCellEditorValue()取回单元格的值,
//并且把这个值传递给TableValues(TableModel)的setValueAt()
listener.editingStopped(changeEvent);
}
}
}
public void cancelCellEditing()
{
}
public boolean stopCellEditing()
{
//可以注释掉下面的fireEditingStopped();,然后在GenderEditor的构造函数中把
//addActionListener()的注释去掉(这时请求终止编辑操作从JComboBox获得),
System.out.println("编辑其中一个单元格,再点击另一个单元格时,调用。");
fireEditingStopped();//请求终止编辑操作从JTable获得
return
true;
}
public Component
getTableCellEditorComponent(JTable table, Object
value,
boolean
isSelected, int row, int column) {
if(value
!= null)
edit_txf.setText(value.toString());
return
this;
}
public boolean
isCellEditable(EventObject anEvent) {
return
true;
}
public boolean
shouldSelectCell(EventObject anEvent) {
return
true;
}
public Object getCellEditorValue()
{
return
edit_txf.getText();
}
public void actionPerformed(ActionEvent
e){
Point p =
edit_btn.getLocation();
new
JTableTestDialog(100,180,this,jTableTest).setVisible(true);
}
}
JTableTest 类的完整代码如下:
package specialtable;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
public class JTableTest extends JFrame{
String[] columnNames =
{"名称及规格","零数","件数","数量","单位","件价","单价","金额","备注"};
JTable tableA;
public Object[][] values =
{
{"","","","","","","","",""},
{"","","","","","","","",""},
{"","","","","","","","",""},
{"","","","","","","","",""},
{"","","","","","","","",""}
};
DefaultTableModel model = new
DefaultTableModel(values,columnNames);
public JTableTest(){
setBounds(100,100,800,400);
tableA = new
JTable(model);
tableA.setRowHeight(30);
JScrollPane
scrollPane = new JScrollPane(tableA);
DefaultTableColumnModel
dcm = (DefaultTableColumnModel)tableA.getColumnModel();
dcm.getColumn(0).setPreferredWidth(200);
//调用我们刚才自己改写后的TableCellRenderer接口JTableTestRenderer
TableColumnModel
tcm= tableA.getColumnModel();
TableColumn
tc = tcm.getColumn(0);
tc.setCellRenderer(new
JTableTestRenderer());
//调用我们刚才自己改写后的TableCellEditor接口JTableTestCellEditor
tc.setCellEditor(new
JTableTestCellEdit(this));
add(scrollPane);
setVisible(true);
}
public static void main(String[]
args){
new
JTableTest();
}
public void
getTable(DefaultTableModel model){
tableA.setModel(model);
TableColumnModel
tcm= tableA.getColumnModel();
TableColumn tc =
tcm.getColumn(0);
tc.setCellRenderer(new
JTableTestRenderer());
tc.setCellEditor(new
JTableTestCellEdit(this));
tableA.setColumnSelectionAllowed(false);
tableA.setRowSelectionAllowed(false);
tcm.getColumn(0).setPreferredWidth(200);
tableA.repaint();
}
}
JTableTestDialog类的完整代码如下:
package specialtable;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.Connection;
import java.sql.Statement;
import java.util.Iterator;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.DefaultTableModel;
public class JTableTestDialog extends JDialog implements
ActionListener{
String[] colunmNames =
{"厂商","名称及规格","零数","件数"};
public Object[][] values =
{
{"京东","电器","12","13"},
{"淘宝","电脑","15","16"},
{"当当","书籍","13","26"},
{"拍拍","qq","15","96"},
{"亚马逊","书","12","18"}
};
DefaultTableModel model = new
DefaultTableModel(values,colunmNames);
JTable tableB;
JScrollPane scrollPane;
JLabel tip_lbl =new
JLabel("按ctrl或shift可多选货品");
JButton ok = new JButton("确定");
JPanel centerPanel = new JPanel();
JPanel southPanel = new JPanel();
JTableTestCellEdit jTableTestCellEdit;
JTableTest jTableTest;
public JTableTestDialog(int x,int
y){
setBounds(x,y,400,300);
tableB = new
JTable(model);
scrollPane = new
JScrollPane(tableB);
scrollPane.setSize(400,
280);
southPanel.add(tip_lbl,BorderLayout.WEST);
southPanel.add(ok,BorderLayout.EAST);
ok.addActionListener(this);
add(scrollPane,BorderLayout.CENTER);
add(southPanel,BorderLayout.SOUTH);
}
public JTableTestDialog(int x,int
y,JTableTestCellEdit jTableTestCellEdit,JTableTest
jTableTest){
this(x,y);
this.jTableTestCellEdit
= jTableTestCellEdit;
this.jTableTest =
jTableTest;
}
public void actionPerformed(ActionEvent
e){
if(jTableTestCellEdit
!= null && jTableTest != null){
String[]
columnNames =
{"名称及规格","零数","件数","数量","单位","件价","单价","金额","备注"};
DefaultTableModel
model2 = new DefaultTableModel(columnNames,0);
int[]
rows = tableB.getSelectedRows();
for(int
i = 0; i < rows.length; i++){
Vector v
= new Vector();
v.add(tableB.getValueAt(rows[i],
0));
v.add(tableB.getValueAt(rows[i],
1));
v.add(tableB.getValueAt(rows[i],
2));
v.add(tableB.getValueAt(rows[i],
3));
v.add("");
v.add("");
v.add("");
v.add("");
v.add("");
model2.addRow(v);
}
for(int
i = 0; i < 5;i++){
Vector v
= new Vector();
v.add("");
v.add("");
v.add("");
v.add("");
v.add("");
v.add("");
v.add("");
v.add("");
v.add("");
model2.addRow(v);
}
jTableTest.getTable(model2);
dispose();
}
}
}
代码的实现过程。
首先我们在一个窗口里写出tableA代码如下。
package specialtable;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.DefaultTableModel;
public class JTableTest extends JFrame{
String[] columnNames =
{"名称及规格","零数","件数","数量","单位","件价","单价","金额","备注"};
JTable tableA;
public Object[][] values = {
{"","","","","","","","",""},
{"","","","","","","","",""},
{"","","","","","","","",""},
{"","","","","","","","",""},
{"","","","","","","","",""}
};
DefaultTableModel model = new
DefaultTableModel(values,columnNames);
public JTableTest(){
setBounds(100,100,800,400);
tableA = new JTable(model);
tableA.setRowHeight(30);
JScrollPane scrollPane = new JScrollPane(tableA);
DefaultTableColumnModel dcm =
(DefaultTableColumnModel)tableA.getColumnModel();
dcm.getColumn(0).setPreferredWidth(200);
add(scrollPane);
setVisible(true);
}
public static void main(String[] args){
new JTableTest();
}
}
此时运行结果如下:
http://s16/mw690/002kk4Nzzy6ETrijgePbf&690
我们得到了最简单的表格。
接下来我们要改写TableCellRenderer,代码如下:
package specialtable;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.TableCellRenderer;
public class JTableTestRenderer extends JPanel implements
TableCellRenderer {
JButton edit_btn;
JTextField edit_txf;
public
JTableTestRenderer(){
super();
setLayout(new BorderLayout());
edit_btn = new JButton("...");
edit_txf = new JTextField();
add(edit_txf);
add(edit_btn,BorderLayout.EAST);
edit_btn.setBackground(Color.white);
edit_btn.setPreferredSize(new
Dimension(20,getHeight()));
}
public Component
getTableCellRendererComponent(JTable table, Object
value,
boolean isSelected, boolean hasFocus, int row,
int column) {
if(isSelected){
setForeground(table.getForeground());
super.setBackground(table.getBackground());
}else{
setForeground(table.getForeground());
setBackground(table.getBackground());
}
if(value != null)