原文鏈接: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
現在基本完成了這個功能。在這個的基礎上,要做出效果類似於智慧記那樣的效果或是其他操作,那就是調整表表格本身的事情了。