JTable单元格放自定义控件(一)-如何在JTable的单元格放JPanel
原文链接: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接口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();
}
}
此时运行结果如下:
我们得到了最简单的表格。
接下来我们要改写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接口JTableTestRenderer
TableColumnModel 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接口JTableTestRenderer
TableColumnModel tcm= tableA.getColumnModel();
TableColumn tc = tcm.getColumn(0);
tc.setCellRenderer(new JTableTestRenderer());
//调用我们刚才自己改写后的TableCellEditor接口JTableTestCellEditor
tc.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接口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();
}
}
}
最后的运行结果如下:
点击JButton弹出JDialog
选择两件商品后,点击确定,就将值写入了tableA中了。
现在基本完成了这个功能。在这个的基础上,要做出效果类似于智慧记那样的效果或是其他操作,那就是调整表表格本身的事情了。
JTable单元格放自定义控件(一)-如何在JTable的单元格放JPanel的更多相关文章
- delphi 需要应用一个单元是,需要在工程里面先添加单元
delphi 需要应用一个单元是,需要在工程里面先添加单元
- Excel 2010 如何在Excel的单元格中加入下拉选项
http://jingyan.baidu.com/article/03b2f78c4ba8a05ea237ae95.html 第一步:打开excel文档,选中需加入下拉选项的单元格. 第二步:点击 ...
- EXCEL中,如何引用一个单元格中的数据,作为另一个单元格内容中的一部分?
https://zhidao.baidu.com/question/230715654.html 假设单元格A1值是8(该值由函数计算得出),我要在单元格B1中引用A1的值,但只是作为B1单元格内容中 ...
- NPOI 生成Excel (单元格合并、设置单元格样式:字段,颜色、设置单元格为下拉框并限制输入值、设置单元格只能输入数字等)
NPIO源码地址:https://github.com/tonyqus/npoi NPIO使用参考:源码中的 NPOITest项目 下面代码包括: 1.包含多个Sheet的Excel 2.单元格合并 ...
- 如何在JTable中动态添加一行
JTable tbImage = new JTable(5,5);//create a dummy tableDefaultTableModel dtm=(DefaultTableModel)tbIm ...
- POI使用cell.getCellStyle()设置指定单元格颜色,但是其它没有指定的单元格也会变色
HSSFCell cell = row.createCell((short)i); cell.getCellStyle().setAlignment(HSSFCellStyle.ALIGN_RIGHT ...
- 网易云课堂_C++程序设计入门(上)_第4单元:物以类聚 – 对象和类_第4单元作业【3】- 在线编程(难度:难)
1 在本单元作业[1]和作业[2]的基础上,创建一个MyRectangle类,并在main函数中创建类的实例.(10分) 题目难度: 难 题目内容: Screen类: 与作业[2]要求完全相同. 如果 ...
- 网易云课堂_C++程序设计入门(下)_第11单元:工欲善其事必先利其器 - STL简介_第11单元 - 单元作业2:OJ编程 - list 与 deque
第11单元 - 单元作业2:OJ编程 - list 与 deque 查看帮助 返回 温馨提示: 1.本次作业属于Online Judge题目,提交后由系统即时判分. 2.学生可以在作业截止时间之 ...
- 在JTable单元格上 加入组件,并赋予可编辑能力 [转]
表格(单元格放置组件) 对于JTable单元格的渲染主要是通过两个接口来实现的,一个是TableCellRenderer另一个是TableCellEditor,JTable默认是用的是DefaultC ...
随机推荐
- windows创建桌面快捷方式的VBA脚本
Dim wShell, oShortcut 'Dim strDesktop$ ' 为了与VBS兼容, Dim strDesktop ' 这里改写一下,测试通过... Set w ...
- (转)MapReduce中的两表join几种方案简介
转自:http://blog.csdn.net/leoleocmm/article/details/8602081 1. 概述 在传统数据库(如:MYSQL)中,JOIN操作是非常常见且非常耗时的.而 ...
- (转)MapReduce二次排序
一.概述 MapReduce框架对处理结果的输出会根据key值进行默认的排序,这个默认排序可以满足一部分需求,但是也是十分有限的.在我们实际的需求当中,往往有要对reduce输出结果进行二次排序的需求 ...
- Async详解之一:流程控制
为了适应异步编程,减少回调的嵌套,我尝试了很多库.最终觉得还是async最靠谱. 地址:https://github.com/caolan/async Async的内容分为三部分: 流程控制:简化十种 ...
- ios技术面试题
1.Difference between shallow copy and deep copy? 浅复制 只拷贝地址 不拷贝地址指向的对象 深复制 拷贝地址 并且指向拷贝的新对象 2.What is ...
- [转]TCP、UDP数据包大小的确定
TCP.UDP数据包大小的确定 http://blog.163.com/jianlizhao%40126/blog/static/1732511632013410101827640/ U ...
- python num[y array
http://sebug.net/paper/books/scipydoc/numpy_intro.html npArr1=np.array([1,2,3],[4,5,6],[7,8,9]]) npA ...
- 一次失败的面试——IBM电话面试
前几天接到IBM的电话面试了,虽然被PASS了,还是发个博记录一下吧.这大概是我第一次比较正式的面试了,虽然只是通过电话,但是还是暴露出了自己的很多问题,总结下,前事不忘,后事之师嘛.:) 一号上午接 ...
- html+css学习笔记 [基础1]
---------------------------------------------------------------------------------------------------- ...
- SpringJUnit4测试--测试无反应/控制台报空指针的解决---junit的jar冲突!
前言: 前些日子碰到一个诡异的问题--用springJUnit进行测试,运行方法什么反应也没有,控制台 也没有输出,百度也没有答案--只好暂时作罢.今天我只好用上了排除法,建个测试小项目,将只要能测试 ...