Mehrere TableModels zu einem einzigen zusammenfügen

Aus Byte-Welt Wiki
Zur Navigation springenZur Suche springen

Mit folgendem Code kann man mehrere TableModels zu einem zusammenfügen, oder bestimmte Zeilen/Spaltenmengen aus einem bestehenden TableModel als ein neues, eigenständiges TableModel anbieten.
Trivialkram, aber immerhin braucht jemand, der das braucht, diesen Trivialkram dann nicht mehr selbst zu schreiben.

TableModelUtils.java

import java.util.*;
import javax.swing.event.*;
import javax.swing.table.*;

/**
 *
 * This class provides utility methods to create special TableModels
 * that are composed of other TableModels, or consist of selected
 * subsets of rows and columns of other TableModels
 */
class TableModelUtils {

    /**
     * Creates a TableModel that composes the given TableModels into
     * one. The number of rows of the resulting TableModel will be
     * the maximum of all row counts of the given TableModels
     *
     * @param tableModels The TableModels to combine
     * @return A TableModel combining the given TableModels
     */
    public static TableModel createCompoundTableModel(TableModel... tableModels) {
        return new CompoundTableModel(tableModels);
    }

    /**
     * Creates a new TableModel which represents the "sub-table" that is
     * described by the given row- and column indices
     *
     * @param tableModel The TableModel from which the given sub-table
     * should be taken
     * @param col0 The first column of the sub-table, i.e. index of the
     * column in the given TableModel that should be the column with
     * index 0 in the returned model
     * @param row0 The first row of the sub-table, i.e. index of the
     * row in the given TableModel that should be the row with
     * index 0 in the returned model
     * @param col1 The column index where the sub-table should end
     * @param row1 The row index where the sub-table should end
     * @return A sub-table of the given TableModel
     */
    public static RangeTableModel createSubTableModel(TableModel tableModel, int row0, int col0, int row1, int col1) {
        return new RangeTableModel(tableModel, row0, col0, row1, col1);
    }

    /**
     * Creates a TableModel that consists of the rows with the
     * given indices of the given TableModel
     *
     * @param tableModel The TableModel from which the rows
     * will be taken
     * @param indices The indices of the rows that should be
     * contained in the resulting TableModel
     * @return
     */
    public static TableModel createRowSelectionTableModel(TableModel tableModel, int... indices) {
        return new SelectionTableModel(tableModel, indices, null);
    }

    /**
     * Creates a TableModel that consists of the columns with the
     * given indices of the given TableModel
     *
     * @param tableModel The TableModel from which the columns
     * will be taken
     * @param indices The indices of the columns that should be
     * contained in the resulting TableModel
     * @return
     */
    public static TableModel createColumnSelectionTableModel(TableModel tableModel, int... indices) {
        return new SelectionTableModel(tableModel, null, indices);
    }

    /**
     * This class is a TableModel that combines several other TableModels
     */
    private static class CompoundTableModel implements TableModel {

        /**
         * The TableModels that are combined in this TableModel
         */
        private List<TableModel> tableModels;

        /**
         * Create a new CompoundTableModel, combining the given TableModels
         *
         * @param tableModels The TableModels to combine
         */
        public CompoundTableModel(TableModel... tableModels) {
            this.tableModels = new ArrayList<TableModel>(Arrays.asList(tableModels));
        }

        /**
         * {@inheritDoc}
         */
        public void addTableModelListener(TableModelListener tableModelListener) {
            for (TableModel tableModel : tableModels) {
                tableModel.addTableModelListener(tableModelListener);
            }
        }

        /**
         * {@inheritDoc}
         */
        public void removeTableModelListener(TableModelListener tableModelListener) {
            for (TableModel tableModel : tableModels) {
                tableModel.removeTableModelListener(tableModelListener);
            }
        }

