2013-10-16 251 views
1

我想創建一組兩個按鈕(A和B),其中從B切換到A始終是允許的,但是從A切換到A B取決於一個條件。只有在後一種情況下(A到B)才能檢查條件,並且每次開關嘗試只能進行一次檢查。如果阻止了交換機,則必須沒有爲任一按鈕生成事件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

禁用按鈕,直到滿足條件 – kleopatra

+0

@kleopatra,決定應該以互動的方式,進行被點擊B之後。我不能禁用B,如果這就是你的建議。點擊B是隨時可用的用戶選項。 – predi

+0

嗯,對我來說沒什麼意義:如果它沒有效果,不能成爲一個可行的選擇......所以我可以點擊(又名:選擇)按鈕或不按鈕。可能沒有完全明白你的想法:-) – kleopatra

回答

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); 
} 
+1

這與我在上次嘗試中接近它的方式類似。將嘗試一下。 – predi

+1

工程就像一個魅力。我接受了這個答案,而不是我自己的答案,但都似乎工作。謝謝。 – predi

1

諮詢我意識到,調用ButtonGroup.setSelected(ButtonModel, boolean)可能催生同樣的方法,新的呼叫ButtonGroup實施後,導致我的情況最多檢查三次。所以我現在警惕後續的電話。似乎工作。不過,有一點點。

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(); 
    } 

} 
+0

是的,這個想法是一樣的 - 在同一時間找到:-) +1 – kleopatra