2012-09-28 63 views
3

我想要有具有歷史記錄的命令窗口。我製作了okAction並將其綁定到Ok按鈕。這個命令在發出命令時調用。爲什麼動作執行3次?

如果命令成功,命令的文本將從輸入單元中刪除並添加到歷史記錄中。這是可編輯的JComboBox

如果用戶從歷史記錄中選擇了一些命令,與按下Ok按鈕時發生的情況相同。所以我也將相同的動作綁定到組合框。

不幸的是,使用組合框操作也會導致操作調用。在下面的例子中,這是模擬命令失敗的一個動作,被稱爲3次。

爲什麼?

import java.awt.*; 
import java.awt.event.*; 
import java.util.Random; 
import javax.swing.*; 
import javax.swing.border.*; 

public class JCommandWindow extends JFrame { 

    private static final Random rnd = new Random(); 
    private static final long serialVersionUID = 1L; 
    private AbstractAction okAction = new AbstractAction("Ok") { 

     private static final long serialVersionUID = 1L; 

     @Override 
     public void actionPerformed(ActionEvent e) { 

      if (issue((String) inputComboBox.getSelectedItem())) { 
       inputComboBox.setSelectedItem(""); 
      } else { 
       inputComboBox.getEditor().selectAll(); 
      } 
     } 
    }; 
    private AbstractAction cancelAction = new AbstractAction("Cancel") { 

     private static final long serialVersionUID = 1L; 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      close(); 
     } 
    }; 
    private JTextArea logTextArea = new JTextArea(); 

    { 
     logTextArea.setWrapStyleWord(true); 
     logTextArea.setBorder(new EtchedBorder()); 
     logTextArea.setEditable(false); 
    } 
    private JScrollPane logScrollPane = new JScrollPane(logTextArea); 

    { 
     logScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 
     logScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 
    } 
    private JPanel logPanel = new JPanel(); 

    { 
     logPanel.setLayout(new BorderLayout()); 
     logPanel.setBorder(new EmptyBorder(5, 5, 0, 5)); 
     logPanel.add(logScrollPane, BorderLayout.CENTER); 
    } 
    private DefaultComboBoxModel historyModel = new DefaultComboBoxModel(); 
    private JComboBox inputComboBox = new JComboBox(); 

    { 
     inputComboBox.setModel(historyModel); 
     inputComboBox.setEditable(true); 
     inputComboBox.addActionListener(okAction); 
    } 
    private JPanel inputPanel = new JPanel(); 

    { 
     inputPanel.setLayout(new BorderLayout()); 
     inputPanel.setBorder(new EmptyBorder(5, 5, 5, 0)); 
     inputPanel.add(inputComboBox, BorderLayout.CENTER); 
    } 
    private JButton okButton = new JButton(okAction); 
    private JButton cancelButton = new JButton(cancelAction); 
    private JPanel buttonPanel = new JPanel(); 

    { 
     buttonPanel.setLayout(new FlowLayout()); 
     buttonPanel.add(okButton); 
     buttonPanel.add(cancelButton); 
    } 
    private JPanel bottomPanel = new JPanel(); 

    { 
     bottomPanel.setLayout(new BorderLayout()); 
     bottomPanel.add(inputPanel, BorderLayout.CENTER); 
     bottomPanel.add(buttonPanel, BorderLayout.EAST); 
    } 
    private final JRootPane rootPane = getRootPane(); 

    { 
     rootPane.setLayout(new BorderLayout()); 
     rootPane.add(logPanel, BorderLayout.CENTER); 
     rootPane.add(bottomPanel, BorderLayout.SOUTH); 

     rootPane.setDefaultButton(okButton); 
     rootPane.addKeyListener(new KeyListener() { 

      @Override 
      public void keyTyped(KeyEvent e) { 
       // TODO Auto-generated method stub 
      } 

      @Override 
      public void keyReleased(KeyEvent e) { 
       // TODO Auto-generated method stub 
      } 

      @Override 
      public void keyPressed(KeyEvent e) { 
       if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { 
        cancelAction.actionPerformed(null); 
       } 
      } 
     }); 
     addWindowFocusListener(new WindowFocusListener() { 

      @Override 
      public void windowLostFocus(WindowEvent e) { 
       // TODO Auto-generated method stub 
      } 

      @Override 
      public void windowGainedFocus(WindowEvent e) { 
       inputComboBox.requestFocusInWindow(); 
      } 
     }); 
    } 

    public JCommandWindow() { 
     setDefaultCloseOperation(DISPOSE_ON_CLOSE); 
    } 

    public void close() { 
     WindowEvent wev = new WindowEvent(this, WindowEvent.WINDOW_CLOSING); 
     Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(wev); 
    } 

    @Override 
    public void pack() { 
     super.pack(); 
     // Get the size of the screen 
     Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); 
     int w = dim.width * 2/3; 
     int h = dim.height * 2/3; 
     setSize(w, h); 
     int x = (dim.width - w)/2; 
     int y = (dim.height - h)/2; 
     // Move the window 
     setLocation(x, y); 
    } 

    public void addText(String text) { 
     logTextArea.append(text + "\n"); 
     logTextArea.setCaretPosition(logTextArea.getDocument().getLength()); 
    } 

    public void rememberCommand(String command) { 
     historyModel.addElement(command); 
    } 

    public boolean issue(String command) { 
     /* 
     if(rnd.nextBoolean()) { 
     addText(command + " succeeded"); 
     rememberCommand(command); 
     return true; 
     } 
     else { 
     addText(command + " failed"); 
     return false; 
     } 
     */ 
     addText(command + " failed"); 
     return false; 
    } 

    public static void main(String[] args) { 
     JCommandWindow commandWindow = new JCommandWindow(); 
     commandWindow.pack(); 
     commandWindow.setVisible(true); 
    } 
} 
+2

當按鈕被點擊時,調用okAction - *第一次調用*。在那裏,'inputComboBox'被操縱,觸發'okAction' - *第二次調用*。這會讓你回到'inputComboBox'被再次操作的同一個函數,這會觸發'okAction' - *第三次調用*。最好不要讓組件觸發事件本身,因爲事件監聽將會遞歸直到出現錯誤。 – davidXYZ

回答

4

當編輯ComboBox失去焦點時,JComboBox事件被觸發來觸發ActionListeneractionPerformedcontentsChanged方法。然後,focusLost再次調用actionPerformed

然後觸發按鈕按下的動作。