Question

I created a class MyTableModel which extends DefaultTableModel. And what I want is, to have already initialized three columns with data. Inside a constructor of MyTableModel I set header/data values by calling this.addColumn("FIRST COL", FIRST_COL_VALUES); but I get this exception "Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0 >= 0", how do I fix this?

public MyTableModel () {
            // code below is what I tried so far to fix the exception

            //super(INPUT_ROW_COUNT, 1);
            // next three lines, is from what I expect to work, but instead I get exception
            //this.addColumn("First Column", FIRST_COL_VALUES);
            //this.addColumn("Second Column", SECOND_COL_VALUES);
            //this.addColumn("Third Column", THIRD_COL_VALUES);

            //TableColumn column = new TableColumn();
            //column.setModelIndex(0);
            //column.setHeaderValue("String value");
            //this.addColumn(column);
}

UPDATE:

public class Main {

    public Main() {
        Model model = new Model();
        Model.TTableModel tableModel = model.new TTableModel();
        Model.TComboBoxModel cBoxModel = model.new TComboBoxModel();

        View view = new View(tableModel, cBoxModel);    
        new Controller(view, model, tableModel, cBoxModel);
    }

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


import java.util.ArrayList;
import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import javax.swing.table.DefaultTableModel;

public class Model {

    private static final int ROW_COUNT = 8;
    private ArrayList<Object> columnsNames = new ArrayList<>();
    private Object[][] data = new Object[ROW_COUNT][0];
    private int columnIndex;

    public int getColumnIndex() {
        return columnIndex;
    }

    public void increaseColumnIndex() {
        columnIndex++;
    }

    public void decreaseColumnIndex() {
        columnIndex--;
    }

    public void displayArrayListObjects() {
        System.out.println(columnsNames);
    }

    class TTableModel extends DefaultTableModel {

        public TTableModel() {
            //super(new Object[][]{{1, 2, 3, 4, 5, 6, 7, 8}, {4, 5, 6, 7}},new String[]{"First", "Second", "Third"});
            this.addColumn("First", new Object[] {1, 2, 3, 4, 5, 6, 7, 8});
            this.addColumn("Second", new Object[] {1, 2, 3, 4, 5, 6, 7, 8});
            this.addColumn("Third", new Object[] {1, 2, 3, 4, 5, 6, 7, 8});
        }

        public void addColumn(String header) {
            columnsNames.add(header);
            fireTableStructureChanged();
        }

        public void removeColumn() {
            if (columnIndex >= 0 && columnIndex < getColumnCount()) {
                columnsNames.remove(columnIndex);
                fireTableStructureChanged();
            }
        }

        @Override
        public int getColumnCount() {
            return columnsNames.size();
        }

        @Override
        public String getColumnName(int column) {
            return columnsNames.get(column).toString();
        }

        @Override
        public int getRowCount() {
            if (data != null) {
               return data.length;
            }
            return 0;
        }

        @Override
        public Object getValueAt(int row, int col) {
            return data[row][col];
        }
    }

    class TComboBoxModel extends AbstractListModel implements ComboBoxModel {

        private Object selectedItem = null;
        private ArrayList<Object> itemList = new ArrayList<>();

        public void addItem(String item) {
            this.itemList.add(item);
            this.fireIntervalAdded(item, columnIndex, columnIndex);
        }

        public void removeItem() {
            if (columnIndex >= 0 && columnIndex < getSize()) {
                this.itemList.remove(columnIndex);
                this.fireIntervalRemoved(selectedItem, columnIndex, columnIndex);
            }
        }

        public void updateSelectedItem() {
            if (itemList.get(0) != null) {
                selectedItem = itemList.get(0);
            } else {
                if (selectedItem != null) {
                    selectedItem = null;
                    this.fireContentsChanged(selectedItem, -1, -1);
                }
            }
        }

        @Override
        public void setSelectedItem(Object anObject) {
            if ((selectedItem != null && !selectedItem.equals(anObject)) || selectedItem == null && anObject != null) {
                this.selectedItem = anObject;
                this.fireContentsChanged(anObject, -1, -1);
            }
        }

