原文链接:http://blog.sina.com.cn/s/blog_7f1c8c710101hdpf.html
最近自己尝试着模仿着实现一款非常有名的进销库存管理系统(智慧记)里面的一个功能。功能如下下图所示。
JTable tableA的第一列(品名规格)放的是自定义JPanel控件,JPanel上面放的是JTextfield和JButton,点击每一行第一列的JButton会弹出弹出一个JDialog,选择JDialog上面表格tableB的多行数据,插入到表格tableA里去。
1、一开始的表格tableA如下

2、点击JButton后界面如下

3、选中tableB的多行数据

4、点击确定的时候一次性插入选中的数据到tableA中

这个问题我首先查了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接口JTableTestRendererTableColumnModel tcm= tableA.getColumnModel(); TableColumn tc = tcm.getColumn(0); tc.setCellRenderer(new JTableTestRenderer());//调用我们刚才自己改写后的TableCellEditor接口JTableTestCellEditortc.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();}
}

此时运行结果如下:

我们得到了最简单的表格。
接下来我们要改写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)edit_txf.setText(value.toString());return this; }
}

//在类JTableTest调用我们刚才自己改写后的TableCellRenderer接口JTableTestRenderer
TableColumnModel tcm= tableA.getColumnModel();
TableColumn tc = tcm.getColumn(0);
tc.setCellRenderer(new JTableTestRenderer());
此时,完整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接口JTableTestRendererTableColumnModel tcm= tableA.getColumnModel(); TableColumn tc = tcm.getColumn(0); tc.setCellRenderer(new JTableTestRenderer());add(scrollPane);setVisible(true);}public static void main(String[] args){new JTableTest();}
}

此时运行结果如下,看看第一列似乎已经变成我们需要的样子了。

我们先写出接下来要弹出的JDialog类JTableTestDialog ,代码如下:

package specialtable;
import java.awt.BorderLayout;
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{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();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);add(scrollPane,BorderLayout.CENTER);add(southPanel,BorderLayout.SOUTH);}
}

接下来我们改写TableCellEditor接口:

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;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);    //给单元格的JButton添加ActionListener,以便于弹出JDialog} 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){new JTableTestDialog(100,180).setVisible(true);}
}

此时在JTableTest中调用我们刚才自己改写后的TableCellEditor接口JTableTestCellEditor
调用后的的完整代码如下:

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接口JTableTestRendererTableColumnModel tcm= tableA.getColumnModel(); TableColumn tc = tcm.getColumn(0); tc.setCellRenderer(new JTableTestRenderer());//调用我们刚才自己改写后的TableCellEditor接口JTableTestCellEditortc.setCellEditor(new JTableTestCellEdit()); add(scrollPane);setVisible(true);}public static void main(String[] args){new JTableTest();}
}

运行结果如下:

此时是不是更加接近我们想要的效果了。但是如何实现最后一部功能呢。即,在JTableTestDialog中选择多行数据插入表格tableA。
我们可以将数据先写入TableModel中,由于这个过程是弹出JTableTestDialog后完成的,而最终的结果写在了tableA里,因此,需要把JTableTest当前对象传给给JTableTestDialog,而JTableTestDialog是在点击了JTableTestCellEdit的JButton之后弹出来的,而JTableTestCellEdit是在JTableTest里调用的,因此可以JTableTest通过把当前对象先传给JTableTestCellEdit对象,然后在弹出JDialog后通过JTableTestCellEdit对象和JTableTestCellEdit同时传给JDialog对象。然后在JDialog对象里将数据传到JTableTest对象的tableModel里去。因此我们分别要在这些类里添加一些构造方法,以便实现对象的传递。这个过程似乎有点复杂,我不确定自己讲清楚了没有,不多说了,直接看代码吧,这样最直接。
在JTableTestCellEdit里添加一个如下构造方法,以便于将JTableTest对象传进来。

JTableTestCellEdit(JTableTest jTableTest){this();this.jTableTest = jTableTest;}

此时JTableTest里的调用变成如下所示,将自己传给TableCellEditor对象。
//调用我们刚才自己改写后的TableCellEditor接口JTableTestCellEditor
tc.setCellEditor(new JTableTestCellEdit(this));
JTableTestDialog里需要添加如下构造方法,以便于接收传进来的JTableTestCellEdit对象,和传给JTableTestCellEdit的JTableTest对象。

public JTableTestDialog(int x,int y,JTableTestCellEdit jTableTestCellEdit,JTableTest jTableTest){this(x,y);this.JTableTestCellEdit = JTableTestCellEdit;this.jTableTest = jTableTest;}

此时JTableTestCellEdit对象的监视器里应该通过如下语句完成传值,
new JTableTestDialog(100,180,this,jTableTest).setVisible(true);
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);}
}

JTableTestCellEdit差不多已经完成了他的任务,接下来就是JTableTestDialog对象如何将值传给JTableTest的问题了。
我们在JTableTest添加一个如下所示的方法,以便于接收JTableTestDialog里的存有JTableTestDialog上数据的TableModel对象。

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类里将数据写入TableModel对象里传给JTableTest对象:
这时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接口JTableTestRendererTableColumnModel tcm= tableA.getColumnModel(); TableColumn tc = tcm.getColumn(0); tc.setCellRenderer(new JTableTestRenderer());//调用我们刚才自己改写后的TableCellEditor接口JTableTestCellEditortc.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();   }}
}

最后的运行结果如下:
点击JButton弹出JDialog

选择两件商品后,点击确定,就将值写入了tableA中了。

现在基本完成了这个功能。在这个的基础上,要做出效果类似于智慧记那样的效果或是其他操作,那就是调整表表格本身的事情了。