        /**
         * {@inheritDoc}
         */
        public Class getColumnClass(int columnIndex) {
            for (TableModel tableModel : tableModels) {
                if (tableModel.getColumnCount() > columnIndex) {
                    return tableModel.getColumnClass(columnIndex);
                }
                columnIndex -= tableModel.getColumnCount();
            }
            throw new IllegalArgumentException("No column found for the given index");
        }

        /**
         * {@inheritDoc}
         */
        public int getColumnCount() {
            int columnCount = 0;
            for (TableModel tableModel : tableModels) {
                columnCount += tableModel.getColumnCount();
            }
            return columnCount;
        }

        /**
         * {@inheritDoc}
         */
        public String getColumnName(int columnIndex) {
            for (TableModel tableModel : tableModels) {
                if (tableModel.getColumnCount() > columnIndex) {
                    return tableModel.getColumnName(columnIndex);
                }
                columnIndex -= tableModel.getColumnCount();
            }
            throw new IllegalArgumentException("No column found for the given index");
        }

        /**
         * {@inheritDoc}
         */
        public int getRowCount() {
            int maxRowCount = -1;
            for (TableModel tableModel : tableModels) {
                maxRowCount = Math.max(maxRowCount, tableModel.getRowCount());
            }
            return maxRowCount;
        }

        /**
         * {@inheritDoc}
         */
        public Object getValueAt(int rowIndex, int columnIndex) {
            for (TableModel tableModel : tableModels) {
                if (tableModel.getColumnCount() > columnIndex) {
                    if (rowIndex < tableModel.getRowCount()) {
                        return tableModel.getValueAt(rowIndex, columnIndex);
                    } else {
                        return null;
                    }
                }
                columnIndex -= tableModel.getColumnCount();
            }
            throw new IllegalArgumentException("No column found for the given index");
        }

        /**
         * {@inheritDoc}
         */
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            for (TableModel tableModel : tableModels) {
                if (tableModel.getColumnCount() > columnIndex) {
                    if (rowIndex < tableModel.getRowCount()) {
                        tableModel.setValueAt(aValue, rowIndex, columnIndex);
                        return;
                    } else {
                        throw new IllegalArgumentException("No cell found for the given row index");
                    }
                }
                columnIndex -= tableModel.getColumnCount();
            }
            throw new IllegalArgumentException("No column found for the given index");
        }

