将包含标题和数据的列添加到MyTableModel

时间:2013-08-18 21:25:27

标签: java swing jtable defaulttablemodel

我创建了一个扩展DefaultTableModel的类MyTableModel。我想要的是,已经用数据初始化了三列。在MyTableModel的构造函数内部,我通过调用this.addColumn("FIRST COL", FIRST_COL_VALUES);来设置头/数据值,但是我得到了这个异常“线程中的异常”main“java.lang.ArrayIndexOutOfBoundsException:0> = 0”,我该如何解决这个问题? / p>

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);
}

更新

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;
    }
}

3 个答案:

答案 0 :(得分:3)

  

我创建了一个扩展DefaultTableModel的类MyTableModel。和   我想要的是,已经用数据初始化了三列。   在MyTableModel的构造函数内部,我设置了标头/数据值   调用this.addColumn(“FIRST COL”,FIRST_COL_VALUES);但我明白了   异常“线程中的异常”主“   java.lang.ArrayIndexOutOfBoundsException:0&gt; = 0“,我该如何解决这个问题?

这可以通过覆盖TableColumn

来实现

有(非常有用的方法,如果不使用则删除)

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);

编辑,您可以从@MadProgrammer提供SCCCE开始,然后仅为未来的读者提供

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);
    }
}

答案 1 :(得分:2)

您没有提供任何代码,因此我只能猜测您的FIRST_COL_VALUES等未初始化(可能是无效长度?),或者您可能正在替换代码中其他位置的模型。使用数据显示3列非常简单,如下所示。

请注意,这是一个可运行的示例。如果您为代码提供类似的代码,我将能够更详细地解释您的错误实际上是什么。

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);
            }
        });
    }
}

更新1:您未正确扩展DefaultTableModel。当您在构造函数中调用addColumn(...)时,父级会插入一个新列名称,当它尝试为行/列腾出空间时,它会调用您重写的方法,例如getColumnCount()getColumnName()等。但是,您的模型不使用父项的基础数据,而是检查此时为空的新结构(ArrayList)。因此父对象遇到不存在的行为(即它只添加了一个新列,getColumnCount()返回0)。只需注释掉以下方法,您的代码就可以运行:getColumnCount()getColumnName()getRowCount()getValueAt()

然后你应该决定你想做什么。 DefaultTableModel具有存储数据的数据结构。如果扩展它,请使用这些结构,并且不要覆盖与父进行相同行为的方法,只是为了摇动它。如果要添加一些附加行为,则应扩展它。

另一方面,如果您想使用自己的数据结构和自己的方式添加/删除列和行,则只需扩展AbstractTableModel


更新2:关于AbstractTableModel和您的问题:模型就是它的名字所说的。一种建模数据的方法。当您使用Object[]或数组数组或ArrayList<Object>时,您会执行相同的操作。这是一个模型,但相当差。表模型封装了一个抽象的数据结构,无论多么复杂(即JTree使用它来封装树节点的层次结构),它都可以满足您的需求。 所有Swing组件的行为方式相同:更新模型并使用事件(通常调用fireXXX())通知相应的组件重绘自己。
因此,在您的情况下,如果您需要添加/删除列,那么您应该有一个方法addColumn/removeColumn,可以在外部调用,即在创建表之后。该模型将在内部更新其数据并调用适当的fireXXX方法。关于您应该使用哪种数据类型,请使用更方便的方法。在您的示例中,您使用Integer作为数据类型,因此Object[]Integer[]或相应的ArrayList有意义。如果您使用更复杂的数据类型,您甚至可以引入一个新的Column类来封装数据。它可能会像您需要的那样复杂。

答案 2 :(得分:0)

MyTableModel构造函数中,尝试先调用此行:

super(ROW_COUNT, COLUMN_COUNT);

其中ROW_COUNTCOLUMN_COUNT分别是表格中的行数和列数。