zoukankan      html  css  js  c++  java
  • [Swing扩展组件分享]为JTable添加选择列(CheckBox)的包装类

        有个时候,我们需要在Table中添加一列来标识某行是否被选中(不同于自带的行选择),同时又不方便去修改原来TableModel。为了解决这种问题,我编写了下面这个包装类(不知这么称呼是否恰当哈)。

    CheckBoxTableModelProxy
    package trytocatch.swingplus.table;
    
    import java.util.BitSet;
    
    import javax.swing.event.TableModelEvent;
    import javax.swing.event.TableModelListener;
    import javax.swing.table.AbstractTableModel;
    import javax.swing.table.TableModel;
    /**
     * 将一个TableMode封装成新的AbstractTableModel,在其中添加一列,用以标识是否被选中
     * @author trytocatch@163.com
     * @date 2013-4-30
     */
    public class CheckBoxTableModelProxy extends AbstractTableModel {
        private static final long serialVersionUID = 4419095637613592975L;
        protected TableModel tableModel;
        protected String checkBoxColumnName;
        protected BitSet checkBitSet;
        protected int checkBoxIndex;
    
        public CheckBoxTableModelProxy(TableModel model,
                String checkBoxColumnName) {
            this(model, checkBoxColumnName, 0);
        }
    
        public CheckBoxTableModelProxy(TableModel model,
                String checkBoxColumnName, int checkBoxIndex) {
            if (model == null)
                throw new IllegalArgumentException("model can't be null");
            if (checkBoxIndex > model.getColumnCount())
                throw new IllegalArgumentException(
                        "checkBoxIndex can't be greater than colunm size");
            this.tableModel = model;
            this.checkBoxColumnName = checkBoxColumnName;
            this.checkBoxIndex = checkBoxIndex < 0 ? 0 : checkBoxIndex;
            checkBitSet = new BitSet();
            model.addTableModelListener(new EventRedirector());
        }
    
        @Override
        public int getRowCount() {
            return tableModel.getRowCount();
        }
    
        @Override
        public int getColumnCount() {
            return tableModel.getColumnCount() + 1;
        }
    
        @Override
        public String getColumnName(int columnIndex) {
            if (columnIndex == checkBoxIndex)
                return checkBoxColumnName;
            else if (columnIndex > checkBoxIndex)
                return tableModel.getColumnName(columnIndex - 1);
            else
                return tableModel.getColumnName(columnIndex);
        }
    
        @Override
        public Class<?> getColumnClass(int columnIndex) {
            if (columnIndex == checkBoxIndex)
                return Boolean.class;
            else if (columnIndex > checkBoxIndex)
                return tableModel.getColumnClass(columnIndex - 1);
            else
                return tableModel.getColumnClass(columnIndex);
        }
    
        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            if (columnIndex == checkBoxIndex)
                return true;
            else if (columnIndex > checkBoxIndex)
                return tableModel.isCellEditable(rowIndex, columnIndex - 1);
            else
                return tableModel.isCellEditable(rowIndex, columnIndex);
        }
    
        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            if (columnIndex == checkBoxIndex)
                return checkBitSet.get(rowIndex);
            else if (columnIndex > checkBoxIndex)
                return tableModel.getValueAt(rowIndex, columnIndex - 1);
            else
                return tableModel.getValueAt(rowIndex, columnIndex);
        }
    
        @Override
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            if (columnIndex == checkBoxIndex){
                checkBitSet.set(rowIndex, (Boolean) aValue);
                fireTableChanged(new TableModelEvent(this, rowIndex, rowIndex, columnIndex));
            } else if (columnIndex > checkBoxIndex)
                tableModel.setValueAt(aValue, rowIndex, columnIndex - 1);
            else
                tableModel.setValueAt(aValue, rowIndex, columnIndex);
    
        }
    
        public int[] getCheckedIndexes() {
            int[] indexes = new int[checkBitSet.cardinality()];
            int nextIndex = -1;
            for (int n = 0; n < indexes.length; n++) {
                nextIndex = checkBitSet.nextSetBit(nextIndex + 1);
                indexes[n] = nextIndex;
            }
            return indexes;
        }
    
        private class EventRedirector implements TableModelListener {
            @Override
            public void tableChanged(TableModelEvent e) {
                int Column = e.getColumn();
                if (Column >= checkBoxIndex)
                    Column++;
                fireTableChanged(new TableModelEvent(CheckBoxTableModelProxy.this,
                        e.getFirstRow(), e.getLastRow(), Column, e.getType()));
                if (e.getType() != TableModelEvent.UPDATE//insert,delete
                        || e.getLastRow() == Integer.MAX_VALUE//fireTableDataChanged
                        || e.getLastRow() == TableModelEvent.HEADER_ROW) {//fireTableStructureChanged
                    checkBitSet.clear();
                    fireTableChanged(new TableModelEvent(
                            CheckBoxTableModelProxy.this, 0, getRowCount() - 1,
                            checkBoxIndex, TableModelEvent.UPDATE));
                }
            }
        }
    }

        使用很方便,new CheckBoxTableModelProxy(oldTableModel,checkBoxColumnName)就可以得到一个添加了选择列的AbstractTableModel,再将它添加到JTable中即可,当然,也可以指定这一列的添加位置(使用另一个构造方法)。

        需要注意的是,如果原来的TableModel有行被添加或删除,或整个TableModel发生了变化,那么该Model中的选择列将被清空,如果只是单元格或行的数据更新,不会发生此问题,具体细节可查看EventRedirector。

        一直对设计模式的分类不太感冒,不知道这里使用的是不是代理模式。

        若对源码有疑问,欢迎提问或讨论。

        玩Swing的人已经很少了,如果该文章对你有用,还请推荐或留言支持一下,也算是给予我继续下去的动力。(PS:如果感兴趣的人多,接下来我把那个显示JTextArea行数(自动换行时的逻辑行数)的组件发出来)

  • 相关阅读:
    第一个JAVA程序
    python小项目(python实现鉴黄)源码
    整蛊小病毒,自己拿来快乐
    JavaScript(这里主要侧重于 JavaScript HTML DOM)杂项
    图片与文本基础(html和css)
    CSS的基础学习
    Javascript中this作用域以及bind方法的重写
    斐波那契数列算法求解及速度
    javascript中的描述对象(Descriptor)获取和定义随笔
    vue-cli3生产环境和开发环境路径的替换
  • 原文地址:https://www.cnblogs.com/trytocatch/p/3052301.html
Copyright © 2011-2022 走看看