        /**
         * {@inheritDoc}
         */
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            for (TableModel tableModel : tableModels) {
                if (tableModel.getColumnCount() > columnIndex) {
                    if (rowIndex < tableModel.getRowCount()) {
                        return tableModel.isCellEditable(rowIndex, columnIndex);
                    } else {
                        return false;
                    }
                }
                columnIndex -= tableModel.getColumnCount();
            }
            throw new IllegalArgumentException("No column found for the given index");
        }
    }

    /**
     * This class describes a TableModel which represents a selection
     * of rows and columns of another TableModel
     */
    private static class SelectionTableModel implements TableModel {

        /**
         * The TableModel from which the rows and columns are selected
         */
        private TableModel tableModel;

        /**
         * The selection of rows
         */
        private int rowSelection[];

        /**
         * The selection of columns
         */
        private int columnSelection[];

        /**
         * Creates a new SelectionTableModel, which selects the specified rows
         * and columns from the given TableModel. The selections may be null.
         * Then all rows/columns will be selected, respectively
         *
         * @param tableModel The TableModel from which the rows and columns are
         * selected
         * @param rowSelection The selection of rows
         * @param columnSelection The selection of columns
         */
        public SelectionTableModel(TableModel tableModel, int rowSelection[], int columnSelection[]) {
            this.tableModel = tableModel;
            if (rowSelection != null) {
                this.rowSelection = rowSelection.clone();
            } else {
                this.rowSelection = createSelectionFromSize(tableModel.getRowCount());
            }
            if (columnSelection != null) {
                this.columnSelection = columnSelection.clone();
            } else {
                this.columnSelection = createSelectionFromSize(tableModel.getColumnCount());
            }
        }

        /**
         * Creates a selection containing all indices from 0 to size-1
         *
         * @param size The size of the selection
         * @return The selection array
         */
        static int[] createSelectionFromSize(int size) {
            int selected[] = new int[size];
            for (int i = 0; i < selected.length; i++) {
                selected[i] = i;
            }
            return selected;
        }

        /**
         * Creates a selection containing all indices from min to max-1
         *
         * @param min The minimum value to be selected
         * @param max The maximum value to be selected
         * @return The selection array
         */
        static int[] createSelectionFromRange(int min, int max) {
            int selected[] = new int[max - min];
            for (int i = 0; i < selected.length; i++) {
                selected[i] = i + min;
            }
            return selected;
        }

        /**
         * {@inheritDoc}
         */
        public void addTableModelListener(TableModelListener tableModelListener) {
            tableModel.addTableModelListener(tableModelListener);
        }

        /**
         * {@inheritDoc}
         */
        public void removeTableModelListener(TableModelListener tableModelListener) {
            tableModel.removeTableModelListener(tableModelListener);
        }

        /**
         * {@inheritDoc}
         */
        public Class getColumnClass(int columnIndex) {
            return tableModel.getColumnClass(columnSelection[columnIndex]);
        }

        /**
         * {@inheritDoc}
         */
        public int getColumnCount() {
            return columnSelection.length;
        }

        /**
         * {@inheritDoc}
         */
        public String getColumnName(int columnIndex) {
            return tableModel.getColumnName(columnSelection[columnIndex]);
        }

        /**
         * {@inheritDoc}
         */
        public int getRowCount() {
            return rowSelection.length;
        }

        /**
         * {@inheritDoc}
         */
        public Object getValueAt(int rowIndex, int columnIndex) {
            return tableModel.getValueAt(rowSelection[rowIndex], columnSelection[columnIndex]);
        }

        /**
         * {@inheritDoc}
         */
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            tableModel.setValueAt(aValue, rowSelection[rowIndex], columnSelection[columnIndex]);
        }

        /**
         * {@inheritDoc}
         */
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return tableModel.isCellEditable(rowSelection[rowIndex], columnSelection[columnIndex]);
        }

    }

    /**
     * This class describes a TableModel which represents a range
     * of rows and columns of another TableModel
     */
    public static class RangeTableModel implements TableModel {

        /**
         * The TableModel from which the rows and columns are selected
         */
        private TableModel tableModel;

        /**
         * The TableModelListeners that have been added to this TableModel
         */
        private List<TableModelListener> tableModelListeners = new ArrayList<TableModelListener>();

        /**
         * The minimum row
         */
        private int minRow;

        /**
         * The maximum row
         */
        private int maxRow;

        /**
         * The minimum column
         */
        private int minColumn;

        /**
         * The maximum column
         */
        private int maxColumn;

        /**
         * Creates a new SelectionTableModel, which selects the specified rows
         * and columns from the given TableModel.
         *
         * @param tableModel The TableModel from which the rows and columns are
         * selected
         * @param minRow The row of the given model which will be row 0 in this
         * model
         * @param minColumn The column of the given model which will be column 0
         * in this model
         * @param maxRow The row of the given model which will be the last row
         * in this model
         * @param maxColumn The column of the given model which will be the last
         * column in this model
         */
        public RangeTableModel(TableModel tableModel, int minRow, int minColumn, int maxRow, int maxColumn) {
            this.tableModel = tableModel;
            this.minRow = minRow;
            this.maxRow = maxRow;
            this.minColumn = minColumn;
            this.maxColumn = maxColumn;
        }

        /**
         * Set the range that is displayed by this RangeTableModel.
         *
         * @param minRow The row of the given model which will be row 0 in this
         * model
         * @param minColumn The column of the given model which will be column 0
         * in this model
         * @param maxRow The row of the given model which will be the last row
         * in this model
         * @param maxColumn The column of the given model which will be the last
         * column in this model
         */
        public void setRange(int minRow, int minColumn, int maxRow, int maxColumn) {
            this.minRow = minRow;
            this.maxRow = maxRow;
            this.minColumn = minColumn;
            this.maxColumn = maxColumn;
            if (tableModelListeners.size() > 0) {
                TableModelEvent tableModelEvent = new TableModelEvent(this, TableModelEvent.HEADER_ROW);
                for (TableModelListener tableModelListener : tableModelListeners) {
                    tableModelListener.tableChanged(tableModelEvent);
                }
            }
        }

        /**
         * {@inheritDoc}
         */
        public void addTableModelListener(TableModelListener tableModelListener) {
            tableModel.addTableModelListener(tableModelListener);
            tableModelListeners.add(tableModelListener);
        }

        /**
         * {@inheritDoc}
         */
        public void removeTableModelListener(TableModelListener tableModelListener) {
            tableModel.removeTableModelListener(tableModelListener);
            tableModelListeners.remove(tableModelListener);
        }

        /**
         * {@inheritDoc}
         */
        public Class getColumnClass(int columnIndex) {
            return tableModel.getColumnClass(columnIndex + minColumn);
        }

        /**
         * {@inheritDoc}
         */
        public int getColumnCount() {
            return maxColumn - minColumn + 1;
        }

        /**
         * {@inheritDoc}
         */
        public String getColumnName(int columnIndex) {
            return tableModel.getColumnName(columnIndex + minColumn);
        }

        /**
         * {@inheritDoc}
         */
        public int getRowCount() {
            return maxRow - minRow + 1;
        }

        /**
         * {@inheritDoc}
         */
        public Object getValueAt(int rowIndex, int columnIndex) {
            return tableModel.getValueAt(rowIndex + minRow, columnIndex + minColumn);
        }

        /**
         * {@inheritDoc}
         */
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            tableModel.setValueAt(aValue, rowIndex + minRow, columnIndex + minColumn);
        }

        /**
         * {@inheritDoc}
         */
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return tableModel.isCellEditable(rowIndex + minRow, columnIndex + minColumn);
        }
    }
}

