2

我正在尝试设置一个 JRadioButton-Matrix,以便在每一列和每一行中,一次只能选择一个按钮。我有以下代码:

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]);

那么上面右边的矩阵是可能的,但左边的矩阵是可能的。

4

3 回答 3

2

不,任何AbstractButton使用默认值的子类ButtonModel(不出所料地命名为DefaultButtonModel)只能在一个ButtonGroup.

有关详细信息,请参阅ButtonGroup.add(...)ButtonModel.setGroup(...)

可以创建一个ButtonGroup了解矩阵的特殊子类,并允许多项选择(我认为有一些技巧)。我曾经创建了一组单选按钮(互斥)和多个复选框(允许多选),它对我有用。:-) 目前无法访问代码,但如果您有兴趣,稍后可能会更新代码。

于 2013-12-25T13:08:28.640 回答
1

自定义 ButtonGroup(正如@Harald 已经建议的那样)绝对是要走的路。

由于 buttonModel 和 group 的职责混合有点奇怪,这并不完全是微不足道的:要记住的基本调整是 group 必须保持自己的选择状态(而不是依赖于模型的 selected)。

下面的 POC 实现将其保存在一个矩阵 (list-of-(lists-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);
}
于 2013-12-25T18:55:17.650 回答
1

您正在寻找的功能是否可行?是的。下面是我的意思的一个例子。我使用了很多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();
            }
        });
    }
}

在此处输入图像描述

于 2013-12-25T12:55:21.350 回答