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