TableModelUtilsTest.java

import javax.swing.event.*;
import javax.swing.table.TableModel;
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;

/**
 * Test class for the TableModelUtils
 */
class TableModelUtilsTest extends JFrame {

    public static void main(String args[]) {
        new TableModelUtilsTest();
    }

    public TableModelUtilsTest() {
        super("TableModelUtils test");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        TableModel tm0 = new DefaultTableModel(
                new Object[][]{
                    {"tm0 c00", "tm0 c01", "tm0 c02"},
                    {"tm0 c10", "tm0 c11", "tm0 c12"},
                    {"tm0 c20", "tm0 c21", "tm0 c22"}},
                new Object[]{"tm0 h0", "tm0 h1", "tm0 h2"});

        TableModel tm1 = new DefaultTableModel(
                new Object[][]{
                    {"tm1 c00", "tm1 c01", "tm1 c02", "tm1 c03", "tm1 c04"},
                    {"tm1 c10", "tm1 c11", "tm1 c12", "tm1 c13", "tm1 c14"},
                    {"tm1 c20", "tm1 c21", "tm1 c22", "tm1 c23", "tm1 c24"},
                    {"tm1 c30", "tm1 c31", "tm1 c32", "tm1 c33", "tm1 c34"},
                    {"tm1 c40", "tm1 c41", "tm1 c42", "tm1 c43", "tm1 c44"}},
                new Object[]{"tm1 h0", "tm1 h1", "tm1 h2", "tm1 h3", "tm1 h4"});

        JPanel p = new JPanel();
        p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));

        p.add(createPanel("Input model 0", tm0));
        p.add(createPanel("Input model 1", tm1));
        p.add(createRangePanel(TableModelUtils.createSubTableModel(tm1, 0, 0, 4, 4)));
        p.add(createPanel("Compound of model 0 and model 1",
                TableModelUtils.createCompoundTableModel(tm0, tm1)));
        p.add(createPanel("Sub(1,1,4,4) of model 1",
                TableModelUtils.createSubTableModel(tm1, 1, 1, 4, 4)));
        p.add(createPanel("RowSelection(0,2,4) of model 1",
                TableModelUtils.createRowSelectionTableModel(tm1, 0, 2, 4)));
        p.add(createPanel("ColumnSelection(0,2,4) of model 1",
                TableModelUtils.createColumnSelectionTableModel(tm1, 0, 2, 4)));

        TableModel tableModel = null;
        tableModel = TableModelUtils.createCompoundTableModel(tm0, tm1);
        tableModel = TableModelUtils.createSubTableModel(tableModel, 1, 1, 4, 5);
        tableModel = TableModelUtils.createRowSelectionTableModel(tableModel, 0, 2);
        tableModel = TableModelUtils.createColumnSelectionTableModel(tableModel, 0, 2, 4);
        p.add(createPanel("<html>ColumnSelection(0,2,4) of "
                + "RowSelection(0,2) of "
                + "Sub(1,1,4,4) of "
                + "Compound of model 0 and model 1", tableModel));

        getContentPane().add(new JScrollPane(p));
        setSize(800, 300);
        setVisible(true);
    }

    private JPanel createPanel(String infoString, TableModel tableModel) {
        JPanel panel = new JPanel(new BorderLayout());
        JLabel label = new JLabel(infoString);
        panel.add(label, BorderLayout.NORTH);
        panel.add(new JScrollPane(new JTable(tableModel)), BorderLayout.CENTER);
        return panel;
    }

    private JPanel createRangePanel(final TableModelUtils.RangeTableModel tableModel) {
        JPanel panel = new JPanel(new BorderLayout());

        JPanel p = new JPanel(new BorderLayout());
        p.add(new JLabel("Selection of range"), BorderLayout.NORTH);

        JPanel controlPanel = new JPanel(new GridLayout(2, 0));

        final JSpinner minRow = createSpinner(0, 0, tableModel.getRowCount() - 1);
        final JSpinner minCol = createSpinner(0, 0, tableModel.getColumnCount() - 1);
        final JSpinner maxRow = createSpinner(tableModel.getRowCount() - 1, 0, tableModel.getRowCount() - 1);
        final JSpinner maxCol = createSpinner(tableModel.getColumnCount() - 1, 0, tableModel.getColumnCount() - 1);

        ChangeListener changeListener = new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                int minR = (Integer) minRow.getValue();
                int minC = (Integer) minCol.getValue();
                int maxR = (Integer) maxRow.getValue();
                int maxC = (Integer) maxCol.getValue();
                tableModel.setRange(minR, minC, maxR, maxC);
            }
        };

        minRow.addChangeListener(changeListener);
        minCol.addChangeListener(changeListener);
        maxRow.addChangeListener(changeListener);
        maxCol.addChangeListener(changeListener);

        controlPanel.add(new JLabel("Min. row", JLabel.CENTER));
        controlPanel.add(minRow);
        controlPanel.add(new JLabel("Min. col", JLabel.CENTER));
        controlPanel.add(minCol);
        controlPanel.add(new JLabel("Max. row", JLabel.CENTER));
        controlPanel.add(maxRow);
        controlPanel.add(new JLabel("Max. col", JLabel.CENTER));
        controlPanel.add(maxCol);

        p.add(controlPanel, BorderLayout.CENTER);
        panel.add(p, BorderLayout.NORTH);
        panel.add(new JScrollPane(new JTable(tableModel)), BorderLayout.CENTER);

        return panel;
    }

    private JSpinner createSpinner(int initial, int min, int max) {
        SpinnerModel model = new SpinnerNumberModel(initial, min, max, 1);
        JSpinner spinner = new JSpinner(model);
        return spinner;
    }
}

Nachbetrachtung

Eigentlich wär's ja noch schick, das ganze in dem Sinne "mächtiger" zu machen, dass man sowas wie die hintereinanderschaltbaren RowFilter (und entsprechende ColumnFilter) einbaut, aber ... da das ja keiner braucht....


--Marco13 27.08.2008, 19:39