zoukankan      html  css  js  c++  java
  • 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如下

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

    2、点击JButton后界面如下

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

    3、选中tableB的多行数据

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

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

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


           这个问题我首先查了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();
           }
    }

    此时运行结果如下:

    JTable单元格放自定义控件(一)-如何在JTable的单元格放JPanel
    我们得到了最简单的表格。

    接下来我们要改写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();
              }
    }

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

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

    我们先写出接下来要弹出的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();
     }
    }

    运行结果如下:

    JTable单元格放自定义控件(一)-如何在JTable的单元格放JPanel
    此时是不是更加接近我们想要的效果了。但是如何实现最后一部功能呢。即,在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

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

    选择两件商品后,点击确定,就将值写入了tableA中了。
    JTable单元格放自定义控件(一)-如何在JTable的单元格放JPanel

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

  • 相关阅读:
    Spring Boot 入门之持久层篇(三)
    Spring Boot 入门之 Web 篇(二)
    Spring Boot 入门之基础篇(一)
    Java 设计模式之建造者模式(四)
    Java 设计模式之抽象工厂模式(三)
    Java 设计模式之工厂模式(二)
    c++ type_info and typeid
    opengl& 颜色
    OpenGl And 视图
    如何写一个c++插件化系统
  • 原文地址:https://www.cnblogs.com/beautiful-code/p/5049029.html
Copyright © 2011-2022 走看看