2

B から A への切り替えは常に許可されますが、A から B への切り替えは条件に依存する 2 つのボタン (A と B) のグループを作成したいと思います。条件は、後者の場合 (A から B) でのみチェックでき、チェックは切り替え試行ごとに 1 回だけ実行できます。ItemEvent.SELECTED切り替えが妨げられた場合、どちらのボタンに対してもイベントが生成されてはなりません。

非常に簡単に思えるので、単純で簡潔な方法でこれを行うことができなかった理由について困惑しています。ButtonGroup を拡張することがこれを行う方法だと思っていましたが、今はもうわかりません。

import java.awt.FlowLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;

public class ToggleGroup extends JFrame {

    private ButtonGroup group = new MyButtonGroup();
    private JToggleButton buttonA = new JToggleButton("A");
    private JToggleButton buttonB = new JToggleButton("B");

    public ToggleGroup() {
        setLayout(new FlowLayout());
        add(buttonA);
        add(buttonB);
        group.add(buttonA);
        group.add(buttonB);
        group.setSelected(buttonA.getModel(), true);
        pack();
        setLocationRelativeTo(null);

        ItemListener itemListener = new ItemListener() {
            public void itemStateChanged(ItemEvent e) {                
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    System.out.println("-> " + (e.getSource() == buttonA ? "A" : "B") + " selected");
                }
            }
        };
        buttonA.addItemListener(itemListener);
        buttonB.addItemListener(itemListener);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                ToggleGroup test = new ToggleGroup();
                test.setVisible(true);
            }
        });
    }

    private class MyButtonGroup extends ButtonGroup {

        private boolean check() {
            int result = JOptionPane.showConfirmDialog(
                    ToggleGroup.this, "May I switch to B?",
                    "Important question", JOptionPane.YES_NO_OPTION,
                    JOptionPane.WARNING_MESSAGE);
            return result == JOptionPane.YES_OPTION;
        }

        @Override
        public void setSelected(ButtonModel m, boolean b) {      
            if (!b) {
                return;
            }
            if (m == buttonA.getModel() || m == buttonB.getModel() && check()) {
                super.setSelected(m, b);
            }
        }

    }
}

私のコードの問題は明らかです。条件は複数回チェックされるため、ダイアログも複数回表示されます。

では、条件が失敗したときに切り替えの試行を「消費」するにはどうすればよいでしょうか。

編集:

これらのボタンを使用しているコンテキストは、アプリケーションのさまざまなモード間の切り替えの実装です。モードの 1 つは、データを変更して後でコミットできるようにします。コミットされていない変更が存在する場合、モードを切り替えるとデータが失われる可能性があります。切り替えが意図的なものであることを確認したいと思います。条件が満たされるまでいずれかのボタンを無効にすることはできません。

4

2 に答える 2

1

興味深い...少し掘り下げると、選択/武装/押されたの相互作用が、中断されたチェックによって多少混乱していることがわかります(バグをかすかに覚えていますが、今は見つけられません)。主な問題は、setSelected メソッドへの再入力を許可しないことです。汚い(読んだ:これ以上掘り下げなかった)方法は、フラグを切り替えることです。

private boolean isChecking;
@Override
public void setSelected(final ButtonModel m, boolean b) {   
    if (isChecking) return;
    isChecking = false;
    if (!b) {
        return;
    }
    if (m == buttonB.getModel()) {
        isChecking = true;
        final boolean select = check();
        if (select) {
            superSetSelected(m, select);
        }
        isChecking = false;
        return;
    } else {
        superSetSelected(m, b);
    }
}

protected void superSetSelected(ButtonModel m, boolean b) {
    super.setSelected(m, b);
}
于 2013-10-16T12:08:38.337 に答える
1

の実装を調べたところ、呼び出しによって同じメソッドの新しい呼び出しが生成される可能性があり、条件が最大 3 回チェックされることButtonGroupに気付きました。ButtonGroup.setSelected(ButtonModel, boolean)だから私は今、後続の呼び出しを防ぎます。うまくいくようです。ちょっと微妙だけど。

private class MyButtonGroup extends ButtonGroup {

    private Stack<ButtonModel> locked = new Stack<ButtonModel>();

    @Override
    public void setSelected(ButtonModel m, boolean b) {      
        if (!b || !locked.isEmpty() && locked.peek() == m) {
            return;
        }
        locked.push(m);
        if (m == buttonA.getModel() || m == buttonB.getModel() && check()) {
            super.setSelected(m, b);
        }
        locked.pop();
    }

}
于 2013-10-16T12:09:06.457 に答える