Search code examples
javaswingjtablejradiobutton

How to set not editable JTable cells when JRadioButton is selected?


I have a JTable with some rows. How can i block edit row just when radiobutton unlock is selected? Below a small project to use as a working example

Update
ElencoPersoneFrame class

package test;
import java.awt.*;
import java.util.*;

import javax.swing.*;

public class ElencoPersoneFrame extends JFrame {
    private PersonaTableModel tableModel;
    private JTable table;
    private JScrollPane scrollPane;

    JRadioButton rdbtnFilm = new JRadioButton("Editable");
    JRadioButton rdbtnSerieTv = new JRadioButton("Not editable");
    public ElencoPersoneFrame()
    {
        super ("Elenco Persone");

        setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
        setSize(400, 250);

        ArrayList<Persona> listaPersone = new ArrayList<Persona>();
        listaPersone.add(new Persona("Mario", "Rossi", 1972, false));
        listaPersone.add(new Persona("Giacomo", "Bianchi", 1946, false));
        listaPersone.add(new Persona("Roberto", "Verdi", 1985, true));
        tableModel = new PersonaTableModel(listaPersone);
        table = new JTable(tableModel);
        scrollPane = new JScrollPane(table);

        JPanel rdpnl=new radioPanel();

        getContentPane().add(rdpnl, BorderLayout.NORTH);
        getContentPane().add(scrollPane, BorderLayout.CENTER);

    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                ElencoPersoneFrame f = new ElencoPersoneFrame();
                f.setVisible(true);
            }
        });
    }
}

Persona class

package test;
public class Persona 
{
        private String nome;
        private String cognome;
        private int annoNascita;
        private boolean disoccupato;

        /*costruttore*/
        public Persona(String nome, String cognome, int annoNascita, boolean disoccupato) {
            this.nome = nome;
            this.cognome = cognome;
            this.annoNascita = annoNascita;
            this.disoccupato = disoccupato;
        }

        public String getNome() { return nome; }
        public String getCognome() { return cognome; }
        public int getAnnoNascita() { return annoNascita; }
        public boolean isDisoccupato() { return disoccupato; }

        public void setNome(String nome) { this.nome = nome; }
        public void setCognome(String cognome) { this.cognome = cognome; }
        public void setAnnoNascita(int annoNascita) { this.annoNascita = annoNascita; }
        public void setDisoccupato(boolean disoccupato) { this.disoccupato = disoccupato; }
}

PersonaTableModel class

package test;
import java.util.ArrayList;
import javax.swing.table.AbstractTableModel;

public class PersonaTableModel extends AbstractTableModel 
{
    private ArrayList<Persona> listaPersone;

    public PersonaTableModel(ArrayList<Persona> listaPersone) {
        this.listaPersone = listaPersone;
    }

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

    public int getColumnCount() {
        return 4;
    }

    public String getColumnName(int column) {
        switch (column) {
            case 0: return "Nome";
            case 1: return "Cognome";
            case 2: return "Anno nascita";
            case 3: return "Disoccupato?";
        }

        return "";
    }

    public Class getColumnClass(int column) {
        switch (column) {
            case 0: return String.class;
            case 1: return String.class;
            case 2: return Number.class;    
            case 3: return Boolean.class;  
        }
        return Object.class;
    }

    public boolean isCellEditable(int row, int column) {
        return true;
    }

    public Object getValueAt(int row, int column) {
        Persona p = listaPersone.get(row);

        switch (column) {
            case 0: return p.getNome();
            case 1: return p.getCognome();
            case 2: return p.getAnnoNascita();   
            case 3: return p.isDisoccupato();   
        }

        return null;
    }

   public void setValueAt(Object value, int row, int column) 
   {
        Persona p = listaPersone.get(row);

        switch (column) 
        {
            case 0: p.setNome((String) value); break;
            case 1: p.setCognome((String) value); break;
            case 2: p.setAnnoNascita((Integer) value); break;   
            case 3: p.setDisoccupato((Boolean) value); break;   
        }
    }

    public void aggiungiPersona(Persona p) {
        listaPersone.add(p);
        int row = listaPersone.size() - 1;
        fireTableRowsInserted(row, row);
    }
}

radioPanel class

package test;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ButtonGroup;
import javax.swing.JPanel;
import javax.swing.JRadioButton;


public class radioPanel extends JPanel implements ActionListener 
{
    private JRadioButton unlock;
    private JRadioButton lock;
    private ButtonGroup rdgroup;

    public radioPanel()
    {
        rdgroup=new ButtonGroup();
        unlock = new JRadioButton("Editable");
        lock = new JRadioButton("Not editable");

        rdgroup.add(unlock);
        rdgroup.add(lock);
        rdgroup.setSelected(unlock.getModel(), true);

        this.add(unlock);   
        this.add(lock);

        lock.addActionListener(this);
        unlock.addActionListener(this);
    }

    @Override
    public void actionPerformed(ActionEvent e) 
    {
        if(e.getSource() == this.lock)
        {

        }

        if(e.getSource() == this.unlock)
        {

        }   
    }
}

Solution

  • So there doesn't seem to be (AFAIK) some magic method to set the table uneditable. What you can do though is create a method in your model, like setEditable(boolean), where you can set a class member boolean editable. Use the same field for isCellEditable. After you change the state, you should fire the table change. Something like

    class PersonaTableModel extends AbstractTableModel {
        ...
        private boolean editable = true;
    
        public boolean isEditable() {
            return editable;
        }
    
        public boolean isCellEditable(int row, int column) {
            return editable;
        }
    
        public void setEditable(boolean editable) {
            this.editable = editable;
            fireTableDataChanged();
        }
        ...
    }
    

    You'll also need to way for the ActionListener to get hold of the table model. So you can refactor your radio panel to something like

    class radioPanel extends JPanel {
        private JRadioButton unlock;
        private JRadioButton lock;
        private ButtonGroup rdgroup;
    
        ...
    
        public ButtonGroup getButtonGroup() {
            return rdgroup;
        }
    
        public AbstractButton getUnlock() {
            return unlock;
        }
    
        public AbstractButton getLock() {
            return lock;
        }
    }
    

    This way you can just get the radio buttons from anywhere and add the ActionListener. So you can change you main class code to something like:

    radioPanel rdpnl = new radioPanel();
    rdpnl.getUnlock().addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent e) {
            tableModel.setEditable(true);
        }
    });
    rdpnl.getLock().addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent e) {
            tableModel.setEditable(false);
        }
    });
    
    getContentPane().add(rdpnl, BorderLayout.NORTH);
    

    Tested, and seems to work as expected.


    Aside: Please make note of Java naming convention. Class names should begin with upper case letters i.e. radioPanelRadioPanel