【发布时间】:2015-02-09 17:19:26
【问题描述】:
所以我有一个类似于控制台的 GUI。我希望用户在 JTextField 中输入文本并按 Enter。当用户按下回车键时,我使用键绑定进行回调。
现在我想创建一个名为 waitForInput() 的方法,它等待用户输入并返回它。我正在尝试的是下面。但是在回调函数中调用 notify() 会导致 java.lang.IllegalMonitorStateException。
public class MainWindow{
private JFrame mainWindow;
private JTextArea textEntry;
private String inputStringMonitor = ""; // lock/user input value
private Boolean stringReady = false; //flag for wait while loop
public MainWindow(){
mainWindow = new JFrame("console");
textEntry = new JTextArea();
// set up key bindings
InputAction = new UserInputAction();
textEntry.getInputMap().put( KeyStroke.getKeyStroke( "ENTER" ),"EnterAction" );
textEntry.getActionMap().put( "EnterAction", InputAction);
//configure window
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWindow.setMinimumSize(new Dimension(800,675));
mainWindow.getContentPane().add(textEntry);
mainWindow.pack();
mainWindow.setVisible(true);
}
// callback action when user presses enter
public class UserInputAction extends AbstractAction
{
public void actionPerformed( ActionEvent bp )
{
System.out.println( "enter pressed" );
textEntry.setText("> ");
textEntry.setCaretPosition(2);
synchronized(inputStringMonitor){
stringReady = true;
inputStringMonitor = textEntry.getText();
inputStringMonitor.notify(); //causes exception
}
}
}
public String waitForInput() throws InterruptedException {
String retval = "";
synchronized(inputStringMonitor){
stringReady = false;
System.out.println("waiting");
while(!stringReady){
inputStringMonitor.wait();
}
retval = inputStringMonitor;
}
return retval;
}
}
【问题讨论】:
-
这都是错误的。您通过在
actionPerformed(....)方法中使用synchronized块并重新初始化同步synchronized(inputStringMonitor){... inputStringMonitor = textEntry.getText(); ...}的对象来阻止 EDT -
好的。那么有没有办法从 EDT 通知呢?我想做同样的事情,但分支一个新线程来做它,所以它不会阻塞?并使用专用锁修复重新初始化部分?
-
你可以使用新线程来做等待和通知,你可以创建一个SwingWorker或者你可以使用invokeLater(..)方法。正如你所说,使用专用对象进行同步。
-
字符串不是用作同步监视器的好对象,因为它可以被实习和共享。
new Object()足以创建监视器。如果需要可序列化,new StringBuilder()是另一种选择。
标签: java swing callback monitor