        @Override
        public Object getSelectedItem() {
            return selectedItem;
        }

        @Override
        public int getSize() {
            return columnsNames.size();
        }

        @Override
        public Object getElementAt(int index) {
            return columnsNames.get(index).toString();
        }


    }

}

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import mvc1.Model.TComboBoxModel;
import mvc1.Model.TTableModel;

public class Controller {

    private View view;
    private Model model;
    private Model.TTableModel tableModel;
    private Model.TComboBoxModel cBoxModel;

    public Controller(View view, Model model, TTableModel tableModel, TComboBoxModel cBoxModel) {
        this.view = view;
        this.model = model;
        this.tableModel = tableModel;
        this.cBoxModel = cBoxModel;

        this.view.addButtonListener(new ButtonActionListener());
    }

    class ButtonActionListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            String s = e.getActionCommand();
            switch (s) {
                case "Add New Column":
                    model.increaseColumnIndex();
                    tableModel.addColumn("Field " + model.getColumnIndex());
                    break;
                case "Remove Column":
                    if (model.getColumnIndex() != 0) {
                        model.decreaseColumnIndex();
                        tableModel.removeColumn();
                    } else {
                        view.displayErrorMessage("There is no column left to remove.");
                    }
                    break;
                case "Calculate Column":
                    model.displayArrayListObjects();
                    break;
                case "Final Results Of All Rows":
                    break;
            }
        }

    }

}

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

public class View {

    private JMenuBar menuBar;
    private JMenu menuFile;
    private JMenuItem newMenuItem;
    private JMenuItem exitMenuItem;
    private JMenu menuView;
    private JMenuItem aboutMenuItem;

    private JButton addNewColumnButton;
    private JButton removeColumnButton;
    private JButton calculateColumnButton;
    private JButton totalResultButton;

    private JLabel textLabel;
    private JTextField columnField;
    private JTextField finalResultField;
    private JComboBox columnListCB;
    private JTable table;

    public View(TableModel tableModel, ComboBoxModel cBoxModel) {
        JFrame frame = new JFrame("MVC");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.setJMenuBar(getMenuBarComponent());
        frame.add(getPanelComponents(tableModel, cBoxModel));

        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    void addMenuListener(ActionListener l) {
        newMenuItem.addActionListener(l);
        aboutMenuItem.addActionListener(l);
        exitMenuItem.addActionListener(l);
    }

    void addButtonListener(ActionListener l) {
        addNewColumnButton.addActionListener(l);
        removeColumnButton.addActionListener(l);
        calculateColumnButton.addActionListener(l);
        totalResultButton.addActionListener(l);
    }

    void displayErrorMessage(String errorMessage) {
        JOptionPane.showMessageDialog(null, errorMessage, "Error Message", JOptionPane.ERROR_MESSAGE);
    }

    void displayInfoMessage(String infoMessage) {
        JOptionPane.showMessageDialog(null, infoMessage, "Information Message", JOptionPane.INFORMATION_MESSAGE);
    }

    private JMenuBar getMenuBarComponent() {
        menuBar = new JMenuBar();

        menuFile = new JMenu("File");
        newMenuItem = new JMenuItem("New");
        menuFile.add(newMenuItem);
        menuFile.addSeparator();
        exitMenuItem = new JMenuItem("Exit");
        menuFile.add(exitMenuItem);

        menuView = new JMenu("View");
        aboutMenuItem = new JMenuItem("About Me");
        menuView.add(aboutMenuItem);

        menuBar.add(menuFile);
        menuBar.add(menuView);
        return menuBar;
    }

    private JPanel getPanelComponents(TableModel tableModel, ComboBoxModel cBoxModel) {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

        panel.add(centerPanel(tableModel), BorderLayout.CENTER);
        panel.add(southPanel(), BorderLayout.SOUTH);
        panel.add(eastPanel(cBoxModel), BorderLayout.EAST);
        return panel;
    }

    private JPanel centerPanel(TableModel tableModel) {
        JPanel centerPanel = new JPanel(new GridLayout());
        table = new JTable(tableModel);
        table.setPreferredScrollableViewportSize(new Dimension(450, 150));
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        centerPanel.add(new JScrollPane(table));
        return centerPanel;
    }

    private JPanel southPanel() {
        JPanel southPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 5));
        totalResultButton = new JButton("Final Results Of All Rows");
        southPanel.add(totalResultButton);

