JTable用法-实例

前几篇文章介绍了JTable的基本用法,本文实现一个简单的JTable,算是前文的一个总结,并造福供拷贝党们。

Swing-JTable用法-入门

Swing-JTable的渲染器与编辑器使用demo

Swing-JTable检测单元格数据变更事件

一、主要功能

1.数据的增删改;

2.渲染器:“Vegetarian”列存放布尔值,以checkBox形式显示;“Sport”列存放字符串,以comboBox形式显示;

3.编辑器:“Name”的编辑器实现一个按钮,按下时弹出对话框;

4.ToolTip:各列和各单元格均具有自己的ToolTip,且单元格ToolTip与其值相关;

5.事件:检测单元格值的变更,并输出旧值、新值和单元格坐标。

二、程序设计

本程序根据功能可分为6部分,以6个类来实现,分别是:

Gui.java:实现GUI,成员有:1个JTable,2个按钮;

MyJTable.java:继承自JTable,重载2个方法:getToolTipText和createDefaultTableHeader,分别实现单元格和表头的toolTip;

MyTableModel.java:继承自DefaultTableModel,重载1个方法:getColumnClass,实现布尔值的checkBox形式显示。表格的基本功能均已被DefaultTableModel类实现,直接使用就好。如果你还需要对单元格可访问性等细节进行精确控制,可以重载相关方法。

TableCellListener.java:实现对单元格数据变更的检测。这是通过表格的addPropertyChangeListener方法实现的,而不是基于tableModel的addTableModelListener方法。后者的不足之处在前文中已经分析。

ButtonEditor.java:实现一个基于按钮的编辑器,被按下时弹出对话框;

ButtonRenderer.java:实现一个渲染器,可定制单元格的配色。

三、程序代码

Gui.java

package DefaultTableModelDemo;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;
import JButtonTableExample.ButtonEditor;
import JButtonTableExample.ButtonRenderer;


public class Gui extends JPanel {
    
    private Object[] tmpRow = {"tmpName", "tmpDescription"};
    private MyJTable table;
    private JButton addBtn;
    private JButton delBtn;
    private MyTableModel model ;
    
     public Gui() {
         table = new MyJTable();
            table.setPreferredScrollableViewportSize(new Dimension(500, 300));
            table.setFillsViewportHeight(true);
            
            //Create the scroll pane and add the table to it.
            JScrollPane scrollPane = new JScrollPane(table);
            //scrollPane.setPreferredSize(new Dimension(500, 600));
            //scrollPane.set
            //Add the scroll pane to this panel.
            add(scrollPane);
            //set tableModel and data
            model = new MyTableModel();
            String[] columnNames = {"Name",
                    "Description",
                    "Sport",
                    "# of Years",
                    "Vegetarian"};
            Object[][] data = {
                    {"Kathy", "Smith",
                     "Snowboarding", new Integer(5), new Boolean(false)},
                    {"John", "Doe",
                     "Rowing", new Integer(3), new Boolean(true)},
                    {"Sue", "Black",
                     "Knitting", new Integer(2), new Boolean(false)},
                    {"Jane", "White",
                     "Speed reading", new Integer(20), new Boolean(true)},
                    {"Joe", "Brown",
                     "Pool", new Integer(10), new Boolean(false)}
                    };
            model.setDataVector(data, columnNames);
            table.setModel(model);
            //添加渲染器
            table.getColumn("Name").setCellRenderer(new ButtonRenderer());
            //添加编辑器
            table.getColumn("Name").setCellEditor( new ButtonEditor());
            //添加按钮
            addBtn = new JButton("增加");
            addBtn.addActionListener(new ActionListener() {
                
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    // TODO Auto-generated method stub
                    model.addRow(tmpRow);
                }
            });
            
