如何将 JRadioButton 添加到 JTable 中的组 [英] How to add JRadioButton to group in JTable
问题描述
我使用渲染器和编辑器向 JTable
添加了单选按钮.我也为此创建了组.我无法使用此原则实现排他性(仅应选择 1 个单选按钮).请查看下面我的代码并感谢您的回复.
渲染器和编辑器类:
class RadioButtonRenderer 实现 TableCellRenderer {公共组件 getTableCellRendererComponent(JTable 表,对象值,boolean isSelected, boolean hasFocus, int row, int column) {如果(值 == 空)返回空;返回(组件)值;}}类 RadioButtonEditor 扩展 DefaultCellEditor 实现 ItemListener {私人 JRadioButton 按钮;公共单选按钮编辑器(JCheckBox 复选框){超级(复选框);}公共组件 getTableCellEditorComponent(JTable 表,对象值,boolean isSelected, int row, int column) {如果(值 == 空)返回空;按钮 = (JRadioButton) 值;button.addItemListener(this);返回(组件)值;}公共对象 getCellEditorValue() {button.removeItemListener(this);返回按钮;}public void itemStateChanged(ItemEvent e) {super.fireEditingStopped();}}
这是准备数据和完成分组的地方:
private void displayPhoneListShow(Person person) {DefaultTableModel dm = 新的 DefaultTableModel() {@覆盖public boolean isCellEditable(int row, int column) {返回真;}};对象[]对象=新对象[3];Object[] tableColumnNamesPhone = new Object[3];tableColumnNamesPhone[0] = "选择";tableColumnNamesPhone[1] = "电话号码";tableColumnNamesPhone[2] = "首选";dm.setColumnIdentifiers(tableColumnNamesPhone);ListIterator<电话>phoneList = person.getPhoneList().listIterator();而 (phoneList.hasNext()) {电话电话 = phoneList.next();objects[0] = new JRadioButton(("^"));对象[1] = phone.getPhoneNumber();对象[2] = phone.getPreferred();dm.addRow(对象);}this.phoneTable.setModel(dm);ButtonGroup 组 = new ButtonGroup();for (int row = 0; row < dm.getRowCount(); row++) {JRadioButton radio = (JRadioButton) dm.getValueAt(row, 0);group.add(radio);}phoneTable.getColumn("Select").setCellRenderer(新 RadioButtonRenderer());phoneTable.getColumn("Select").setCellEditor(new RadioButtonEditor(new JCheckBox()));}
我仍然无法达到结果.我还尝试将 ButtonGroup group = new ButtonGroup()
添加为类变量以及 RadioButtonRenderer
类的一部分,并向该组添加按钮.但结果无所谓.
请提出建议.
作为替代方案,使用 JComboBox
作为 的图,Mac OS X:
图来自@mKorbel 的 StatusRenderer
和 StatusEditor
,Windows:
图使用 DefaultTableCellRenderer
和 DefaultCellEditor
,Windows(见评论):
代码:
import java.awt.*;导入 java.awt.event.*;导入 java.text.DateFormat;导入 java.text.SimpleDateFormat;导入 java.util.Date;导入 java.util.Vector;导入 javax.swing.AbstractAction;导入 javax.swing.AbstractCellEditor;导入 javax.swing.BorderFactory;导入 javax.swing.ButtonGroup;导入 javax.swing.JFrame;导入 javax.swing.JPanel;导入 javax.swing.JRadioButton;导入 javax.swing.JScrollPane;导入 javax.swing.JSpinner;导入 javax.swing.JTable;导入 javax.swing.JToolBar;导入 javax.swing.SpinnerDateModel;导入 javax.swing.SwingUtilities;导入 javax.swing.table.AbstractTableModel;导入 javax.swing.table.DefaultTableCellRenderer;导入 javax.swing.table.TableCellEditor;导入 javax.swing.table.TableCellRenderer;导入 javax.swing.table.TableColumnModel;公共类 JRadioAsRendererEditor 扩展 JPanel {private static final String[] COLUMN_NAMES = {"List ID", "Expiration Date", "Status", "Date Created"};private static final DateFormat DATE_FORMAT = new SimpleDateFormat("dd/MM/yyyy");private static final DateFormat TIME_FORMAT_LONG = new SimpleDateFormat("HH:mm:ss,SSS");私人 MyTableModel tableModel;私有 JTable 表;私有 JFrame 框架 = new JFrame("TestRadioButtonRenderer");公共 JRadioAsRendererEditor() {超级(新的边框布局(0, 5));setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));tableModel = new MyTableModel();table = new JTable(tableModel);table.setDefaultEditor(Date.class, new DateEditor());table.setDefaultRenderer(Date.class, new DateRenderer());table.setDefaultEditor(Status.class, new StatusEditor());table.setDefaultRenderer(Status.class, new StatusRenderer());//注释前两行并为标准编辑器取消注释以下行//table.setDefaultEditor(Status.class, new DefaultCellEditor(//new JComboBox(new Status[]{Status.Single, Status.Married, Status.Divorced})));添加(新 JScrollPane(表),BorderLayout.CENTER);JToolBar toolBar = new JToolBar();toolBar.setFloatable(false);toolBar.add(new AbstractAction("Add new") {@覆盖public void actionPerformed(ActionEvent e) {tableModel.add(new TableEntry());包表();}});toolBar.add(new AbstractAction("Remove") {@覆盖public void actionPerformed(ActionEvent e) {tableModel.remove(table.getSelectedRow());}});frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.add(new JScrollPane(table), BorderLayout.CENTER);frame.add(toolBar, BorderLayout.NORTH);框架.pack();SwingUtilities.invokeLater(new Runnable() {@覆盖公共无效运行(){frame.setVisible(true);}});}私有无效包表(){TableColumnModel columnModel = table.getColumnModel();int columnCount = table.getColumnCount();int rowCount = table.getRowCount();int[][] preferredHeights = new int[columnCount][rowCount];TableCellRenderer 渲染器;组件组合;for (int col = 0; col < columnCount; col++) {渲染器 = columnModel.getColumn(col).getCellRenderer();如果(渲染器 == 空){渲染器 = table.getDefaultRenderer(tableModel.getColumnClass(col));}for (int row = 0; row < rowCount; row++) {comp = renderer.getTableCellRendererComponent(table,tableModel.getValueAt(row, col), false, false, row, col);preferredHeights[col][row] = (int) comp.getPreferredSize().getHeight();}}for (int row = 0; row < rowCount; row++) {INT偏好= 0;for (int col = 0; col < columnCount; col++) {pref = Math.max(pref, preferredHeights[col][row]);}table.setRowHeight(row, pref);}}公共静态无效主(字符串 [] args){SwingUtilities.invokeLater(new Runnable() {@覆盖公共无效运行(){JRadioAsRendererEditor tableTestPanel = new JRadioAsRendererEditor();}});}私人枚举状态{单身、已婚、离婚;}私有类 StatusPanel 扩展 JPanel {私人 JRadioButton theSingleOption;私人 JRadioButton theMarriedOption;私人 JRadioButton theDivorcedOption;私人按钮组按钮组 = 新按钮组();状态面板(){超级(新的网格布局(0, 1));设置不透明(真);theSingleOption = createRadio(Status.Single);theMarriedOption = createRadio(Status.Married);theDivorcedOption = createRadio(Status.Divorced);}私人 JRadioButton createRadio(状态状态){JRadioButton jrb = new JRadioButton(status.toString());jrb.setOpaque(false);添加(jrb);buttonGroup.add(jrb);返回 jrb;}公共状态 getStatus() {如果 (theMarriedOption.isSelected()) {返回状态.已婚;} else if (theDivorcedOption.isSelected()) {返回状态.离婚;} 别的 {返回 Status.Single;}}公共无效设置状态(状态状态){如果(状态 == 状态.已婚){theMarriedOption.setSelected(true);} else if (status == Status.Divorced) {theDivorcedOption.setSelected(true);} 别的 {theSingleOption.setSelected(true);}}}私有类 TableEntry {私有 int instanceNumber;私人长期身份;私人日期 theExpirationDate;私人状态状态;私人日期 theCreationDate;表条目(){实例编号++;theId = new Long(instanceNumber);theExpirationDate = 新日期();theStatus = Status.Single;theCreationDate = 新日期();}TableEntry(Long anId, Date anExpirationDate, Status aStatus, Date aCreationDate) {theId = anId;theExpirationDate = anExpirationDate;theStatus = aStatus;theCreationDate = aCreationDate;}公共长 getId() {返回Id;}公共日期 getExpirationDate() {返回到期日期;}公共状态 getStatus() {返回状态;}公共日期 getCreationDate() {返回创建日期;}public void setId(Long anId) {theId = anId;}public void setExpirationDate(Date anExpirationDate) {theExpirationDate = anExpirationDate;}公共无效setStatus(状态aStatus){theStatus = aStatus;}public void setCreationDate(Date aCreationDate) {theCreationDate = aCreationDate;}}私有类 MyTableModel 扩展了 AbstractTableModel {私有向量<对象>条目;MyTableModel() {theEntries = new Vector
I have added radio buttons to a JTable
using renderer and editor. I have also created group for the same. I'm unable to achieve the exclusiveness (only 1 radio button should be selected) using this principle. Please see my code below and appreciate your response.
Renderer and Editor classes:
class RadioButtonRenderer implements TableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (value == null)
return null;
return (Component) value;
}
}
class RadioButtonEditor extends DefaultCellEditor implements ItemListener {
private JRadioButton button;
public RadioButtonEditor(JCheckBox checkBox) {
super(checkBox);
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
if (value == null)
return null;
button = (JRadioButton) value;
button.addItemListener(this);
return (Component) value;
}
public Object getCellEditorValue() {
button.removeItemListener(this);
return button;
}
public void itemStateChanged(ItemEvent e) {
super.fireEditingStopped();
}
}
This is where the data is prepared and the grouping is done:
private void displayPhoneListShow(Person person) {
DefaultTableModel dm = new DefaultTableModel() {
@Override
public boolean isCellEditable(int row, int column) {
return true;
}
};
Object[] objects = new Object[3];
Object[] tableColumnNamesPhone = new Object[3];
tableColumnNamesPhone[0] = "Select";
tableColumnNamesPhone[1] = "Phone Number";
tableColumnNamesPhone[2] = "Preferred";
dm.setColumnIdentifiers(tableColumnNamesPhone);
ListIterator<Phone> phoneList = person.getPhoneList().listIterator();
while (phoneList.hasNext()) {
Phone phone = phoneList.next();
objects[0] = new JRadioButton(("^"));
objects[1] = phone.getPhoneNumber();
objects[2] = phone.getPreferred();
dm.addRow(objects);
}
this.phoneTable.setModel(dm);
ButtonGroup group = new ButtonGroup();
for (int row = 0; row < dm.getRowCount(); row++) {
JRadioButton radio = (JRadioButton) dm.getValueAt(row, 0);
group.add(radio);
}
phoneTable.getColumn("Select").setCellRenderer(
new RadioButtonRenderer());
phoneTable.getColumn("Select").setCellEditor(
new RadioButtonEditor(new JCheckBox()));
}
I am still unable to achieve the result. I have also tried adding ButtonGroup group = new ButtonGroup()
as a class variable and also part of the RadioButtonRenderer
class and added buttons to this group. But results were indifferent.
Please suggest.
As an alternative, use a JComboBox
as an editor for mutually exclusive choices within a row. For convenience, DefaultCellEditor
offers a constructor especially for this. The result also makes more efficient use of horizontal space in the row. DependentColumn
is an example, shown below. See also these other alternatives.
Figure from @mKorbel's
StatusRenderer
andStatusEditor
, Mac OS X:Figure from a related example, Mac OS X:
Figure from @mKorbel's
StatusRenderer
andStatusEditor
, Windows:Figure using
DefaultTableCellRenderer
andDefaultCellEditor
, Windows (see comments):
Code:
import java.awt.*;
import java.awt.event.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Vector;
import javax.swing.AbstractAction;
import javax.swing.AbstractCellEditor;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTable;
import javax.swing.JToolBar;
import javax.swing.SpinnerDateModel;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
public class JRadioAsRendererEditor extends JPanel {
private static final String[] COLUMN_NAMES = {
"List ID", "Expiration Date", "Status", "Date Created"};
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("dd/MM/yyyy");
private static final DateFormat TIME_FORMAT_LONG = new SimpleDateFormat("HH:mm:ss,SSS");
private MyTableModel tableModel;
private JTable table;
private JFrame frame = new JFrame("TestRadioButtonRenderer");
public JRadioAsRendererEditor() {
super(new BorderLayout(0, 5));
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
tableModel = new MyTableModel();
table = new JTable(tableModel);
table.setDefaultEditor(Date.class, new DateEditor());
table.setDefaultRenderer(Date.class, new DateRenderer());
table.setDefaultEditor(Status.class, new StatusEditor());
table.setDefaultRenderer(Status.class, new StatusRenderer());
// comment the two preceding lines and uncomment the following for a standard editor
// table.setDefaultEditor(Status.class, new DefaultCellEditor(
// new JComboBox(new Status[]{Status.Single, Status.Married, Status.Divorced})));
add(new JScrollPane(table), BorderLayout.CENTER);
JToolBar toolBar = new JToolBar();
toolBar.setFloatable(false);
toolBar.add(new AbstractAction("Add new") {
@Override
public void actionPerformed(ActionEvent e) {
tableModel.add(new TableEntry());
packTable();
}
});
toolBar.add(new AbstractAction("Remove") {
@Override
public void actionPerformed(ActionEvent e) {
tableModel.remove(table.getSelectedRow());
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(table), BorderLayout.CENTER);
frame.add(toolBar, BorderLayout.NORTH);
frame.pack();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
frame.setVisible(true);
}
});
}
private void packTable() {
TableColumnModel columnModel = table.getColumnModel();
int columnCount = table.getColumnCount();
int rowCount = table.getRowCount();
int[][] preferredHeights = new int[columnCount][rowCount];
TableCellRenderer renderer;
Component comp;
for (int col = 0; col < columnCount; col++) {
renderer = columnModel.getColumn(col).getCellRenderer();
if (renderer == null) {
renderer = table.getDefaultRenderer(tableModel.getColumnClass(col));
}
for (int row = 0; row < rowCount; row++) {
comp = renderer.getTableCellRendererComponent(table,
tableModel.getValueAt(row, col), false, false, row, col);
preferredHeights[col][row] = (int) comp.getPreferredSize().getHeight();
}
}
for (int row = 0; row < rowCount; row++) {
int pref = 0;
for (int col = 0; col < columnCount; col++) {
pref = Math.max(pref, preferredHeights[col][row]);
}
table.setRowHeight(row, pref);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JRadioAsRendererEditor tableTestPanel = new JRadioAsRendererEditor();
}
});
}
private enum Status {
Single, Married, Divorced;
}
private class StatusPanel extends JPanel {
private JRadioButton theSingleOption;
private JRadioButton theMarriedOption;
private JRadioButton theDivorcedOption;
private ButtonGroup buttonGroup = new ButtonGroup();
StatusPanel() {
super(new GridLayout(0, 1));
setOpaque(true);
theSingleOption = createRadio(Status.Single);
theMarriedOption = createRadio(Status.Married);
theDivorcedOption = createRadio(Status.Divorced);
}
private JRadioButton createRadio(Status status) {
JRadioButton jrb = new JRadioButton(status.toString());
jrb.setOpaque(false);
add(jrb);
buttonGroup.add(jrb);
return jrb;
}
public Status getStatus() {
if (theMarriedOption.isSelected()) {
return Status.Married;
} else if (theDivorcedOption.isSelected()) {
return Status.Divorced;
} else {
return Status.Single;
}
}
public void setStatus(Status status) {
if (status == Status.Married) {
theMarriedOption.setSelected(true);
} else if (status == Status.Divorced) {
theDivorcedOption.setSelected(true);
} else {
theSingleOption.setSelected(true);
}
}
}
private class TableEntry {
private int instanceNumber;
private Long theId;
private Date theExpirationDate;
private Status theStatus;
private Date theCreationDate;
TableEntry() {
instanceNumber++;
theId = new Long(instanceNumber);
theExpirationDate = new Date();
theStatus = Status.Single;
theCreationDate = new Date();
}
TableEntry(Long anId, Date anExpirationDate, Status aStatus, Date aCreationDate) {
theId = anId;
theExpirationDate = anExpirationDate;
theStatus = aStatus;
theCreationDate = aCreationDate;
}
public Long getId() {
return theId;
}
public Date getExpirationDate() {
return theExpirationDate;
}
public Status getStatus() {
return theStatus;
}
public Date getCreationDate() {
return theCreationDate;
}
public void setId(Long anId) {
theId = anId;
}
public void setExpirationDate(Date anExpirationDate) {
theExpirationDate = anExpirationDate;
}
public void setStatus(Status aStatus) {
theStatus = aStatus;
}
public void setCreationDate(Date aCreationDate) {
theCreationDate = aCreationDate;
}
}
private class MyTableModel extends AbstractTableModel {
private Vector<Object> theEntries;
MyTableModel() {
theEntries = new Vector<Object>();
}
@SuppressWarnings("unchecked")
public void add(TableEntry anEntry) {
int index = theEntries.size();
theEntries.add(anEntry);
fireTableRowsInserted(index, index);
}
public void remove(int aRowIndex) {
if (aRowIndex < 0 || aRowIndex >= theEntries.size()) {
return;
}
theEntries.removeElementAt(aRowIndex);
fireTableRowsDeleted(aRowIndex, aRowIndex);
}
public int getRowCount() {
return theEntries.size();
}
@Override
public String getColumnName(int column) {
return COLUMN_NAMES[column];
}
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0:
return Long.class;
case 1:
return Date.class;
case 2:
return Status.class;
case 3:
return Date.class;
}
return Object.class;
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
TableEntry entry = (TableEntry) theEntries.elementAt(rowIndex);
switch (columnIndex) {
case 0:
try {
entry.setId(new Long(Long.parseLong(aValue.toString())));
} catch (NumberFormatException nfe) {
return;
}
break;
case 1:
entry.setExpirationDate((Date) aValue);
break;
case 2:
entry.setStatus((Status) aValue);
break;
case 3:
entry.setCreationDate((Date) aValue);
break;
default:
return;
}
fireTableCellUpdated(rowIndex, columnIndex);
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
@Override
public int getColumnCount() {
return 4;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
TableEntry entry = (TableEntry) theEntries.elementAt(rowIndex);
switch (columnIndex) {
case 0:
return entry.getId();
case 1:
return entry.getExpirationDate();
case 2:
return entry.getStatus();
case 3:
return entry.getCreationDate();
}
return null;
}
}
private class DateRenderer extends DefaultTableCellRenderer {
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (!(value instanceof Date)) {
return this;
}
setText(DATE_FORMAT.format((Date) value));
return this;
}
}
private class TimeRenderer extends DefaultTableCellRenderer {
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (!(value instanceof Date)) {
return this;
}
setText(TIME_FORMAT_LONG.format((Date) value));
return this;
}
}
private class DateEditor extends AbstractCellEditor implements TableCellEditor {
private JSpinner theSpinner;
DateEditor() {
theSpinner = new JSpinner(new SpinnerDateModel());
theSpinner.setOpaque(true);
theSpinner.setEditor(new JSpinner.DateEditor(theSpinner, "dd/MM/yyyy"));
}
@Override
public Object getCellEditorValue() {
return theSpinner.getValue();
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
theSpinner.setValue(value);
if (isSelected) {
theSpinner.setBackground(table.getSelectionBackground());
} else {
theSpinner.setBackground(table.getBackground());
}
return theSpinner;
}
}
private class TimeEditor extends AbstractCellEditor implements TableCellEditor {
private JSpinner theSpinner;
private Object value;
TimeEditor() {
theSpinner = new JSpinner(new SpinnerDateModel());
theSpinner.setOpaque(true);
theSpinner.setEditor(new JSpinner.DateEditor(theSpinner, "HH:mm:ss,SSS"));
}
@Override
public Object getCellEditorValue() {
return theSpinner.getValue();
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
theSpinner.setValue(value);
if (isSelected) {
theSpinner.setBackground(table.getSelectionBackground());
} else {
theSpinner.setBackground(table.getBackground());
}
return theSpinner;
}
}
private class StatusEditor extends AbstractCellEditor implements TableCellEditor {
private StatusPanel theStatusPanel;
StatusEditor() {
theStatusPanel = new StatusPanel();
}
@Override
public Object getCellEditorValue() {
return theStatusPanel.getStatus();
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
theStatusPanel.setStatus((Status) value);
if (isSelected) {
theStatusPanel.setBackground(table.getSelectionBackground());
} else {
theStatusPanel.setBackground(table.getBackground());
}
return theStatusPanel;
}
}
private class StatusRenderer extends StatusPanel implements TableCellRenderer {
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
setStatus((Status) value);
if (isSelected) {
setBackground(table.getSelectionBackground());
} else {
setBackground(table.getBackground());
}
return this;
}
}
}
这篇关于如何将 JRadioButton 添加到 JTable 中的组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!