        textLabel = new JLabel("Total result:");
        southPanel.add(textLabel);

        finalResultField = new JTextField();
        finalResultField.setPreferredSize(new Dimension(50, 25));
        southPanel.add(finalResultField);
        return southPanel;
    }

    private JPanel eastPanel(ComboBoxModel cBoxModel) {
        JPanel eastPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 0));
        Box eastPanelBox = Box.createVerticalBox();

        addNewColumnButton = new JButton("Add New Column");
        addNewColumnButton.setAlignmentX(Box.CENTER_ALIGNMENT);
        eastPanelBox.add(addNewColumnButton);
        eastPanelBox.add(Box.createVerticalStrut(5));

        removeColumnButton = new JButton("Remove Column");
        removeColumnButton.setAlignmentX(Box.CENTER_ALIGNMENT);
        eastPanelBox.add(removeColumnButton);
        eastPanelBox.add(Box.createVerticalStrut(5));

        columnField = new JTextField();
        columnField.setAlignmentX(Box.CENTER_ALIGNMENT);
        columnField.setPreferredSize(new Dimension(130, 25));
        eastPanelBox.add(columnField);
        eastPanelBox.add(Box.createVerticalStrut(5));

        columnListCB = new JComboBox(cBoxModel);
        columnListCB.setAlignmentX(Box.CENTER_ALIGNMENT);
        eastPanelBox.add(columnListCB); // might need to remove
        eastPanelBox.add(Box.createVerticalStrut(5));

        calculateColumnButton = new JButton("Calculate Column");
        calculateColumnButton.setAlignmentX(Box.CENTER_ALIGNMENT);
        eastPanelBox.add(calculateColumnButton);
        eastPanel.add(eastPanelBox);
        return eastPanel;
    }
}
Was it helpful?

Solution 2

You don't provide any code so I can only guess that your FIRST_COL_VALUES etc are not initialized (perhaps an invalid length?) or perhaps you are replacing the model somewhere else in your code. Displaying 3 columns with data is as simple as can be seen below.

Note that this is a runnable example. If you provide a similar one for your code I would be able to explain in more detail what your error actually is.

package gui.table;

import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;

public class ThreeColumnDemo {

    public static class ThreeColumnModel extends DefaultTableModel {