            delBtn = new JButton("删除");
            delBtn.addActionListener(new ActionListener() {
                
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    // TODO Auto-generated method stub
                    int rowIndex = table.getSelectedRow();
                    if(rowIndex != -1)
                        model.removeRow(rowIndex);
                }
            });
            
            add(addBtn);
            add(delBtn);
            
            addDataChangeListener();
            
            //设置列
            setSportsColumn();
     }
     
     private void setSportsColumn(){
            String [] itmes = {"Snowboarding", "Rowing", "Knitting", "Speed reading", "Pool"};
            JComboBox<String> comboBox = new JComboBox<String>(itmes);
            DefaultTableCellRenderer renderer =
                    new DefaultTableCellRenderer();
            renderer.setToolTipText("Click for combo box");
            setColumn("Sport", comboBox, renderer);
            TableColumn col = table.getColumn("Sport");
            //setToolTipText("favorit sport is " + );
        }
     
     public void setColumn(String colName, Object editor, Object renderer) {
            int index = table.getColumnModel().getColumnIndex(colName);
            TableColumn modeColumn = table.getColumnModel().getColumn(index);
            if (editor instanceof JComponent) {
                setEditor(modeColumn, (JComponent)editor);
            }
            else if (editor instanceof DefaultCellEditor) {
                modeColumn.setCellEditor((DefaultCellEditor)editor);
            }
            
            if (renderer instanceof DefaultTableCellRenderer) {
                modeColumn.setCellRenderer((DefaultTableCellRenderer)renderer);
            }
            else if (renderer instanceof ButtonRenderer) {
                modeColumn.setCellRenderer((ButtonRenderer)renderer);
            }
        }
     
     protected void setEditor(TableColumn column, JComponent component){
         if(component instanceof JTextField )
            column.setCellEditor(new DefaultCellEditor((JTextField) component));
         else if(component instanceof JComboBox )
            column.setCellEditor(new DefaultCellEditor((JComboBox<String>) component));
         else if(component instanceof JCheckBox )
            column.setCellEditor(new DefaultCellEditor((JCheckBox) component));
     }
     
     private void addDataChangeListener(){
         //检测单元格数据变更
         Action action = new AbstractAction()
         {
             public void actionPerformed(ActionEvent e)
             {
                 TableCellListener tcl = (TableCellListener)e.getSource();
                 int row = tcl.getRow();
                 int col = tcl.getColumn();
                 Object oldValue = tcl.getOldValue();
                 //if(oldValue == null)
                     //oldValue = "";
                 Object newValue = tcl.getNewValue();       
                 //if(newValue == null)
                     //newValue = "";
                 System.out.printf("cell changed at [%d,%d] : %s -> %s%n",row, col, oldValue, newValue);
             }
         };
         @SuppressWarnings("unused")
        TableCellListener tcl1 = new TableCellListener(table, action);
         System.out.printf("cell changed%n");
     }
     
     private static void createAndShowGUI() {
            //Create and set up the window.
            JFrame frame = new JFrame("Gui");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            //Create and set up the content pane.
            Gui newContentPane = new Gui();
            newContentPane.setOpaque(true); //content panes must be opaque
            frame.setContentPane(newContentPane);

            //Display the window.
            frame.pack();
            frame.setVisible(true);
        }

        public static void main(String[] args) {
            //Schedule a job for the event-dispatching thread:
            //creating and showing this application's GUI.
            javax.swing.SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    createAndShowGUI();
                }
            });
        }
}

 

MyTableModel.java

package DefaultTableModelDemo;

import javax.swing.table.DefaultTableModel;

public class MyTableModel extends DefaultTableModel{

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        if (columnIndex == 4)
            return Boolean.class;
        return super.getColumnClass(columnIndex);
    }
}

 

MyJTable.java

package DefaultTableModelDemo;

import java.awt.event.MouseEvent;

import javax.swing.JTable;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableModel;

public class MyJTable extends JTable{

