Forum Stats

  • 3,815,606 Users
  • 2,259,059 Discussions
  • 7,893,185 Comments

Discussions

JTable of JRadioButtons, grouped by row

Chavadam
Chavadam Member Posts: 2
edited May 5, 2017 12:41PM in Swing

Good morning.

I'm new on this forum.

I need some help regarding a JTable with N' fixed columns of BigDecimal values first, then a variable number of columns of JRadioButtons, and N"  fixed columns of BigDecimal eventually. The variable groups of JRadioButtons are grouped per row.

(Short, Self Contained, Correct (Compilable) Example : http://sscce.org/). Reduced to a SSCCE, it is although a four-classes mini-application : XYExtensTable_SSCCE, MonModTable, GestionnObjetsDUneRangée, MonObjet - see below. I'm sure that the two last ones cannot contain the reason of my problem, as I also made such a table mini-app with a fixed number of JRadioButtons columns using these two last classes (GestionnObjetsDUneRangée, MonObjet), and it works well.

The issue : When a JRadioButton is clicked, no call to 'getTableCellEditorComponent' happens, and subsequently no change of the activated JRadioButton happens. Nevertheless, I think to be close to my goal.

So, let us concentrate on the two first classes of my minimized code (Hum! a SSCCE of two times up to 350 lines long ! But they include a lot of explaining comments) :


XYExtensTable_SSCCE[CODE]

package xyextenstable_sscce;

import java.awt.BorderLayout;

import java.awt.Component;

import java.awt.Dimension;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import javax.swing.JFrame;

import javax.swing.AbstractCellEditor;

import javax.swing.JRadioButton;

import javax.swing.JScrollPane;

import javax.swing.JTable;

import javax.swing.table.DefaultTableCellRenderer;      // RenduCol3

import javax.swing.table.TableCellEditor;

import javax.swing.table.TableCellRenderer;

import javax.swing.table.TableColumn;

import javax.swing.JButton;

import javax.swing.GroupLayout;

import javax.swing.SwingConstants;          // CENTER

import javax.swing.SwingUtilities;

import javax.swing.UIManager;

import javax.swing.UnsupportedLookAndFeelException;     // main()

import javax.swing.event.*;             // TableModelListener, TableModelevent

import static xyextenstable_sscce.MonModTable.NBRE_FIXE_COL_AVANT;

import static xyextenstable_sscce.MonModTable.NBRE_FIXE_COL_APRES;

public class XYExtensTable_SSCCE extends JFrame implements ActionListener   // TableModelListener

{

    // <editor-fold defaultstate="collapsed" desc="Variables declarations">

    private /* final */ JTable table;

   /* Local variables 'renduCellBoutRad' and 'monModTable' are accessed from

    * within a inner class (JTable) --> needs to be declared final.       */

    private /* final */ MonModTable monModTable;

    private JScrollPane panDéroul_Table;

    private /* final */ JTable table;

    private TableColumn coloDeTable;

    private byte nbreColoTable;

    private static final byte LARGEUR_MAX_COL = 50;

    private int largTotTable;

    private int largTotTable_TtesRangées;

    private byte nbreColÀBR_AvantModif, nbreColÀBR;

    private JButton boutAjoutUneColon;

    private JButton boutRetraitUneColon;

            static final boolean DEBUG = false;

    // </editor-fold>

    protected void initUI()

    {  

        // <editor-fold defaultstate="collapsed" desc="Variables initialization">

        monModTable = new MonModTable(nbreColÀBR = 0, nbreColÀBR_AvantModif = 0);

        table = new JTable(monModTable)

        {  

            DefaultTableCellRenderer renduCell;

            RendEdit_CellBoutRad rendu_CellBoutRad;

            // Default constructor bloc of the JTable.

            {   // Method inherited from JLabel

                renduCell = new DefaultTableCellRenderer();

                renduCell.setHorizontalAlignment(SwingConstants.CENTER);

                rendu_CellBoutRad = new RendEdit_CellBoutRad();

                // setRowHeight(55);

                // Title width of each column

                largTotTable = 0;

                // = (byte) table.getModel().getColumnCount();

                nbreColoTable = (byte) monModTable.getColumnCount();

            }

            // Overrides method from javax.swing.JTable

            @Override public TableCellRenderer getCellRenderer(int rang, int col)

            {  

                if (col < NBRE_FIXE_COL_AVANT)

                    return renduCell;

                else

                if (col >= NBRE_FIXE_COL_AVANT && col < monModTable.colFinBoutRadio)

                    return rendu_CellBoutRad;

                else       

                if (col >= monModTable.colFinBoutRadio &&

                    col < NBRE_FIXE_COL_AVANT + nbreColÀBR + NBRE_FIXE_COL_APRES)

                    return renduCell;

                else

                    return null;      // Never

            }

           /* Prepares the renderer by querying the data model for the

            * value and selection state of the cell at row, column.

            * With Java, you can specify cell renderers and editors either

            * by column or by data type.       */

            @Override public Component prepareRenderer(

                    TableCellRenderer renduCelluleTableÀPréparer, int rang, int col)

            {   // The parent class of  'JTable' is 'javax.swing.JComponent'.

byte toRemove1 = 0;  // Only to be able to place here a breakpoint.

               /* For all the column cells that do not contain an object of type 'MonObjet' :

                * - 'renduCelluleTableÀPréparer' contains an object of type 'DefaultTableCellRenderer'.

                * - 'compos' contains an object of type 'DefaultTableCellRenderer'.

                * For all the column cells that do contain an object of type 'MonObjet' :

                * - 'renduCelluleTableÀPréparer' contains an object of type 'RendEdit_CellBoutRad'.

                * - 'compos' contains an object of type 'JRadioBouton'.      */

               /* Call of 'getValueAt()' in 'MonModTable' and of 'isSélectionné()" in 'MonObjet'   */

                final Component compos =

                        super.prepareRenderer(renduCelluleTableÀPréparer, rang, col);

                // compos.setBackground(Color.GRAY);

                return compos;

            }

            // Not used, apparently.

            @Override public void tableChanged(TableModelEvent e)

            {   // The parent class of 'JTable' is 'javax.swing.JComponent'.

                super.tableChanged(e);

                repaint();

            }

        };      // End of 'new JTable(...'

 

        panDéroul_Table = new JScrollPane(table);

        // panDéroul_Table.setViewportView(table);

        //  -     -     -     -     -     -     -     -     -     -     -

        boutAjoutUneColon = new JButton("Adding a column");

        boutAjoutUneColon.addActionListener(this);

        boutRetraitUneColon = new JButton("Removing a column");

        boutRetraitUneColon.addActionListener(this);

        //  -     -     -     -     -     -     -     -     -     -     -

        this.add(panDéroul_Table, BorderLayout.CENTER);

        this.add(boutAjoutUneColon, BorderLayout.NORTH);

        this.add(boutRetraitUneColon, BorderLayout.SOUTH);

        this.pack();

        this.setVisible(true);

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }   // End of the XYExtensTable_SSCCE constructor

        // </editor-fold>      // End of 'Variables initialization'

    // Push-buttons Add / remove a column.

    @Override public void actionPerformed(ActionEvent évé)

    {  

        nbreColoTable = (byte) table.getColumnModel().getColumnCount();

        nbreColÀBR = (byte) (nbreColoTable - (NBRE_FIXE_COL_AVANT + NBRE_FIXE_COL_APRES));

        nbreColÀBR_AvantModif = nbreColÀBR;

        if (évé.getSource() == boutAjoutUneColon)

        {

            miseÀJourModèleEtStructTable(++nbreColÀBR, nbreColÀBR_AvantModif);

            boutRetraitUneColon.setEnabled(true);

        }

        else

        if (évé.getSource() == boutRetraitUneColon)

        {

            if (nbreColÀBR <= 0)

                boutRetraitUneColon.setEnabled(false);

            else

            {

                miseÀJourModèleEtStructTable(--nbreColÀBR, nbreColÀBR_AvantModif);

                boutRetraitUneColon.setEnabled(true);

            }

        }

    }

   /** Updates the data in 'monModTable'

    * Note : table.getModel().addColumn(new TableColumn(libelléCol)); is only provisionned

    * by 'DefaultTableModel', not by 'AbstractTableModel'.

    * Cette méthode est appelée suite à l'actionnement de l'un des deux boutons-poussoirs.

    * @param nbreColÀBR5

    * @param nbreColÀBR_AvantModif5

    */

    public void miseÀJourModèleEtStructTable(byte nbreColÀBR5, byte nbreColÀBR_AvantModif5)

    {  

        this.remove(panDéroul_Table);

        this.remove(table.getTableHeader());

        this.revalidate();      // Tells Swing that an area of the window is dirty.

        // For this SSCCE, it is always one column at a time that is to be added or removed.

        byte nbreColÀAjouter = (byte) ((nbreColÀBR5 - nbreColÀBR_AvantModif5));

        // Last column of Radio-buttons after which the next one is to be inserted.

        byte idxDernColoBoutRad;

 

        if (nbreColÀAjouter > 0)

        {  

            monModTable = new MonModTable(nbreColÀBR5, nbreColÀBR_AvantModif5);

            table.setModel(monModTable);

           

            nbreColoTable = (byte) monModTable.getColumnCount();

            // With Java, you can specify cell renderers and editors either by column or by data type.

            for (idxDernColoBoutRad = NBRE_FIXE_COL_AVANT ;

                                  // = NBRE_FIXE_COL_AVANT + nbreColÀRB3

                 idxDernColoBoutRad < nbreColoTable - NBRE_FIXE_COL_APRES ;

                 idxDernColoBoutRad++)

            {

                coloDeTable = table.getColumnModel().getColumn(idxDernColoBoutRad);

                coloDeTable.setMaxWidth(30);

                // Different 'RendEdit_CellBoutRad' are needed for 'CellEditor' et 'CellRenderer'.

                // edit_CellBoutRad = new RendEdit_CellBoutRad();

                // jTable.getColumnModel().getColumn(1).setCellEditor(tableCellEditor);

                coloDeTable.setCellEditor  (new RendEdit_CellBoutRad());

                coloDeTable.setCellRenderer(new RendEdit_CellBoutRad());

            }

           

           /* The new column is always added to the extreme right of the table and must

            * consequently be moved to the first of the NBRE_FIXE_COL_APRES last columns. */

            table.moveColumn(nbreColoTable -1, idxDernColoBoutRad);

            // nbreColÀAjouter--;

           

    //        monModTable.fireTableDataChanged();

            monModTable.fireTableStructureChanged();

            // The functional grouping of radio-buttons is made by 'GestionnObjetsDUneRangée'.

/*        }   // End of 'if (nbreColÀAjouter > 0)'

        else if (nbreColÀAjouter < 0)      // Column(s) to be removed.

        {

            nbreColoTable = (byte) table.getColumnCount();

            idxDernColoBoutRad = (byte) (nbreColoTable - NBRE_FIXE_COL_APRES -1);

            coloDeTable = table.getColumn(idxDernColoBoutRad);

            monModTable.libellésColonnes.remove((int) (NBRE_FIXE_COL_AVANT + nbreRangées));

            table.removeColumn(coloDeTable);

            // Deselects the columns from index0 to index1, inclusive.

//            table.removeColumnSelectionInterval(

//                (int) NBRE_FIXE_COL_AVANT, (int)(NBRE_FIXE_COL_AVANT - nbreColÀAjouter));

        }

*/       

        panDéroul_Table.setViewportView(table);

        this.add(BorderLayout.CENTER, panDéroul_Table);

        this.repaint();         // Tells the layout manager to recalculate the layout.

    }

    /**

     * @param args the command line arguments

     * @throws ClassNotFoundException

     * @throws InstantiationException

     * @throws IllegalAccessException

     * @throws UnsupportedLookAndFeelException

     */

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException,

                                         IllegalAccessException, UnsupportedLookAndFeelException

    {

        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

        SwingUtilities.invokeLater(new Runnable()

        {

            @Override public void run()     // Implements method from java.lang.Runnable

            {

                new XYExtensTable_SSCCE().initUI();

            }

        }                         );

    }

        //  -     -     -     -     -     -     -     -     -     -     -

    // Not "extends JRadioButton".

            class RendEdit_CellBoutRad extends AbstractCellEditor

                implements TableCellRenderer, TableCellEditor, ActionListener

    {

        private final JRadioButton boutonRadio;

        public RendEdit_CellBoutRad()

        {

            this.boutonRadio = new JRadioButton();

            boutonRadio.addActionListener(this);    // Leaking 'this' in constructor.

            boutonRadio.setHorizontalAlignment(SwingConstants.CENTER);

            boutonRadio.setOpaque(false);

        }

       /* Implements the unique method from 'javax.swing.table.TableCellRenderer' interface.

        *

        * The object returned by 'getValueAt()' in 'MonModTable' is handled here.     */

        @Override public Component getTableCellRendererComponent(JTable table, Object valeur,

                            boolean estSélectionné, boolean aLeFocus, int rangée, int colonne)

        {

            boutonRadio.setSelected(Boolean.TRUE.equals(valeur));

            boutonRadio.setOpaque(true);

//            boutonRadio.setBackground(java.awt.Color.yellow);

            return boutonRadio;

        }

        // This method is called when a cell value is edited by the user. NEVER CALLED !

        // Implements method from 'javax.swing.table.TableCellEditor'.

        @Override public Component getTableCellEditorComponent(JTable table, Object valeur,

                                             boolean estSélectionné, int rangée, int colonne)

        {

            boutonRadio.setSelected(Boolean.TRUE.equals(valeur));

            return boutonRadio;

        }

        // Implements method from 'java.awt.event.ActionListener'.

        @Override public void actionPerformed(ActionEvent e)

        {  

            stopCellEditing();

        }

        // Implements method from 'javax.swing.CellEditor'. JTable or JTree

        @Override public Object getCellEditorValue()

        {   // 'isSelected()' is inherited from class javax.swing.AbstractButton .

            return boutonRadio.isSelected();        // boolean

        }

    }

}[/CODE]

MonModTable

[CODE]package xyextenstable_sscce;

import java.math.BigDecimal;

import java.util.List;          // Interface

import java.util.ArrayList;

import java.beans.PropertyChangeEvent;

import java.beans.PropertyChangeListener;

import javax.swing.table.AbstractTableModel;

// import static xyextenstable_sscce.XYExtensTable_SSCCE.DEBUG;

/** Swing doen't provide the possivility to implement a listener cell by cell.

* --> Implement a listener to the 'class XYExtensTable_SSCCE'. */

    class MonModTable extends AbstractTableModel implements PropertyChangeListener

{  

    // <editor-fold defaultstate="collapsed" desc="Variables declaration">

    private List<BigDecimal> échelleValeurs1eColonne;

    private byte nbreColÀBR3;

    private byte nbreColÀBR_AvantModif3;

    // Horizontally

    // Not 'private' because capability to remove items from XYExtenTable_SSCCE.

         List<String> libellésColonnes;

    public List<String> libelAutresColQueColÀBP;

    // Formats of the column contents : String, RendeurEditeur_CelluleBoutonRadio, BigDecimal

    public final List<Object> renduCellCol;

   /* 'idxRangée' in 'Elaborate the base of the data rows of the table' dans

    * 'élaborTtsRangéesTable()' doit être accessible dans '@Override propertyChange(evt)'. */

    private byte idxRangée;

    // Before and after the group of a variable number of columns to radio-buttons.

            static final byte NBRE_FIXE_COL_AVANT = 2;

            static final byte NBRE_FIXE_COL_APRES = 1;

//     private int colCommencementBoutRadio = NBRE_FIXE_COL_AVANT;

       /* For 'getColumnClass()', 'isCellEditable()', 'getValueAt()', 'setValueAt()'

        * and 'getCellRenderer()'.             */

                 int colFinBoutRadio = 0;

    // Contain and manage the rows of radio-buttons and their groupings.

    private List<GestionnObjetsDUneRangée> gestionnDonnéesTteLaTable;

    private GestionnObjetsDUneRangée gestionObjDUneRang;

    // </editor-fold>      // End of 'Variables initialization'

    MonModTable(byte nbreColÀBR2, byte nbreColÀBR_AvantModif2)

    {  

       /* Calls the constructor of 'AbstractTableModel'. This abstract class provides

        * default implementations for most of the methods in the TableModel interface.

        *

        * Not necessary because the required methods are implemented in this sub-class.

        */

        // super();

       /* For '@Override public Class<?> getColumnClass(int colo)', isCellEditable(),

        * 'élaborTtsRangéesTable()', ...        */

        this.nbreColÀBR3 = nbreColÀBR2;

        this.nbreColÀBR_AvantModif3 = nbreColÀBR_AvantModif2;

        // Instanciated here also, to avoid a 'NullPointerException' in 'getRowCount()'.

        gestionnDonnéesTteLaTable = new ArrayList<>();

        // Vertically

        libellésColonnes = new ArrayList<>();

        libellésColonnes.add("A");

        libellésColonnes.add("B");

        // Here in-between will come the colums of radio-buttons.

        libellésColonnes.add("Z");

        // Format of the column content - See 'ajustageLargeurCol()'

       /*  renduCellCol = new ArrayList(new Collection{"#.0", "#.00", "#.0"});  */

        renduCellCol = new ArrayList();

        renduCellCol.add("#.0");    // A

        renduCellCol.add("#.00");   // B

        // Here in-between will come the columns of radio-buttons.

        renduCellCol.add("#.0");    // C

        élaborTtsRangéesTable();    // Assign a return value to the new variable

    }

   /** Called

- during the initialization, in 'élaborTtsRangéesTable()', in the loop

accumulating the 'MonObjet's.

    */

    @Override public void propertyChange(PropertyChangeEvent evt)

    {

        Object objet2 = evt.getSource();

        if (objet2 == gestionObjDUneRang)

        {  

            switch (evt.getPropertyName())

            {   case "objetsDUneTranPuiss":

                    // 'supportChang_tPropri'

//                    ((MonObjet) evt.getNewValue()).getSupportChangtPropri_Obj().addPropertyChangeListener(this);

                    break;

            // MonModèleTable

                case "objectBijgevoegd":

                    // Constructor

                    break;

                case "objectenVanEenRij":

                    // Never passes here.

                    break;

            //    fireTableDataChanged();

                case "dataVanEenRij":

                    // Never passes here.

                    break;

            }

        } else

        if (objet2 instanceof MonObjet)

        {

            switch (evt.getPropertyName())

            {  case "juistVeranderd":

                    // Constructeur et utilisation

                    break;

                case "ObjMgrDezeRijIsBijgevoegd":

                    // Constructeur

                    break;

            }

            ;

//             int idx_Tran = gestionObjDUneRang.getObjetsDUneRangée().indexOf(objet2);

            // short[] coordBR = ((MonObjet) objet2).getCoordBP();

            // fireTableRowsUpdated(coordBR[0]-1, coordBR[0]-1);       // Only the concerned row.

        }

    }

   /** Method required by the 'AbstractTableModel' interface --> Name in English.

    * Implements method from javax.swing.table.TableModel

    * @return libellésColonnes.size()

    */

    @Override public int getColumnCount()

    {  

        return libellésColonnes.size();

        // return gestionObjDUneRang.getObjetsDUneRangée().size();

    }

   /** Methode required by the 'AbstractTableModel' interface.

    * 'gestionnDonnéesTteLaTable' must have been instanciated in the constructor method.

    * @return

    */

    @Override public int getRowCount()

    {  

        return gestionnDonnéesTteLaTable.size();

    }

    // Existing method but not required by the 'AbstractTableModel' interface.

    @Override public String getColumnName(int col)

    {  

        return libellésColonnes.get(col);

    }

   /** If you did not specify a renderer for a particular column, then the table

    * invokes the table model's getColumnClass method, which gets the data type

    * of the column's cells.

    * @param colo

    * @return

    */

    @Override public Class<?> getColumnClass(int idxColo1)

    {  

        if (idxColo1 < NBRE_FIXE_COL_AVANT)

        {

            return BigDecimal.class;

        } else

        if (idxColo1 >= NBRE_FIXE_COL_AVANT && idxColo1 < colFinBoutRadio)

        {

            return MonObjet.class;      // Contains a JRadioButton property.

        } else

        if (idxColo1 >= colFinBoutRadio &&

            idxColo1 < NBRE_FIXE_COL_AVANT + nbreColÀBR3 + NBRE_FIXE_COL_APRES)

        {

            return BigDecimal.class;

        } else           

        return null;      // Never passes here.

    }

    // Only the radio-buttons columns are editable.

    @Override public boolean isCellEditable(int rang, int idxColo2)

    {  

        if (idxColo2 < NBRE_FIXE_COL_AVANT)

            return false;

        else if (idxColo2 >= NBRE_FIXE_COL_AVANT && idxColo2 < colFinBoutRadio)

            return true;

        else if (idxColo2 >= colFinBoutRadio  &&

                 idxColo2 < NBRE_FIXE_COL_AVANT + nbreColÀBR3 + NBRE_FIXE_COL_APRES)

            return false;

        return false;       // Jamais

    }

   /** Method required by the 'AbstractTableModel' interdace.

    * The returned 'contCellTabl' will be handled by the method

    * 'TableCellRenderer.getTableCellRendererComponent (JTable table,

    * Object value, boolean isSelected, boolean hasFocus, int row, int column)'

    * in 'XYExtensTable_SSCCE'.

    * Renvoie un String ou un Boolean.      */

    @Override public Object getValueAt(int rang, int idxColo3)

    {  

        Object contCellTabl = getValeurÀ(rang, idxColo3);

        if (idxColo3 < NBRE_FIXE_COL_AVANT)

        {

            return contCellTabl;        // BigDecimal

        } else

        if (idxColo3 >= NBRE_FIXE_COL_AVANT && idxColo3 < colFinBoutRadio)

        {   // Bouton radio : Boolean       boolean --> Boolean

            if ((Class<?>)contCellTabl.getClass() == MonObjet.class)

            {

                Boolean étaitSélect_é = (Boolean)((MonObjet) contCellTabl).isSélectionné();

                return étaitSélect_é;

            }

        } else

        if (idxColo3 >= colFinBoutRadio  &&

                 idxColo3 < NBRE_FIXE_COL_AVANT + nbreColÀBR3 + NBRE_FIXE_COL_APRES)

        {

            return contCellTabl;        // BigDecimal

        }

        ;

        return null;

    }

   /** Need to implement this method because some table data can be manually changed.

    * Purpose : Activate or de- the radio-button of only one cell of the table.

   ¨* If it is activating it, the consequence for the other cellules of the row are

    * generated by the 'miseàjourTousBP_Rangée()' method in 'gestionnObjetsDUneRangée',

    * itself called here by 'setSélectionné()' in 'monObjet'.

    * Overrides method from javax.swing.table.AbstractTableModel

    */

    @Override public void setValueAt(Object bpActionné, int idxRang2, int idxColo4)

    {

        if (idxColo4 >= NBRE_FIXE_COL_AVANT && idxColo4 < colFinBoutRadio)

        {

            MonObjet contCellTabl = (MonObjet) getValeurÀ(idxRang2, idxColo4);

            contCellTabl.setSélectionné(Boolean.TRUE.equals(bpActionné));

        }

       /* It works without 'fireTableCellUpdated(..;)' if you change the data by

        * using the table editor, because once the editor is closed, the cell will

        * get repainted by the table.

        * However, if you manually invoke 'setValueAt()', then it won't work.

        * Also if you don't invoke that method, the 'no event' will be fired for

        * a TableModelListener that might be added to the TableModel.

        */

        fireTableCellUpdated(idxRang2, idxColo4);

    }

    // Method called by 'getValueAt() et 'setValueAt()'.

    Object getValeurÀ(int rang, int idxCol5)

    {   // There is [NBRE_RANG] gestionnObjetsDUneRangée in 'gestionnDonnéesTteLaTable'.

        return gestionnDonnéesTteLaTable.get(rang).getObjetsDUneRangée().get(idxCol5);

    }

    List<GestionnObjetsDUneRangée> getDonnéesTteLaTable()   // ArrayList<Object>

    {  

        return gestionnDonnéesTteLaTable;

    }

    //  -     -     -     -     -     -     -     -     -     -     -

   /** Method called in 'miseÀJourModèleEtStructTable()' or in 'MonModTable()'

    */

    private byte élaborTtsRangéesTable()

    {  

       /* For 'getColumnClass()', 'isCellEditable()', 'getValueAt()', 'setValueAt()'

        * and 'getCellRenderer()'.             */

        colFinBoutRadio = NBRE_FIXE_COL_AVANT + this.nbreColÀBR3;

//        byte nbreCellulesChaqueRangée = (byte)(colFinBoutRadio + NBRE_FIXE_COL_APRES);

        MonObjet objet;

        // System.gc();

        // <editor-fold defaultstate="collapsed" desc="To insert column labels to the radio-buttons columns">

        if (this.nbreColÀBR3 == this.nbreColÀBR_AvantModif3)

        {   // No column to add or to remove.

        } else

        if (this.nbreColÀBR3 > this.nbreColÀBR_AvantModif3)

        {  

            for (byte nièmeCol = 0 ; // (byte) nbreColÀBR_AvantModif3 ;

                                        nièmeCol < nbreColÀBR3 ; nièmeCol++)

            {  

                libellésColonnes.add(NBRE_FIXE_COL_AVANT + nièmeCol,

                                     ((Byte) nièmeCol).toString());

            //    renduCellCol.add(NBRE_FIXE_COL_AVANT + nièmeCol, "-");

            }

        } else      // End of 'if (nbreColÀBR3 > nbreColÀBR_AvantModif3)'

        // Suppressing a column

        if (this.nbreColÀBR3 < this.nbreColÀBR_AvantModif3)

        {  /* The necessary is done by 'ajoutRetraitCol(int pos, byte nbreColÀBR3,

            * List columnData)' dans 'XYExtensTable_SSCCE'               */

        };

        // End of "Adjust the number of columns of radio-buttons".

        // </editor-fold>

        // <editor-fold defaultstate="collapsed" desc="A series of dummy values for the first columns">

       /* Before making the ArrayList 'gestionObjDUneRangée', elaborate

        * the ArrayList 'échelleValeurs1eColonne'.        */

        BigDecimal uneValeur = new BigDecimal(10);

        final BigDecimal multiplicateur = new BigDecimal(1.414213);

        échelleValeurs1eColonne = new ArrayList<>(nbreColÀBR3);

        for (byte num = 0 ; num < (nbreColÀBR3 +1) ; num++)

        {  

            uneValeur = uneValeur.multiply(multiplicateur);

            échelleValeurs1eColonne.add(uneValeur);

        }

        byte nbreRangées = (byte) (échelleValeurs1eColonne.size() -1);

        // </editor-fold>

        // <editor-fold defaultstate="collapsed" desc="Elaborate the base of the data rows of the table">

       /* that is the 'gestionnDonnéesTteLaTable' list of all the 'gestionObjDUneRang' lists

        * of <nbreCellulesChaqueLigne> cellules, in function of the <nbreColÀBP> number.

        * 'Object' is 'MonObjet' when it concerns the dynamically added columns.     */

        gestionnDonnéesTteLaTable = new ArrayList<>(nbreRangées);

        // 'idxRangée' is also used in '@Override ... propertyChange(PropertyChangeEvent evt)

        for (idxRangée = 0 ; idxRangée < nbreRangées ; idxRangée++)

        {  

            gestionObjDUneRang = new GestionnObjetsDUneRangée(nbreColÀBR3);

           /* Support the changing properties.

            * Only 'monModTable' is registered as "listener" of all the properties of

            * - each instanciation of 'gestionObjDUneRang' (whose 'objetsDUneTranPuiss')

            * this in          of 'MonModTable' > '

            * - each instanciation of 'MonObjet', in 'propertyChange()'

            */

           /* For the 'suppChanProp_GestRang' property change support, own to this

            * 'gestionObjDUneRang', to record 'MonModTable' as listener (= Guêteur)

            * of any change of each property of  'gestionObjDUneRang'. */

            gestionObjDUneRang.ajoutGuêteurChangtPropri_GestRang(this);

            // First column

            // Decimal value of the secund cell of the preceding row.

            gestionObjDUneRang.getObjetsDUneRangée().add(échelleValeurs1eColonne.get(idxRangée));

            // Secund column

            gestionObjDUneRang.getObjetsDUneRangée().add(échelleValeurs1eColonne.get(idxRangée+1));

            // Between the secund and the last column

            for (byte col = NBRE_FIXE_COL_AVANT ; col < NBRE_FIXE_COL_AVANT + nbreColÀBR3 ; col++)

            {  

                objet = new MonObjet(idxRangée, col);

               /* For the 'suppChanProp_Obj' property change support, own to this new

                * 'objet', to record 'monModTable' as change listener of each property

                * of this new 'objet'.   */

                objet.ajoutGuêteurChangtPropri_Obj(this);

               /* Thanks to 'setGestionnObjetsDUneRangée(...)' in 'ajoutObjetÀRangée(...)'

                * in 'GestionnObjetsDUneRangée', the property 'gestionObjDUneRang2' in

                * 'contCellTabl' refers to 'gestionObjDUneRang' of here ('monModTable')   */

                gestionObjDUneRang.ajoutObjetÀRangée(objet);

            

                if (col == NBRE_FIXE_COL_AVANT)

                    objet.setSélectionné(true);

            }

            // Last column

            gestionObjDUneRang.getObjetsDUneRangée().add(BigDecimal.ZERO);

            gestionnDonnéesTteLaTable.add(gestionObjDUneRang);

        // The fireXxx() methods simply instruct the view to query the model via getValueAt().

//            fireTableStructureChanged();

        }   // End of "Elaborate the base of the data rows of the table"

        // </editor-fold>

        // fireTableStructureChanged();     // rather in 'miseÀJourModèleEtStructTable()'

        return nbreRangées;

    }

}[/CODE]

GestionnObjetsDUneRangée

[CODE]package xyextenstable_sscce;

import java.beans.PropertyChangeSupport;    // PropertyChangeEvent

import java.beans.PropertyChangeListener;

import java.util.ArrayList;

import java.util.List;

import static xyextenstable_sscce.MonModTable.NBRE_FIXE_COL_AVANT;

import static xyextenstable_sscce.MonModTable.NBRE_FIXE_COL_APRES;

// import static xyextenstable_sscce.XYExtensTable_SSCCE.DEBUG;

/**  Bean that support bound properties. (All Swing components are also beans)

Manages a list of listeners and dispatches PropertyChangeEvents to them.

A bound property notifies listeners when its value changes. This has two implications:

1. This bean class includes 'addPropertyChangeListener()' [and 'removePropertyChangeListener()'] methods for managing the bean's listener(s) (here only 'MonModTable').

2. When a bound property is changed (in 'GestionnObjetsDUneRangée gestionObjDUneRang'

and in each 'MonObjet objet' created in 'MonModTable'),

as well as at execution of 'propertyChangeSupport.firePropertyChange()',

the bean sends a PropertyChangeEvent to its registered listeners.

*/

public class GestionnObjetsDUneRangée

   /* Each row (objetsDUneRangée) contains 'BigDecimal's and 

    * a variable number of 'MonObjet' (containing a 'JRadioButton'). */

    private List<Object> objetsDUneRangée;

    private /* final */ PropertyChangeSupport suppChanProp_GestRang;

    private final byte nbreColÀBP1;

    GestionnObjetsDUneRangée(byte nbreColÀBP2)

    {   // 'nbreColÀBP1' only for 'miseàjourTousBR_Rangée()'.

        this.nbreColÀBP1 = nbreColÀBP2;

        objetsDUneRangée = new ArrayList<>(

                NBRE_FIXE_COL_AVANT + nbreColÀBP1 + NBRE_FIXE_COL_APRES);

        suppChanProp_GestRang = new PropertyChangeSupport(this);

    }

    public List<Object> getObjetsDUneRangée()

    {

        return objetsDUneRangée;

    }

    // Method called by ?

    void setObjetsDUneRangée(List<Object> objetsDUneRangée2)

    {

        List<Object> ancienObjetsDUneRangée = objetsDUneRangée;

        this.objetsDUneRangée = objetsDUneRangée2;

        suppChanProp_GestRang.firePropertyChange("objectenVanEenRij",

                                 ancienObjetsDUneRangée, objetsDUneRangée);

    }

   /* Method called

    * - in 'MonModTable' > 'élaborTtsRangéesTable()'

    * > 'Elaborate the base of the data rows of the table'   */

    void ajoutObjetÀRangée(Object objet)

    {  

        objetsDUneRangée.add(objet);

        // Puts in each object the reference to the object manager that contains it.

        if (objet != null)

        {

            ((MonObjet) objet).setGestionnObjetsDUneRangée(this);

/*            ((MonObjet) objet).getSupportChangtPropri().firePropertyChange("dataVanEenRij",

                                  null, ((MonObjet) objet).getGestionnObjetsDUneRangée());

*/

            suppChanProp_GestRang.firePropertyChange("objectBijgevoegd", null, (MonObjet) objet);

        }

    }

   /** Method called by 'setSélectionné()' in 'monObjet' and calls 'setSélectionné()'

    * (= re-intering method).

    * Puts all the radio-buttons of a row in their appropriate state.

    * 'MonObjet' does not know 'nbreColÀBP'; 'GestionObjDUneRang' does.

    * @param objetActionné

    */

    void miseàjourTousBR_Rangée(MonObjet objetActionné)

    {  

        MonObjet obj;

        for (byte j = NBRE_FIXE_COL_AVANT ; j < NBRE_FIXE_COL_AVANT + nbreColÀBP1 ; j++)

        {  

            obj = ((MonObjet) objetsDUneRangée.get(j));

            obj.setSélectionné(objetActionné == obj);

        }

    }

    PropertyChangeSupport getSuppoChangePropri_GestRang()

    {

        return suppChanProp_GestRang;

    }

    void ajoutGuêteurChangtPropri_GestRang(PropertyChangeListener guêteur)

    {

        suppChanProp_GestRang.addPropertyChangeListener(guêteur);

    }

    void retraitGuêteurChangePropri_GestRang(PropertyChangeListener guêteur)

    {

        suppChanProp_GestRang.removePropertyChangeListener(guêteur);

    }

}[/CODE]

MonObjet

[CODE]package xyextenstable_sscce;

import java.beans.PropertyChangeListener;

import java.beans.PropertyChangeSupport;

// import static xyextenstable_sscce.XYExtensTable_SSCCE.DEBUG;

/** Bean supporting bound properties.

* The common listening class ot 'MonObjet' is 'MonModTable' only.

*/

    class MonObjet

{  /* Delegating to 'suppChanProp_Obj' the management of a list of listeners

    * and the dispatching of 'PropertyChangeEvents'        */

    private boolean sélectionné;

    private GestionnObjetsDUneRangée gestionObjDUneRang;

    private final PropertyChangeSupport suppChanProp_Obj;

    public MonObjet(short idxRang, short idxColo)

    {  

        suppChanProp_Obj = new PropertyChangeSupport(this);

    }

    // The accessor method to be defined uses 'is...' instead of 'get...' because boolean.

    boolean isSélectionné()

    {

        return sélectionné;

    }

   /** Method called by

    * - the constructor of 'MonModTable()'.

    * - 'setValueAt()' in 'MonModTable()'.

    * - 'setSélectionné(objet)' in 'gestionnObjetsDUneRangée').

    *

    * @override setValueAt() > getValeurÀ(idxRang2, idxColo2)).setSélectionné() >

    * gestionObjDUneRang2.miseàjourTousBR_Rangée() > obj.setSélectionné()

    * miseàjourTousBR_Rangée()

    */

    void setSélectionné(boolean sélectionné2)

    {  

        if (this.sélectionné != sélectionné2)

        {   // Passes here only if there is a state change.

            this.sélectionné = sélectionné2;

            if (sélectionné == true)

            {   // Passes here only if the radio-button just changed to 'true'.

               /* 'gestionObjDUneRang' is an instanciated reference (not null) in the

                * constructor of 'MonModTable' by the call of 'gestionObjetsDUneRangée'.

                * ajoutObjetÀRangée()' containing the call to 'objet.setGestionnObjetsDUneRangée()'.

                */

                gestionObjDUneRang.miseàjourTousBR_Rangée(this);

            }

            suppChanProp_Obj.firePropertyChange("juistVeranderd", !sélectionné, sélectionné);

        }

    }

    // Method called by 'ajoutObjetÀRangée(Object objet)' in 'GestionnObjetsDUneRangée'.

    void setGestionnObjetsDUneRangée(GestionnObjetsDUneRangée gestionnObjetsDUneRangée2)

    {  

        GestionnObjetsDUneRangée ancienGestionnObjetsDUneRangée = gestionObjDUneRang;

       /* The purpose of a reference to the objet container (gestionObjDUneRang) 

        * being recorded in each object  is ...

        */

        this.gestionObjDUneRang = gestionnObjetsDUneRangée2;

        suppChanProp_Obj.firePropertyChange("ObjMgrDezeRijIsBijgevoegd",

                                ancienGestionnObjetsDUneRangée, gestionnObjetsDUneRangée2);

    }

    // Method called by 'ajoutObjetÀRangée(MonObjet objet)' in 'GestionnObjetsDUneRangée'.

    GestionnObjetsDUneRangée getGestionnObjetsDUneRangée()

    {

        return gestionObjDUneRang;

    }

    PropertyChangeSupport getSupportChangtPropri_Obj()

    {

        return suppChanProp_Obj;

    }

    // The listener (= "guêteur") is 'monModTable'

    void ajoutGuêteurChangtPropri_Obj(PropertyChangeListener guêteur)

    {

        suppChanProp_Obj.addPropertyChangeListener(guêteur);

    }

    void retraitGuêteurChangePropri_Obj(PropertyChangeListener guêteur)

    {

        suppChanProp_Obj.removePropertyChangeListener(guêteur);

    }

}[/CODE]

Cut, paste and compile it; it must work.

 

Additionnally and interestingly, as Swing objects make a suite of calls to '@Override ...' methods, I traced this suite of calls :

For my table of fixed number of JRadioButtons columns

which works entirely fine.

The activated radio-button before the new activation is in the 1st, and then in 2nd radio-button column of the 1st row.

The radio-button effectively activated is first the one of the 2nd raio-buttons column, then the one of the 1st r-b column.

It is the first time that I use this editor. Good grief ! It is impossible to cut and paste a formatted text (WordPad) in it !

I'll try to paste the 'sequences of method calls' later on.

This topic seems to be of wide interest to most of the users of JTable, isn't it ?

 

Thanks by advance for trying to help me.

 

I use Windows 10, Netbeans 8, ...

Answers

  • Chavadam
    Chavadam Member Posts: 2
    edited May 5, 2017 12:41PM

    Good evening.

    This rather is a trial to transmit the 'sequences of method calls' that could not be added in my (first) post of yesterday.

    Additionnally and interestingly, as Swing objects make a suite of calls to '@Override ...' methods, I traced this suite of calls :

    1) For this table of variable number of JRadioButtons columns     for which the JRadioButtons activation doesn't work.

    First manage for the table to display two columns of radio-buttons between the columns of BigDecimal values.

    The radio-button activated before the last actionning is the one in column of index 2 (3rd column), and in a secund time the one in column of index 3 (of row 1).

    The effectively actionnated radio-button is first the one of column of index 3, then of index 2.

    @ isCellEditable(0,3) MonModTable true

    @ getColumnClass(3) MonModTable MonObjet.class

    getCellRenderer(0,0) XYExtensTable_SSCCE renduCell

    prepareRenderer(0,0) XYExtensTable_SSCCE

    super.prepareRenderer(0,0) XYExtensTable_SSCCE

    getValueAt(0,0) MonModTable BigDecimal

    getCellRenderer(0,1) XYExtensTable_SSCCE renduCell

    prepareRenderer(0,1) XYExtensTable_SSCCE

    super.prepareRenderer(0,1) XYExtensTable_SSCCE

    getValueAt(0,1) MonModTable BigDecimal

    First radio-buttons column. So does not begin with the column

    whose a radio-button just has been activated = This is the issue.

    getCellRenderer(0,2) XYExtensTable_SSCCE rendu_CellBoutRad

    prepareRenderer(0,2) XYExtensTable_SSCCE

    super.prepareRenderer(0,2) XYExtensTable_SSCCE

    getValueAt(0,2) MonModTable

    isSélectionné() true

    The radio-button that just has been leaved ...

    @ getTableCellRendererComponent(true,0,2)

    boutonRadio.setSelected(true)

    getCellRenderer(0,3) XYExtensTable_SSCCE rendu_CellBoutRad

    prepareRenderer(0,3) XYExtensTable_SSCCE

    super.prepareRenderer(0,3) XYExtensTable_SSCCE

    getValueAt(0,3) MonModTable

    isSélectionné() false

    The radio-button that just was activated remains to 'false' !?

    @ getTableCellRendererComponent(false,0,3)

    boutonRadio.setSelected(false)

    getCellRenderer(0,4) XYExtensTable_SSCCE renduCell

    prepareRenderer(0,4) XYExtensTable_SSCCE

    super.prepareRenderer(0,4) XYExtensTable_SSCCE

    getValueAt(0,4) MonModTable BigDecimal

    Good grief, again, the identations are lost.

    For my table of fixed number of JRadioButtons columns     which works entirely fine.

    The activated radio-button before the new activation is in the 1st, and then in 2nd radio-button column of the 1st row.

    The radio-button effectively activated is first the one of the 2nd raio-buttons column, then the one of the 1st r-b column.

    @isCellEditable(0,1) MonModTable true

    Column whose radio-button just has been activated.

    @ getValueAt(0,1)(0,0) MonModTable

    isSélectionné() false

    @ getTableCellEditorComponent(false,0,1)(false,0,0) RendEdit_CellBoutRad

    boutonRadio.setSelected(false)

    @ setValueAt(0,1)(0,0) MonModTable

    getValeurÀ(0,1)(0,0)

    setSélectionné(true) MonObjet

    miseàjourTousBP_Rangée() GestionnObjetsDUneRangée

    [x the nbreCol] objetActionné == obj for the object of column 1, then of column 0.

    setSélectionné() MonObjet

    if false

    break;

    if true

    miseàjourTousBP_Rangée() GestionnObjetsDUneRangée

    setSélectionné() MonObjet GestionnObjetsDUneRangée

    firePropertyChange()

    actionPerformed() Table_NRangées_BoutRadio

    stopCellEditing() Table_NRangées_BoutRadio

     

    @ getCellRenderer(0,0)(0,0) Table_NRangées_BoutRadio

    @ prepareRenderer(0,0)(0,0) Table_NRangées_BoutRadio

    super.prepareRenderer(0,0)(0,0) Table_NRangées_BoutRadio

    @ getValueAt(0,0)(0,0) MonModTable

    isSélectionné() false

    The radio-button that just has been leaved, has just been put to 'false'.

    @ getTableCellRendererComponent(false,0,0)(true,0,0) Table_NRangées_BoutRadio

    boutonRadio.setSelected(false)(true) Table_NRangées_BoutRadio

     

    @ getCellRenderer(0,1)(0,1)

    @ prepareRenderer(0,1)(0,1)

    super.prepareRenderer(0,1)(0,1)

    @ getValueAt(0,1)(0,1)

    isSélectionné() true

    The radio-button that just has been activated, has been put to 'true'.

    @ getTableCellRendererComponent(true,0,1)(false,0,1)

    boutonRadio.setSelected(true)

     

    @ getCellRenderer(0,2)(0,2)

    @ prepareRenderer(0,2)(0,2)

    super.prepareRenderer(0,2)(0,2)

    @ getValueAt(0,2)(0,2)

    isSélectionné() false

    The not concerned radio-buttons remains to 'false'.

    @ getTableCellRendererComponent(false,0,2)(0,2)

    boutonRadio.setSelected(false)

     

    The column whose radio-button just has been activated.

    @ getCellRenderer(0,1)(0,0)

    @ prepareRenderer(0,1)(0,0)

    super.prepareRenderer(0,1)(0,0)

    @ getValueAt(0,1)(0,0)

    isSélectionné() true

    @ getTableCellRendererComponent(true,0,1)(true,0,0)

    boutonRadio.setSelected(true)

    -    -    -    -    -    -    -    -    -    -    -    -    -

    May I have confirmation of the following ?

    1) The initiator of a discussion (question) does not have the opportunity during a few days to make corrections or complete the content of his discussion 'à posteriori'.

    2) The editor does not enable ...

    - to insert code windows (taking into account the code identation and not inserting an additional 'return' to each code line)

    - to use tags ([CODE] and [/CODE] tags), url ([URL]), ...

    - to use tabs

    -    -    -    -    -    -    -    -    -    -    -    -    -

    Have a nice day.

This discussion has been closed.