        public ThreeColumnModel() {
            // Initialize with 3 rows 0 columns
            super(3, 0);

            // add columns with data for each row
            this.addColumn("First Column", new String[] {"Value1_1", "Value2_1", "Value3_1" });
            this.addColumn("Second Column", new String[] {"Value1_2", "Value2_2", "Value3_2" });
            this.addColumn("Third Column", new String[] {"Value1_3", "Value2_3", "Value3_3" });
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater( new Runnable() {

            @Override
            public void run() {
                JFrame window = new JFrame("3-column demo");
                window.setPreferredSize(new Dimension(600, 400));
                window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                JTable table = new JTable( new ThreeColumnModel() );

                // put the table in a scroll pane so column headers are visible
                window.add(new JScrollPane(table));
                window.pack();
                window.setLocationRelativeTo(null);
                window.setVisible(true);
            }
        });
    }
}

Update 1: You are not correctly extending the DefaultTableModel. When you call addColumn(...) during constructor, the parent inserts a new column name and while it tries to make room for the rows/columns it calls your methods like getColumnCount(), getColumnName() etc which you override. However your model does not use the underlying data of the parent but checks a new structure (an ArrayList) which is empty at the moment. So the parent object encounters incosistent behaviour (i.e. it just added a new column and getColumnCount() returns 0). Just comment out the following methods and your code will work: getColumnCount(), getColumnName(), getRowCount(), getValueAt().

Then you should decide what you want to do. DefaultTableModel has a data structure to store data. If you extend it use those structures and do not overide methods that perform the same behaviour with the parent just for the shake of it. You should extend it if you want to add some additional behaviour.

If on the other hand you want to use your own data structure and your own way to add/remove columns and rows then just extend AbstractTableModel.


Update 2: Regarding the AbstractTableModel and your questions: a model is what its name says. A way to model your data. You do the same thing when you use an Object[] or an array of arrays, or an ArrayList<Object> as in your case. That is a model but rather poor. The table model encapsulates an abstract data structure that can be anything that matches your needs no matter how complex (i.e. the JTree uses it to encapsulate a hierarchical structure of tree nodes).
All Swing components behave the same way: you update your model and use events (usually calling a fireXXX()) to notify the corresponding component to redraw itself.
So in your case if you need to add/remove columns then you should have a method addColumn/removeColumn that would be called externally i.e. after you create your table. The model will update its data internally and call the appropriate fireXXX methods. Regarding what data type you should use, use whatever is more convenient for you. In your example you are using Integer for data type so an Object[] or an Integer[] or the corresponding ArrayList make sense. If you use a more complicated data type you can even introduce a new Column class that would encapsulate the data. It can be as complicated as you need it to be.

OTHER TIPS

I created a class MyTableModel which extends DefaultTableModel. And what I want is, to have already initialized three columns with data. Inside a constructor of MyTableModel I set header/data values by calling this.addColumn("FIRST COL", FIRST_COL_VALUES); but I get this exception "Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0 >= 0", how do I fix this?

this is possible with override TableColumn

there are (with quite usefull methods, remove if isn't used)

TableColumn column = new TableColumn();
column.setCellRenderer(....);
column.setModelIndex(int);
column.setHeaderValue("String value");
column.setPreferredWidth(int);
columnModel.addColumn(column);

column = new TableColumn();
column.setCellRenderer(....);
column.setModelIndex(int);
column.setHeaderValue("String value");
column.setPreferredWidth(int);
columnModel.addColumn(column);

column = new TableColumn();
column.setCellRenderer(....);
column.setModelIndex(int);
column.setHeaderValue("String value");
column.setPreferredWidth(int);
columnModel.addColumn(column);

table.setColumnModel(columnModel);

EDIT, You could start by providing an SCCCE by @MadProgrammer, then for future readers only

import java.awt.*;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;

public class CheckBoxTable extends JPanel {

    public static final String[] COLUMNS = {"Purchased", "Item"};
    public static final String[] INITIAL_ITEMS = {"Milk", "Flour", "Rice", "Cooking Oil", "Vinegar"};
    private static final long serialVersionUID = 1L;
    private CheckBoxDefaultTableModel model = new CheckBoxDefaultTableModel(COLUMNS, 0, 0);
    private JTable table = new JTable(model);

    public CheckBoxTable() {
        setLayout(new BorderLayout(5, 5));
        add(new JScrollPane(table), BorderLayout.CENTER);
        for (int i = 0; i < INITIAL_ITEMS.length; i++) {
            Object[] row = {Boolean.FALSE, INITIAL_ITEMS[i]};
            model.addRow(row);
        }
    }

    private static void createAndShowUI() {
        JFrame frame = new JFrame("CheckBoxTable");
        frame.getContentPane().add(new CheckBoxTable());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                createAndShowUI();
            }
        });
    }
}

class CheckBoxDefaultTableModel extends DefaultTableModel {

    private static final long serialVersionUID = 1L;
    private int checkColumn;

    CheckBoxDefaultTableModel(Object[] columnNames, int rowCount, int checkColumn) {
        super(columnNames, rowCount);
        this.checkColumn = checkColumn;
    }

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

Inside the MyTableModel constructor, try calling this line before anything else:

super(ROW_COUNT, COLUMN_COUNT);

where ROW_COUNT and COLUMN_COUNT are the number of rows and columns, respectively, in your table.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top