Asked  7 Months ago    Answers:  5   Viewed   28 times

I have a JTable, that has one column that is text which is not editable and the second column is a check box that displays boolean values.... Now what i want is, when the user selects multiple rows and unchecks any one of the selected check boxes, then all the check boxes under selection should get unchecked and vice versa.

 Answers

24

Using @Hovercraft's example and @camickr's advice, the example below shows a suitable user interface. Although it uses buttons, the SelectionAction would also be suitable for a menu or popup.

Check A Bunch

import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.DefaultListSelectionModel;
import javax.swing.table.DefaultTableModel;

/** @see http://stackoverflow.com/questions/4526779 */
public class CheckABunch extends JPanel {

    private static final int CHECK_COL = 1;
    private static final Object[][] DATA = {
        {"One", Boolean.TRUE}, {"Two", Boolean.FALSE},
        {"Three", Boolean.TRUE}, {"Four", Boolean.FALSE},
        {"Five", Boolean.TRUE}, {"Six", Boolean.FALSE},
        {"Seven", Boolean.TRUE}, {"Eight", Boolean.FALSE},
        {"Nine", Boolean.TRUE}, {"Ten", Boolean.FALSE}};
    private static final String[] COLUMNS = {"Number", "CheckBox"};
    private DataModel dataModel = new DataModel(DATA, COLUMNS);
    private JTable table = new JTable(dataModel);
    private DefaultListSelectionModel selectionModel;

    public CheckABunch() {
        super(new BorderLayout());
        this.add(new JScrollPane(table));
        this.add(new ControlPanel(), BorderLayout.SOUTH);
        table.setPreferredScrollableViewportSize(new Dimension(250, 175));
        selectionModel = (DefaultListSelectionModel) table.getSelectionModel();
    }

    private class DataModel extends DefaultTableModel {

        public DataModel(Object[][] data, Object[] columnNames) {
            super(data, columnNames);
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            if (columnIndex == CHECK_COL) {
                return getValueAt(0, CHECK_COL).getClass();
            }
            return super.getColumnClass(columnIndex);
        }

        @Override
        public boolean isCellEditable(int row, int column) {
            return column == CHECK_COL;
        }
    }

    private class ControlPanel extends JPanel {

        public ControlPanel() {
            this.add(new JLabel("Selection:"));
            this.add(new JButton(new SelectionAction("Clear", false)));
            this.add(new JButton(new SelectionAction("Check", true)));
        }
    }

    private class SelectionAction extends AbstractAction {

        boolean value;

        public SelectionAction(String name, boolean value) {
            super(name);
            this.value = value;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            for (int i = 0; i < dataModel.getRowCount(); i++) {
                if (selectionModel.isSelectedIndex(i)) {
                    dataModel.setValueAt(value, i, CHECK_COL);
                }
            }
        }
    }

    private static void createAndShowUI() {
        JFrame frame = new JFrame("CheckABunch");
        frame.add(new CheckABunch());
        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();
            }
        });
    }
}
Tuesday, June 1, 2021
 
Taptronic
answered 7 Months ago
55

Here's an alternate approach to modifying the TableCellRenderer of a table's JTableHeader. It's not strictly necessary for this usage, but it minimizes the impact on the UI delegate's appearance.

Typical usage:

JTable table = new JTable(…);
JTableHeader header = table.getTableHeader();
header.setDefaultRenderer(new HeaderRenderer(table));

Custom header renderer:

private static class HeaderRenderer implements TableCellRenderer {

    DefaultTableCellRenderer renderer;

    public HeaderRenderer(JTable table) {
        renderer = (DefaultTableCellRenderer)
            table.getTableHeader().getDefaultRenderer();
        renderer.setHorizontalAlignment(JLabel.CENTER);
    }

    @Override
    public Component getTableCellRendererComponent(
        JTable table, Object value, boolean isSelected,
        boolean hasFocus, int row, int col) {
        return renderer.getTableCellRendererComponent(
            table, value, isSelected, hasFocus, row, col);
    }
}
Wednesday, June 9, 2021
 
footy
answered 6 Months ago
28

The default renderer and editor is typically adequate for most data types, but you can define custom renderers and editors as needed.

Addendum: I'm unfamiliar with the approach shown in your fragment. Instead, register a TableModelListener with your model, as shown below, and update the database with whatever granularity is warranted. See also How to Use Tables: Listening for Data Changes.