JTable单元格放自定义控件(一)-如何在JTable的单元格放JPanel相关推荐

  1. java jtable 复选框_java swing如何在JTable一个单元格添加多个复选框

    展开全部 java swing中在jTable中添加多个复选框的方32313133353236313431303231363533e59b9ee7ad9431333337616566式如下:impor ...

  2. vba编程把纯文本转换成html,如何在Excel的单元格中将HTML转换为文本?

    如何在Excel的单元格中将HTML转换为文本? 如下面的屏幕截图所示,如果工作表单元格中存在许多html标记,那么如何在Excel中将它们转换为纯文本? 本文将向您展示两种从Excel单元格中删除所 ...

  3. 计算机单元格复制,2010年职称计算机考试:单元格区域的复制和移动

    单元格区域复制是将某个单元格或单元格区域内容复制到指定的其他单元格或单元格区域中,原有单元格或单元格区域内容不变;而单元格区域移动是将某个单元格或单元格区域内容移动到指定的其他单元格或单元格区域中,而 ...

  4. html打印合并单元格边框不显示不出来,word合并单元格后打印没有边框

    在excel中,合并.拆分单元格是经常会用到的.而在word文档中,偶尔我们也需要插入表格,然后编辑表格,那么如何对word中的表格单元格进行合并.拆分呢? 一.如何在word中创建表格 1.选择&q ...

  5. html table nei边框线,GitHub - meichuanneiku/TableCell: 在TableBank的基础上,进一步标注到单元格精度,利用目标检测/分割实现单元格定位。...

    项目说明 本项目是我2019年7月份的实习工作的**展示与记录**: 把倾斜的表格旋转水平: 制作5000张表格数据集,需要标注每一个单元格,并实现单元格检测 第一项比较简单,仿射变换.透视变换已经很 ...

  6. 合并单元格后打字换行_excel中合并了单元格以后往里面打字如果打两行字,怎么换行...

    点击查看excel中合并了单元格以后往里面打字如果打两行字,怎么换行具体信息 答:1.演示使用的软件为Excel电子表格,软件版本为office家庭和学生版2016. 2.为了演示如何在合并的单元格中 ...

  7. html合并单元格怎么把字竖着,电脑excel单元格中文字如何在合并单元格后竖排显示...

    电脑excel单元格中文字如何在合并单元格后竖排显示 excel软件是我们现在经常使用的数据处理工具之一,接下来小编就教大家怎样在软件中设置合并单元格之后竖排显示文字. 具体如下: 1. 首先我们需要 ...

  8. 【Excel VBA】神操作之命名单元格或区域(二)——引用命名单元格或区域

    纲举目张 说明 代码code 使用说明 本系列博文 说明 在上一篇文章<神操作之命名单元格或区域(一)--为单元格或区域命名>中,已经详细介绍了多种为单元格命名的语句.在成功为单元格或区域 ...

  9. 计算机表格单元格合并,excel表格数据拆分和合并单元格-excel中如何将已经合并的单元格拆分,并将该单元格......

    Excel怎么把一个合并单元格的内容拆分为几个单元格... 要直接位置得到,则有俩种可能性 第一种,合元格是格得来的假合并单元格,单元格都有内容,直接解除合并即可 第二种,若确实是真实合并单元格,则需 ...

  10. phpexcel合并单元格导出_PHPExcel如何实现合并与拆分单元格

    PHPExcel如何实现合并与拆分单元格?本文主要介绍了PHPExcel合并与拆分单元格的方法,涉及PHPExcel中setCellValue与mergeCells方法的使用技巧,需要的朋友可以参考下 ...

最新文章

  1. inrange函数_Python 初学者必备的常用内置函数
  2. 基于Nokia S60的游戏开发之一
  3. Tensorboard可视化:基于LeNet5进行面部表情分类
  4. JavaScript 与 PHP 的语法区别
  5. 中国抗衰老护肤品市场趋势报告、技术动态创新及市场预测
  6. JDBC 与ODBC的区别
  7. 『学了就忘系列』Linux基础命令 — 搜索操作相关命令
  8. amd核芯显卡控制面板自定义分辨率_显卡是哪个
  9. android小米 市场下载地址,小米手机下载的软件在哪里?小米应用商店下载路径介绍...
  10. 2,一个人体姿态识别的项目实现
  11. CentOS报错:There are no enabled repos
  12. 反转链表-就地逆置法
  13. 求职季找工作心得与应聘经验分享(一)
  14. php怎么变成微信小程序,自己怎么开通微信小程序
  15. 【Java设计模式】简单学外观模式——万能遥控器
  16. 电脑需要安装安全管家吗?火绒安全值不值得推荐?
  17. 区块链投资人李明轩:区块链通过多中心化机制解决传统互联网问题|筱静观察
  18. ​富士莱医药通过注册:年营收近5亿 钱祥云曾非法买卖外汇
  19. 这份 Dubbo 3.0 分布式实战笔记由阿里巴巴 P8 亲自撰写真是大厂 offer 收割机
  20. 计算机音乐谱无羁,天谕手游忘羡无羁乐谱代码是什么-天谕手游忘羡无羁乐谱代码分享_快吧手游...

热门文章

  1. Linux无法识别显示器信息,Deepin Linux 15.10 无法识别集显的HDMI
  2. JS——比较当前时间和历史时间
  3. 超嗜热酶综述翻译,《Hyperthermophilic Enzymes: Sources, Uses, and Molecular Mechanisms for Thermostability》
  4. npm 镜像淘宝替换
  5. 陈硕多线程服务器编程--持续更新
  6. ExcelToLua工具
  7. boost创建线程池_boost库使用—线程类
  8. C++ Boost库:windows下编译Boost库
  9. 继电器、并联的二极管和驱动三极管选型实战演练
  10. SpringBoot 图片压缩包上传、解压、存储等