    protected String[] columnToolTips = {null,
            null,
            "The person's favorite sport to participate in is : ",
            "The number of years the person has played the sportis : ",
            "If checked, the person eats no meat"};
    
    //Implement table cell tool tips.
    public String getToolTipText(MouseEvent e) {
        String tip = null;
        java.awt.Point p = e.getPoint();
        int rowIndex = rowAtPoint(p);
        int colIndex = columnAtPoint(p);
        int realColumnIndex = convertColumnIndexToModel(colIndex);
        if(rowIndex < 0)
        {
            //System.out.printf("abnormal rowIndex: %n", rowIndex);
            return null;
        }
        
        if (realColumnIndex == 2) { //Sport column
            tip = columnToolTips[2] 
                   + getValueAt(rowIndex, colIndex);
        } 
        else if (realColumnIndex == 3) { //Years column
            tip = columnToolTips[3] + getValueAt(rowIndex, colIndex);
             
        }else if (realColumnIndex == 4) { //Veggie column
            TableModel model = getModel();
            String firstName = (String)model.getValueAt(rowIndex,0);
            String lastName = (String)model.getValueAt(rowIndex,1);
            Boolean veggie = (Boolean)model.getValueAt(rowIndex,4);
            if (Boolean.TRUE.equals(veggie)) {
                tip = firstName + " " + lastName
                      + " is a vegetarian";
            } else {
                tip = firstName + " " + lastName
                      + " is not a vegetarian";
            }
        } else { 
            //You can omit this part if you know you don't 
            //have any renderers that supply their own tool 
            //tips.
            tip = super.getToolTipText(e);
        }
        return tip;
    }

    //Implement table header tool tips.
    protected JTableHeader createDefaultTableHeader() {
        return new JTableHeader(columnModel) {
            public String getToolTipText(MouseEvent e) {
                String tip = null;
                java.awt.Point p = e.getPoint();
                int index = columnModel.getColumnIndexAtX(p.x);
                int realIndex = 
                        columnModel.getColumn(index).getModelIndex();
                return columnToolTips[realIndex];
            }
        };
    }
    
    
}

 

TableCellListener.java

package DefaultTableModelDemo;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*;

/*
 *  This class listens for changes made to the data in the table via the
 *  TableCellEditor. When editing is started, the value of the cell is saved
 *  When editing is stopped the new value is saved. When the oold and new
 *  values are different, then the provided Action is invoked.
 *
 *  The source of the Action is a TableCellListener instance.
 */
public class TableCellListener implements PropertyChangeListener, Runnable
{
    private JTable table;
    private Action action;

    private int row;
    private int column;
    private Object oldValue;
    private Object newValue;

    /**
     *  Create a TableCellListener.
     *
     *  @param table   the table to be monitored for data changes
     *  @param action  the Action to invoke when cell data is changed
     */
    
    public TableCellListener(JTable table, Action action)
    {
        this.table = table;
        this.action = action;
        this.table.addPropertyChangeListener( this );
    }

    /**
     *  Create a TableCellListener with a copy of all the data relevant to
     *  the change of data for a given cell.
     *
     *  @param row  the row of the changed cell
     *  @param column  the column of the changed cell
     *  @param oldValue  the old data of the changed cell
     *  @param newValue  the new data of the changed cell
     */
    private TableCellListener(JTable table, int row, int column, Object oldValue, Object newValue)
    {
        this.table = table;
        this.row = row;
        this.column = column;
        this.oldValue = oldValue;
        this.newValue = newValue;
    }

    /**
     *  Get the column that was last edited
     *
     *  @return the column that was edited
     */
    public int getColumn()
    {
        return column;
    }

    /**
     *  Get the new value in the cell
     *
     *  @return the new value in the cell
     */
    public Object getNewValue()
    {
        return newValue;
    }

    /**
     *  Get the old value of the cell
     *
     *  @return the old value of the cell
     */
    public Object getOldValue()
    {
        return oldValue;
    }

