2013-12-25 3 views
2

Я пытаюсь настроить JRadioButton-Matrix, так что в каждом столбце и в каждой строке можно выбрать только одну кнопку. У меня есть следующий код:Может ли JRadioButton быть в нескольких ButtonGroups?

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, строки ведут себя правильно.

Чтобы очистить вещи немного вверх (благодаря peeskillet):

Допустим, у меня есть этот 4 х 4 матрица JRadioButton,:

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

, то матрица справа должна быть, но не слева.

+1

* «К сожалению, если имена запутанные ..» * Изменение их быть «не сбивают с толком» является более продуктивным, чем извинения .. –

+0

Класс ButtonGroup предназначен для группировки переключателей. Вам нужно будет написать свои собственные прослушиватели действий, чтобы проверять переключатели между группами кнопок (строками). –

+0

@AndrewThompson Да, это было глупо. – Zuerill

ответ

1

Является ли функциональность, которую вы ищете выполнимой? Да. Ниже приведен пример того, что я имею в виду. Я использовал заявление . Может быть, есть рекурсивный способ добиться этого, но это еще больше умудряет ум. Взгляните на пример. К сожалению, он использовал только 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(); 
      } 
     }); 
    } 
} 

enter image description here

+0

Правильно, но, конечно же, возможны и другие варианты (достигнутые в вашем примере путем замены двух строк). Редактировать: вы поняли. – Zuerill

+0

Хорошо, спасибо, сделаю – Zuerill

+0

Вот и все! Но, ну, мне нужно 14 строк/столбцов ... Спасибо, но, вероятно, это не стоит реализовывать, я могу жить без него. – Zuerill

2

Нет, любой AbstractButton подкласс, используя по умолчанию ButtonModel (Unsurprisingly именем DefaultButtonModel) может быть только в одном ButtonGroup.

Для получения дополнительной информации см. ButtonGroup.add(...) и ButtonModel.setGroup(...).

Возможно создание специального подкласса ButtonGroup, который имеет знания о вашей матрице и позволяет несколько вариантов выбора (с некоторыми хаками, я думаю). Однажды я создал группу из одного радиообмена (взаимно исключающего) и нескольких флажков (разрешено множественное выделение), и это сработало для меня. :-) У меня нет доступа к коду прямо сейчас, но может быть позже обновлен кодом, если вам интересно.

+0

Значит, я не обойдусь без переписывания всех этих классов? – Zuerill

+0

@ Zuerill Я обновил ответ с некоторыми предложениями о том, что вы можете сделать. Я предлагаю одну пользовательскую 'ButtonGroup'. – haraldK

+0

Эх, мне не хватает времени, чтобы сосредоточиться на действительно сложном графическом интерфейсе, это будет трюк, если я просто группирую столбцы. – Zuerill

1

Пользовательская ButtonGroup (как уже было предложено @Harald) определенно является способом выхода.

Не совсем тривиально из-за слегка странной комбинации обязанностей кнопкиModel и группы: основная настройка, которую следует иметь в виду, состоит в том, что группа должна сохранять свое собственное состояние выбора (по сравнению с выбранной моделью).

Нижеприведенная реализация POC хранит ее в матрице (list-of- (lists-of-buttonModels)), которые содержат нуль или модель, которую он считает выбранным. Внутреннее обновление хранит (должно, формально не проверено) :-), что такая матрица, что у нее есть ровно один не-нулевой элемент в каждой строке и каждом столбце. Конечно, есть много свободы действий для очистки ...

/** 
* 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); 
}