0

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;
    }
}
  • 2
    You could start by providing a [ssccee](http://sscce.org/) – MadProgrammer Aug 18 '13 at 21:27
  • Your question would have been answered in a matter of minutes if only you had provided an ssccee or at least the `MyTableModel` constructor and the stacktrace of your error, right from the start. [If you ask a vague question, you’ll get a vague answer](http://stackoverflow.com/help/how-to-ask) – c.s. Aug 19 '13 at 07:51
  • i updated post, with what I did so far – Isaac Tobin Aug 19 '13 at 08:39

3 Answers3

3

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);
    }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • I put inside my empty constructor, `TableColumn column = new TableColumn(); column.setModelIndex(0); column.setHeaderValue("String value"); this.addColumn(column);` but didn't showed anything – Isaac Tobin Aug 18 '13 at 21:51
  • whats this.addColumn(column); you extending JTable as class, – mKorbel Aug 18 '13 at 21:54
  • I'm extending DefaultTableModel into my MyTableModel class – Isaac Tobin Aug 18 '13 at 21:55
  • As I said above, I want to have inside my table already initialized three columns with values. So, if I want to do that, I have to do that in my MyTableClass which exetends DefaultTableModel, so I guess I should do inside my constructor, which is fine, but I get an exception. – Isaac Tobin Aug 18 '13 at 21:58
  • aaach still I can't found any reason to override DefaultTableModel, see my edit – mKorbel Aug 18 '13 at 21:59
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/35709/discussion-between-isaac-tobin-and-mkorbel) – Isaac Tobin Aug 18 '13 at 22:01
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.

c.s.
  • 4,786
  • 18
  • 32
  • Sorry, I hope now you can try something, I modified my topic post and updated it with all code, so you can see where's the problem. – Isaac Tobin Aug 19 '13 at 12:40
  • Yea that works, I will definitely be using AbstractTableModel. However, can you chat me via stackoverflow, I got two more questions related to this topic, about the way of creating a method for adding a column? – Isaac Tobin Aug 19 '13 at 19:35
  • 1
    @IsaacTobin write your questions and I will update my answer. Or even better make a new question and come here and leave a comment so I don't miss it – c.s. Aug 19 '13 at 19:52
  • So first question, I exteneded as you have said AbstractTableModel, so I can use this methods which I've created, and which method do you want me to create now, for adding this three columns with data inside a constructor, about which we were talking above, I mean what way should I do it? – Isaac Tobin Aug 19 '13 at 20:04
  • And second question is, should I use 2D ArrayList (not sure if that's the way u call it) I mean like `private ArrayList> data;` is that ok, or I will just need 1D ArrayList, because I'm not going to remove rows, the way I'm removing is column and for that column all his rows (i mean his results) ? – Isaac Tobin Aug 19 '13 at 20:17
  • @IsaacTobin You can start simple and then change if you need to. The good thing of having a model is that it hides the details of what data structures are used to store the data. See update 2 in my answer – c.s. Aug 19 '13 at 20:46
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/35803/discussion-between-isaac-tobin-and-c-s) – Isaac Tobin Aug 19 '13 at 21:31
  • I would give him +100 if I could ;) – Isaac Tobin Aug 20 '13 at 12:08
0

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.

Raman Lalia
  • 245
  • 1
  • 5
  • I tried that, like super(INPUT_COLUMN_COUNT, INPUT_ROW_COUNT); but didn't worked, i still get the same exception – Isaac Tobin Aug 18 '13 at 21:37