    /**
     *  Get the row that was last edited
     *
     *  @return the row that was edited
     */
    public int getRow()
    {
        return row;
    }

    /**
     *  Get the table of the cell that was changed
     *
     *  @return the table of the cell that was changed
     */
    public JTable getTable()
    {
        return table;
    }
//
//  Implement the PropertyChangeListener interface
//
    @Override
    public void propertyChange(PropertyChangeEvent e)
    {
        //  A cell has started/stopped editing

        if ("tableCellEditor".equals(e.getPropertyName()))
        {
            if (table.isEditing()){
                //System.out.printf("tableCellEditor is editing..%n");
                processEditingStarted();
            }
            else{
                //System.out.printf("tableCellEditor editing stopped..%n");
                processEditingStopped();
            }
                
        }
    }

    /*
     *  Save information of the cell about to be edited
     */
    private void processEditingStarted()
    {
        //  The invokeLater is necessary because the editing row and editing
        //  column of the table have not been set when the "tableCellEditor"
        //  PropertyChangeEvent is fired.
        //  This results in the "run" method being invoked

        SwingUtilities.invokeLater( this );
    }
    /*
     *  See above.
     */
    @Override
    public void run()
    {
        row = table.convertRowIndexToModel( table.getEditingRow() );
        column = table.convertColumnIndexToModel( table.getEditingColumn() );
        oldValue = table.getModel().getValueAt(row, column);
        //这里应对oldValue为null的情况做处理,否则将导致原值与新值均为空时仍被视为值改变
        if(oldValue == null)
            oldValue = "";
        newValue = null;
    }

    /*
     *    Update the Cell history when necessary
     */
    private void processEditingStopped()
    {
        newValue = table.getModel().getValueAt(row, column);
        //这里应对newValue为null的情况做处理,否则后面会抛出异常
        if(newValue == null)
            newValue = "";
        //  The data has changed, invoke the supplied Action
        if (! newValue.equals(oldValue))
        {
            //  Make a copy of the data in case another cell starts editing
            //  while processing this change

            
            TableCellListener tcl = new TableCellListener(
                getTable(), getRow(), getColumn(), getOldValue(), getNewValue());

            ActionEvent event = new ActionEvent(
                tcl,
                ActionEvent.ACTION_PERFORMED,
                "");        
            action.actionPerformed(event);
        }
    }
}

 

ButtonEditor.java

package JButtonTableExample;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JTable;

public class ButtonEditor extends DefaultCellEditor {
      protected JButton button;//represent the  cellEditorComponent
      private String cellValue;//保存cellEditorValue

      public ButtonEditor() {
        super(new JCheckBox());
        button = new JButton();
        button.setOpaque(true);
        button.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            JOptionPane.showMessageDialog(button, cellValue + ": Ouch!");
            //刷新渲染器
            fireEditingStopped();
          }
        });
      }

      public JComponent getTableCellEditorComponent(JTable table, Object value,
          boolean isSelected, int row, int column) {
        //value 源于单元格数值
        cellValue = (value == null) ? "" : value.toString();
        return button;
      }

     public Object getCellEditorValue() {
        return new String(cellValue);
      }
    }

 

ButtonRenderer.java

package JButtonTableExample;

import java.awt.Color;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;

public class ButtonRenderer extends JButton implements TableCellRenderer {

      public JComponent getTableCellRendererComponent(JTable table, Object value,
          boolean isSelected, boolean hasFocus, int row, int column) {
          //value 源于editor
          String text = (value == null) ? "" : value.toString();
          //按钮文字
          setText(text);
          //单元格提示
          setToolTipText(text);
          //背景色
          setBackground(Color.BLACK);
          //前景色
          setForeground(Color.green);
        return this;
      }
    }

 

运行效果如下:

 

posted on 2016-02-29 23:01  pzy4447  阅读(29568)  评论(0编辑  收藏  举报