jeudi 17 novembre 2016

"Checkbox editor" for JTable

What is the best way to add "checkbox editor" for JTable? So far I have a JTable that use custom AbstractTableModel and which use two collections for data: One is HashMap that add for each row checkbox with "false" value. Second collection framework is simple ArrayList with Integers. Also AbstractTableModel has custom method to delete selected rows from ArrayList and from AbstractTableModel. Problem is that if I "check" chceckBox in table, the checked value stays in same row. I think problem is in overriding setValueAt. My piece of code:

package checkboxeditor;

import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import javax.swing.JButton;

public class CheckBoxEditor extends JPanel {

    public CheckBoxEditor() {
        super(new BorderLayout());

        MyTableModel myTableModel = new MyTableModel();
        JTable table = new JTable(myTableModel);
        table.setFillsViewportHeight(true);

        JButton deleteBtn = new JButton("Delete selected rows");
        deleteBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                int rowCount = table.getRowCount();
                for (int i = rowCount - 1; i >= 0; i--) {
                    boolean checked = (boolean) table.getValueAt(i, 0);
                    if (checked) {
                        myTableModel.removeRow((int) table.getValueAt(i, 1));
                    }
                }
            }
        });
        add(deleteBtn, BorderLayout.PAGE_START);

        //Create the scroll pane and add the table to it.
        JScrollPane scrollPane = new JScrollPane(table);

        //Add the scroll pane to this panel.
        add(scrollPane, BorderLayout.CENTER);
    }

    class MyTableModel extends AbstractTableModel {

        // column names
        private String[] columnNames = {"#", "Number"};
        // check boxes
        HashMap<Integer, Boolean> checkBoxes = new HashMap();
        // data
        ArrayList<Integer> data = new ArrayList();

        public MyTableModel() {
            for (Integer i = 1; i < 6; i++) {
                data.add(i);
            }

        }

        public void removeRow(Integer numberToDelete) {
            int index = data.indexOf(numberToDelete);
            data.remove(numberToDelete);
            fireTableRowsDeleted(index, index);
        }

        public int getColumnCount() {
            return columnNames.length;
        }

        public int getRowCount() {
            return data.size();
        }

        public String getColumnName(int col) {
            return columnNames[col];
        }

        public Object getValueAt(int row, int col) {
            switch (col) {
                case 0:
                    Object value = checkBoxes.get(row);
                    return (value == null) ? false : value;
                case 1:
                    return data.get(row);
                default:
                    return "";
            }
        }

        /*
         * JTable uses this method to determine the default renderer/
         * editor for each cell.  If we didn't implement this method,
         * then the last column would contain text ("true"/"false"),
         * rather than a check box.
         */
        public Class getColumnClass(int col) {
            switch (col) {
                case 0:
                    return Boolean.class;
                default:
                    return Integer.class;
            }
        }

        /*
         * Don't need to implement this method unless your table's
         * editable.
         */
        public boolean isCellEditable(int row, int col) {
            //Note that the data/cell address is constant,
            //no matter where the cell appears onscreen.
            return (col == 0);
        }

        /*
         * Don't need to implement this method unless your table's
         * data can change.
         */
        public void setValueAt(Object value, int row, int col) {
            if (col == 0) {
                checkBoxes.put(row, (boolean) value);
            }
        }

    }

    /**
     * Create the GUI and show it. For thread safety, this method should be
     * invoked from the event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("TableDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        CheckBoxEditor newContentPane = new CheckBoxEditor();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}




Aucun commentaire:

Enregistrer un commentaire