我正在尝试设置一个JRadioButton-Matrix,这样在每一列和每一行中,一次只能选择一个Button。我有以下代码:
JRadioButton[][] button = new JRadioButton[names.length][names.length];
ButtonGroup[] r = new ButtonGroup[names.length];
ButtonGroup[] c = new ButtonGroup[names.length];
for (int i = 0; i < names.length; i++) {
r[i] = new ButtonGroup();
c[i] = new ButtonGroup();
}
for (int i = 0; i < names.length; i++) {
for (int j = 0; j < names.length; j++) {
button[i][j] = new JRadioButton();
r[i].add(button[i][j]);
c[j].add(button[i][j]);
}
}
但是当我执行它时,只有列表现正常(即组中的按钮) C)。但是,当我使用c对部件进行注释时,行的行为确实正常。
稍微清楚一点(感谢peeskillet):
假设我有这个4 x 4矩阵的JRadioButtons:
O O O O
O O O O
O O O O
O O O O
我希望能够做出如下选择:
X O O O X O O O O X O O
O X O O O O X O X O O O
O O X O O X O O O O O X
O O O X O O O X O O X O
在上面,每列只有一列,每行只有一行。以下示例是不可能的:
X X O O X O O O
O O O O O X O O
O O X O O X O O
O O O X O O O X
然而,问题是,我可以像上面左边的矩阵一样选择,但不是正确的。如果我评论以下部分:
ButtonGroup[] c = new ButtonGroup[names.length];
c[i] = new ButtonGroup();
c[j].add(button[i][j]);
然后右上方的矩阵是可能的,但不是左边的。
答案 0 :(得分:2)
不,使用默认AbstractButton
的任何ButtonModel
子类(不出所料地命名为DefaultButtonModel
)可能只在一个ButtonGroup
中。
有关详细信息,请参阅ButtonGroup.add(...)和ButtonModel.setGroup(...)。
可以创建一个特殊的ButtonGroup
子类,它具有您的矩阵知识,并允许多个选择(我认为有一些黑客攻击)。我曾经创建了一组radiobutton(互斥)和多个复选框(允许多个选择),它对我有用。 :-)
现在无法访问代码,但如果您有兴趣,可能会在以后使用代码进行更新。
答案 1 :(得分:1)
您正在寻找的功能是否可行?是。以下是我的意思的一个例子。我使用了 lot 的is语句。也许有一种递归方式来实现这一目标,但这更令人难以置信。看看这个例子。不幸的是它只使用了9个按钮。因此,如果您想要使用更多,则需要更多编码。基本上我所做的只是取消选择每个被选中的按钮。
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.SwingUtilities;
public class MultiButtonGroup extends JPanel implements ActionListener {
JRadioButton rb1 = new JRadioButton("rb1");
JRadioButton rb2 = new JRadioButton("rb2");
JRadioButton rb3 = new JRadioButton("rb3");
JRadioButton rb4 = new JRadioButton("rb4");
JRadioButton rb5 = new JRadioButton("rb5");
JRadioButton rb6 = new JRadioButton("rb6");
JRadioButton rb7 = new JRadioButton("rb7");
JRadioButton rb8 = new JRadioButton("rb8");
JRadioButton rb9 = new JRadioButton("rb9");
public MultiButtonGroup() {
JRadioButton[][] buttons = {
{rb1, rb2, rb3},
{rb4, rb5, rb6},
{rb7, rb8, rb9}
};
JPanel panel = new JPanel(new GridLayout(4, 4));
for (JRadioButton[] rbs : buttons) {
for (JRadioButton rbz : rbs) {
rbz.addActionListener(new RadioListener());
panel.add(rbz);
}
}
JButton doSomething = new JButton("Do SOmething");
setLayout(new BorderLayout());
add(panel, BorderLayout.CENTER);
add(doSomething, BorderLayout.SOUTH);
}
public void actionPerformed(ActionEvent e) {
}
private class RadioListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
JRadioButton source = (JRadioButton) e.getSource();
if (source == rb1) {
if (rb1.isSelected()) {
rb2.setSelected(false);
rb3.setSelected(false);
rb4.setSelected(false);
rb7.setSelected(false);
}
} else if (source == rb2) {
if (rb2.isSelected()) {
rb1.setSelected(false);
rb3.setSelected(false);
rb5.setSelected(false);
rb8.setSelected(false);
}
} else if (source == rb3) {
if (rb3.isSelected()) {
rb2.setSelected(false);
rb1.setSelected(false);
rb6.setSelected(false);
rb9.setSelected(false);
}
} else if (source == rb4) {
if (rb4.isSelected()) {
rb1.setSelected(false);
rb7.setSelected(false);
rb5.setSelected(false);
rb6.setSelected(false);
}
} else if (source == rb5) {
if (rb5.isSelected()) {
rb4.setSelected(false);
rb6.setSelected(false);
rb2.setSelected(false);
rb8.setSelected(false);
}
} else if (source == rb6) {
if (rb6.isSelected()) {
rb3.setSelected(false);
rb9.setSelected(false);
rb4.setSelected(false);
rb5.setSelected(false);
}
} else if (source == rb7) {
if (rb7.isSelected()) {
rb1.setSelected(false);
rb4.setSelected(false);
rb8.setSelected(false);
rb9.setSelected(false);
}
} else if (source == rb8) {
if (rb8.isSelected()) {
rb7.setSelected(false);
rb9.setSelected(false);
rb5.setSelected(false);
rb2.setSelected(false);
}
} else if (source == rb9) {
if (rb9.isSelected()) {
rb6.setSelected(false);
rb3.setSelected(false);
rb8.setSelected(false);
rb7.setSelected(false);
}
}
}
}
public static void createAndShowGui() {
JFrame frame = new JFrame();
frame.add(new MultiButtonGroup());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
答案 2 :(得分:1)
自定义ButtonGroup(正如@Harald已经建议的那样)肯定是要走的路。
由于buttonModel和组的职责略有奇怪,并非完全无关紧要:要记住的基本调整是该组必须保持自己的选择状态(相对于所选模型而言) 。
下面的POC实现将其保存在矩阵(list-of-buttonModels)中,其中包含null或它认为选择的模型。内部更新保持(应该,未经过正式测试:-)该矩阵,使其在每行和每列中只有一个非空元素。当然有足够的余地进行清理......
/**
* A buttonGroup that organizes selections in a matrix and guarantees
* to have at most one selection in each row and each column.
*/
public static class MatrixButtonGroup extends ButtonGroup {
// matrix of the buttons
private List<List<AbstractButton>> buttonMatrix;
// sparse matrix of the selected models, contains nulls
// everywhere except the unique selection for each row/column
private List<List<ButtonModel>> selectionMatrix;
public MatrixButtonGroup(List<AbstractButton> buttons, int columnCount) {
if (buttons.size() % columnCount != 0) {
throw new IllegalStateException("buttons count must be a multiple of columnCount");
}
int rowCount = buttons.size() / columnCount;
buttonMatrix = new ArrayList<>();
selectionMatrix = new ArrayList<>();
int counter = 0;
for (int row = 0; row < rowCount; row++) {
List<AbstractButton> buttonsInRow = new ArrayList<>();
List<ButtonModel> modelsInRow = new ArrayList<>();
for (int column = 0; column < columnCount; column++) {
modelsInRow.add(null);
buttons.get(counter).getModel().setGroup(this);
buttonsInRow.add(buttons.get(counter++));
}
selectionMatrix.add(modelsInRow);
buttonMatrix.add(buttonsInRow);
}
}
@Override
public boolean isSelected(ButtonModel m) {
for (int row = 0; row < selectionMatrix.size(); row++) {
List<ButtonModel> modelsInRow = selectionMatrix.get(row);
if (modelsInRow.contains(m)) return true;
}
return false;
}
/**
* Implemented to select the model such that it is the
* uniquely selected in the row/column of its button.
*/
@Override
public void setSelected(ButtonModel model, boolean selected) {
if (model == null || !selected) return;
if (isSelected(model)) return;
int row = getRow(model);
int column = getColumn(model);
ButtonModel rowSelected = getSelectedForRow(row);
ButtonModel columnSelected = getSelectedForColumn(column);
// update internal selection state
select(model, row, column);
// unselect the old selection if necessary
if (rowSelected != null) {
rowSelected.setSelected(false);
}
if (columnSelected != null) {
columnSelected.setSelected(false);
}
// select the new model
model.setSelected(true);
}
/**
* Update internal selection state to select the model such
* that there is exactly one model selected in the given
* row and column.
*/
private void select(ButtonModel model, int row, int column) {
// clear all in column
for (int index = 0; index < selectionMatrix.size(); index++) {
selectionMatrix.get(index).set(column, null);
}
List<ButtonModel> selectionRow = selectionMatrix.get(row);
for (int index = 0; index < selectionRow.size(); index++) {
selectionRow.set(index, null);
}
selectionRow.set(column, model);
}
/**
* @return the column of the given model
*/
private int getColumn(ButtonModel model) {
for (int row = 0; row < buttonMatrix.size(); row++) {
int column = getColumnInRow(buttonMatrix.get(row), model);
if (column >= 0) return column;
}
throw new IllegalStateException("model not managed by this group");
}
/**
* @return the row of the given model
*/
private int getRow(ButtonModel model) {
for (int row = 0; row < buttonMatrix.size(); row++) {
if (getColumnInRow(buttonMatrix.get(row), model) >= 0) return row;
}
throw new IllegalStateException("model not managed by this group");
}
/**
* @return the column of the model in the list
*/
private int getColumnInRow(List<AbstractButton> list, ButtonModel model) {
for (int column = 0; column < list.size(); column++) {
if (list.get(column).getModel() == model) return column;
}
return -1;
}
/**
* @return the selected buttonModel in the column or null if none
* selected
*/
private ButtonModel getSelectedForColumn(int column) {
for (List<ButtonModel> selectionRow : selectionMatrix) {
if (selectionRow.get(column) != null) return selectionRow.get(column);
}
return null;
}
/**
* @return the selected buttonModel in the row or null if none
* selected
*/
private ButtonModel getSelectedForRow(int row) {
List<ButtonModel> selectionRow = selectionMatrix.get(row);
for (ButtonModel model : selectionRow) {
if (model != null) return model;
}
return null;
}
/**
* Implemented to return the first selected model, traversing
* rows from first to last column.
*/
@Override
public ButtonModel getSelection() {
for (List<ButtonModel> selectionRow : selectionMatrix) {
for (ButtonModel model : selectionRow) {
if (model != null) return model;
}
}
return null;
}
@Override
public int getButtonCount() {
return buttonMatrix.size() * buttonMatrix.get(0).size();
}
// super overrides that still need to be done or are not supported
@Override
public Enumeration<AbstractButton> getElements() {
throw new UnsupportedOperationException("not yet implemented");
}
@Override
public void clearSelection() {
throw new UnsupportedOperationException("not yet implemented");
}
@Override
public void add(AbstractButton b) {
throw new UnsupportedOperationException("this button group is unmodifiable");
}
@Override
public void remove(AbstractButton b) {
throw new UnsupportedOperationException("this button group is unmodifiable");
}
}
这是用法:
List<AbstractButton> buttons = new ArrayList<>();
for (int row = 0; row < 4; row++) {
for (int column = 0; column < 4; column++) {
buttons.add(new JRadioButton("row " + row + " col " + column));
}
}
ButtonGroup p = new MatrixButtonGroup(buttons, 4);
JComponent content = new JPanel(new GridLayout(0, 4));
for (AbstractButton button : buttons) {
content.add(button);
}