这是我在StackOverflow中的第一篇文章。
我没有在JTable上找到SSCCE,其行单元格包含JRadioButton的 - 在几个(不是全部)列中,连续的列并不总是每行的相同列 - 并且其ButtonGroup与行对应。 所以我在“如何使用表格 - http://docs.oracle.com/javase/tutorial/uiswing/components/table.html”中重新审视了渲染器和编辑器的主题后,尝试详细说明了这一点。 并在研究了以下讨论之后: - 将JRadioButton(一列)添加到JTable Adding jRadioButton into jTable(Guillaume Polet) - 如何在JTable How to add JRadioButton to group in JTable
中将JRadioButton添加到组中我利用...... - 摇摆 - TableCellEditor和TableCellRenderer - Beans.PropertyChangeSupport,PropertyChangeListener
我的Java代码有效......但行为错误且不完整。 即使正在进行的功能 - 我认为 - 对于许多Java程序员来说都是非常感兴趣的。
个人风格规则:Java,Swing,......中的所有语法单词:英语,如库中一样。所有其他项目,特别是我的应用程序:另一种语言;这里是法国人。
最后,这里是包含4个子类[RendeurEditeur_CelluleBoutonRadio],[MonModeleTable],[GestionnObjetsDUneRangee]和[MonObjet]的“One copy and paste”类文件[TestTable2]。有用。这个SSCCE要复制和粘贴420行:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractCellEditor;
import javax.swing.JFrame;
import javax.swing.JRadioButton;
// import javax.swing.ButtonGroup;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException; // main()
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
public class TestTable2
{
private JFrame cadre;
private JTable table;
protected void initUI()
{
table = new JTable(new MonModeleTable());
short nbreColo = (short) table.getColumnCount();
table.setRowHeight(25);
TableColumn col;
// With Java, you can specify cell renderers and editors either by column or by data type.
for (int i = 0 ; i < nbreColo ; i++)
{
col = table.getColumnModel().getColumn(i);
col.setCellEditor (new RendeurEditeur_CelluleBoutonRadio());
col.setCellRenderer(new RendeurEditeur_CelluleBoutonRadio());
}
cadre = new JFrame();
cadre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cadre.add(new JScrollPane(table), BorderLayout.CENTER);
cadre.pack();
cadre.setVisible(true);
}
/**
* @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 TestTable2().initUI();
}
} );
}
private class RendeurEditeur_CelluleBoutonRadio extends AbstractCellEditor
implements TableCellRenderer, TableCellEditor, ActionListener
{
private final JRadioButton radioButton;
public RendeurEditeur_CelluleBoutonRadio()
{
this.radioButton = new JRadioButton();
radioButton.addActionListener(this);
radioButton.setOpaque(false);
}
@Override public Component getTableCellRendererComponent(JTable table, Object valeur,
boolean estSelectionne, boolean hasFocus, int row, int column)
{
radioButton.setSelected(Boolean.TRUE.equals(valeur));
return radioButton;
}
@Override public Component getTableCellEditorComponent(JTable table, Object valeur,
boolean estSelectionne, int row, int column)
{
radioButton.setSelected(Boolean.TRUE.equals(valeur));
return radioButton;
}
@Override public void actionPerformed(ActionEvent e)
{
stopCellEditing();
}
@Override public Object getCellEditorValue()
{
return radioButton.isSelected();
}
}
/**
*
*/
class MonModeleTable extends AbstractTableModel implements PropertyChangeListener
{
// Manages the rows of radioButtons and their groupings.
private GestionnObjetsDUneRangee gestionn_DonneesDUneRang;
private final List<GestionnObjetsDUneRangee> gestionn_DonneesTteLatable = new ArrayList<>();
public MonModeleTable()
{
super(); // AbstractTableModel()
MonObjet objet;
for (short idxRang = 0 ; idxRang < 5 ; idxRang++)
{
gestionn_DonneesDUneRang = new GestionnObjetsDUneRangee();
/* To record 'this' (= MonModeleTable) as listener of the messages sent
* by the object ...
* - to which a property (gestionn_DonneesDUneRang) of 'MonModeleTable'-itself
* refers to, and
* - pertaining to a class (GestionnObjetsDUneRangee) containing a property (suppoChangePropri)
* refering to an instanciation of PropertyChangeSupport. This later has as argument
* the object of class 'GestionnObjetsDUneRangee'. */
// Leaking 'this' in constructor : Passing suspicious parameter in the constructor.
gestionn_DonneesDUneRang.getSuppoChangePropri().addPropertyChangeListener(this);
for (short idxColo = 0 ; idxColo < 4 ; idxColo++)
{
objet = new MonObjet(idxRang, idxColo);
gestionn_DonneesDUneRang.ajoutObjetÀRangee(objet);
if (idxColo == 0)
objet.setSelectionne(true);
/* To record 'MonModeleTable' as listener of the messages sent by each
* object of the list 'gestionn_DonneesDUneRang'.*/
objet.getSupportChangtPropri().addPropertyChangeListener(this);
}
gestionn_DonneesTteLatable.add(gestionn_DonneesDUneRang);
}
}
// Rem.: Identity of the object's row and column (JRadioButton) available in 'evt.getSource();'.
@Override public void propertyChange(PropertyChangeEvent evt)
{
System.out.print(evt.getPropertyName() + "\t");
Object objet2 = evt.getSource();
if (objet2 == gestionn_DonneesDUneRang)
{
if (evt.getPropertyName().equals("objecten")) // MonModeleTable
{
((MonObjet) evt.getNewValue()).getSupportChangtPropri().addPropertyChangeListener(this);
}
fireTableDataChanged();
System.out.println("");
} else if (objet2 instanceof MonObjet)
{ // When another button of the row has been activated ("geselecteerd")
short[] coordBP = ((MonObjet) objet2).getCoordBP();
fireTableRowsUpdated(coordBP[0], coordBP[0]); // [0] : 2 x row
System.out.println("");
}
}
@Override public int getColumnCount()
{
return gestionn_DonneesDUneRang.getObjetsDUneRangee().size();
}
@Override public int getRowCount()
{
return gestionn_DonneesTteLatable.size();
}
// Exporting non-public type through public API
public MonObjet getValueAt(int col)
{
return gestionn_DonneesDUneRang.getObjetsDUneRangee().get(col);
}
// Implements method from javax.swing.table.TableModel
@Override public Object getValueAt(int idxRang, int idxColo)
{
return getValueAt(idxColo).isSelectionne();
}
// This method can also import idxRang2 and idxColo2 in this class.
// Overrides method from javax.swing.table.AbstractTableModel
@Override public void setValueAt(Object bpActionne, int idxRang2, int idxColo2)
{
getValueAt(idxColo2).setSelectionne(Boolean.TRUE.equals(bpActionne));
}
// Overrides method from javax.swing.table.AbstractTableModel
@Override public boolean isCellEditable(int idxRang3, int idxColo3)
{
return true; // idxRang3 == 1;
}
/** There must be a specification of a renderer for the cells for the table not to invoke the
* table model's 'getColumnClass' method (which gets the data type of the column's cells). */
// Overrides method from javax.swing.table.AbstractTableModel
@Override public Class<?> getColumnClass(int rang)
{
return Object.class;
}
Class<?> getClasseDeCellule(int idxRang, int idxColo)
{
// To be modified.
return Object.class;
}
// Overrides method from javax.swing.table.AbstractTableModel
@Override public String getColumnName(int colo)
{ // Column titles
return "Col " + (colo + 1);
}
}
/** Bean.
*/
class GestionnObjetsDUneRangee
{
private List<MonObjet> objetsDUneRangee = new ArrayList<>();
// private final ButtonGroup groupeHorizBoutRad = new ButtonGroup();
private final PropertyChangeSupport suppoChangePropri = new PropertyChangeSupport(this);
// GestionnObjetsDUneRangee() { }
public void ajoutObjetÀRangee(MonObjet objet)
{
objetsDUneRangee.add(objet);
setGestionn_ObjetsDUneRangee2(objet);
suppoChangePropri.firePropertyChange("objecten", null, objet);
}
public List<MonObjet> getObjetsDUneRangee()
{
return objetsDUneRangee;
}
// ?
public void setObjetsDUneRangee2(List<MonObjet> objetsDUneRangee2)
{
List<MonObjet> ancienObjetsDUneRangee = objetsDUneRangee;
objetsDUneRangee = objetsDUneRangee2;
suppoChangePropri.firePropertyChange("objectenVanEenRij",
ancienObjetsDUneRangee, objetsDUneRangee);
}
// Method called from 'ajoutObjetÀRangee(...)' in this class.
void setGestionn_ObjetsDUneRangee2(MonObjet monObjet)
{
monObjet.gestionn_ObjetsDUneRangee = this;
monObjet.getSupportChangtPropri().firePropertyChange("dataVanEenRij", null, monObjet.gestionn_ObjetsDUneRangee);
}
// Puts all the JRadioButton's of a row in their right states (Only one selected)
public void miseàjourTousBP_Rangee(MonObjet myObject) // setSelectionne()
{
for (MonObjet obj : objetsDUneRangee)
{
obj.setSelectionne(myObject == obj);
}
}
GestionnObjetsDUneRangee getGestionn_ObjetsDUneRangee2(MonObjet monObjet)
{
return monObjet.gestionn_ObjetsDUneRangee;
}
PropertyChangeSupport getSuppoChangePropri()
{
return suppoChangePropri;
}
/*
public void
addPropertyChangeListener(PropertyChangeListener listener)
{
suppoChangePropri.addPropertyChangeListener(listener);
}
public void
removePropertyChangeListener(PropertyChangeListener listener)
{
suppoChangePropri.removePropertyChangeListener(listener);
}
*/
}
/**
* Bean
*/
class MonObjet
{
private boolean selectionne;
GestionnObjetsDUneRangee gestionn_ObjetsDUneRangee;
private final PropertyChangeSupport supportChangtPropri;
short[] coordBP = new short[2]; // idxRang and idxColo of the JRadioButton object
MonObjet(short idxRang, short idxColo)
{
supportChangtPropri = new PropertyChangeSupport(this);
coordBP[0] = idxRang;
coordBP[1] = idxColo;
}
PropertyChangeSupport getSupportChangtPropri()
{
return supportChangtPropri;
}
boolean isSelectionne()
{
return selectionne;
}
// Called by 'positionnerSelectionne(objet)' in 'gestionn_DObjetsDUneRang').
void setSelectionne(boolean selectionne2)
{
if (this.selectionne != selectionne2)
{ // Passes here only if a change of the state occured.
this.selectionne = selectionne2;
if (selectionne)
{ // Passes here only when the radiobutton just was activated.
// 'selectionne' of the object is already 'true'.
gestionn_ObjetsDUneRangee.miseàjourTousBP_Rangee(this);
}
supportChangtPropri.firePropertyChange("geselecteerd", !selectionne, selectionne);
}
}
short[] getCoordBP()
{
return coordBP;
}
public void setGestionn_ObjetsDUneRangee(GestionnObjetsDUneRangee gestionn_ObjetsDUneRangee2)
{
GestionnObjetsDUneRangee ancienGestionn_ObjetsDUneRangee = gestionn_ObjetsDUneRangee;
gestionn_ObjetsDUneRangee = gestionn_ObjetsDUneRangee2;
supportChangtPropri.firePropertyChange("ManagerObjectenVanEenRij",
ancienGestionn_ObjetsDUneRangee, gestionn_ObjetsDUneRangee2);
}
/*
public void addPropertyChangeListener(PropertyChangeListener listener)
{
supportChangtPropri.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener)
{
supportChangtPropri.removePropertyChangeListener(listener);
}
*/
}
}
}
问题:RadioButton位于其中一个刚被激活的行中,在激活的列中,也会发生变化。请运行我的代码观察。 在'MonModèleTable'中,'void propertyChange(PropertyChangeEvent evt)','objet2'的'gestionn_ObjetsDUneRangée'总是指最后一行。如何到达正确的'gestionn_ObjetsDUneRangée',我的意思是对应于刚刚激活的JRadioButton行的那个?
是否有专家同意此案件具有普遍意义,谁可以帮助我们(Guillaume Polet?)? 非常感谢提前。
注意:我正在使用JRE rev。 1.8.0_73和NetBeans IDE rev。 8.0.2。