Addendum: @kleopatra is correct about your TableCellEditor. One convenient way to notify listeners is to invoke the super implementation, as shown here. Note that the delegate invokes fireEditingStopped().

/** @see https://stackoverflow.com/questions/9155596 */
public class NewJavaGUI extends JPanel {

    private final JTable table;

    public NewJavaGUI() {
        String[] colNames = {"C1", "C2", "C3"};
        DefaultTableModel model = new DefaultTableModel(colNames, 0) {

            @Override
            public boolean isCellEditable(int row, int col) {
                // return your actual criteria
                return true;
            }

            @Override
            public Class getColumnClass(int col) {
                // return your actual type tokens
                return getValueAt(0, col).getClass();
            }
        };
        // Add data; note auto-boxing
        model.addRow(new Object[]{"A1", "A2", 42});
        model.addRow(new Object[]{"B1", "B2", 42d});
        model.addTableModelListener(new TableModelListener() {

            @Override
            public void tableChanged(TableModelEvent e) {
                // DML as indicated
            }
        });
        table = new JTable(model);
        this.add(table);
    }

    private void display() {
        JFrame f = new JFrame("NewJavaGUI");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

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

            @Override
            public void run() {
                new NewJavaGUI().display();
            }
        });
    }
}
Saturday, July 31, 2021
 
maelgrove
answered 4 Months ago
66

Overriding prepareRenderer() is a recommended way to do custom rendering for an entire table row, but you can't make it do everything. In particular, the default renderer for Icon should do what you want, and there's no reason to override paint(), at all.

Addendum: Looking closer, your selected field appears empty because setOpaque(false) interferes with the optimization mentioned in the DefaultTableCellRenderer API. The example you copied won't work.

For reference, the example below overrides the getColumnClass() of DefaultTableModel to obtain the default renderer for types Icon and Date.

Java GUI

import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.util.Calendar;
import java.util.Date;
import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;

/** @see https://stackoverflow.com/questions/6873665 */
public class JavaGUI extends JPanel {

    private static final int ICON_COL = 0;
    private static final int DATE_COL = 1;
    private static final Icon icon = UIManager.getIcon("Tree.closedIcon");
    private final Calendar calendar = Calendar.getInstance();

    public JavaGUI() {
        CustomModel model = new CustomModel();
        JTable table = new JTable(model) {

            @Override
            public Component prepareRenderer(
                    TableCellRenderer renderer, int row, int column) {
                Component c = super.prepareRenderer(renderer, row, column);
                if (isRowSelected(row)) {
                    c.setBackground(Color.blue);
                } else {
                    c.setBackground(Color.white);
                }
                return c;
            }
        };
        for (int i = 1; i <= 16; i++) {
            model.addRow(newRow(i));
        }
        this.add(table);
    }

    private Object[] newRow(int i) {
        calendar.add(Calendar.DAY_OF_YEAR, 1);
        return new Object[]{icon, calendar.getTime()};
    }

    private static class CustomModel extends DefaultTableModel {

        private final String[] columnNames = {"Icon", "Date"};

        @Override
        public Class<?> getColumnClass(int col) {
            if (col == ICON_COL) {
                return Icon.class;
            } else if (col == DATE_COL) {
                return Date.class;
            }
            return super.getColumnClass(col);
        }

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

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

        @Override
        public boolean isCellEditable(int row, int column) {
            return false;
        }
    }

    private void display() {
        JFrame f = new JFrame("JavaGUI");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

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

            @Override
            public void run() {
                new JavaGUI().display();
            }
        });
    }
}
Thursday, August 5, 2021
 
Crashthatch
answered 4 Months ago
39

To be rendered as a JCheckBox by default, the table's model must return Boolean.class as the type for that column. If you are using DefaultTableModel, you will have to override getColumnClass() accordingly. Here's a related example.

Addendum: Note in the example that the editor's private instance of ValueRenderer can apply ItemEvent directly, instead of via setValueAt().

Addendum: The example has been updated to reflect the correct model-view workflow.

setValueAt() is called anyway. Verified it via debugging

If you step into setValueAt(), you'll see that "This empty implementation is provided so users don't have to implement this method if their data model is not editable."

Thursday, August 26, 2021
 
hakre
answered 3 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share