线程通信:如何发出被点击键的信号?java.lang.IllegalMonitorStateException.



我有一个简单的JavaFX阶段,上面有一个TextField。我想做的是:当用户在 TextField 中插入字母时,我想打印"现在"(只是为了看看它是否有效(。我使用线程,因为稍后我想扫描字典以查看用户输入的字母是否是字典中单词的一部分。

但我得到:java.lang.IllegalMonitorStateException

有什么想法吗?我似乎不理解Condition.await和Multithreading的整个概念。

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class DictionaryThreading extends Application {

private static Lock lock = new ReentrantLock();
public static Condition condition = lock.newCondition();
public static void main(String[] args) {
    launch();
}
private static class ScanWords implements Runnable{
    @Override
    public void run() {
        lock.lock();
        try{    
            while(true){
                this.wait();
                System.out.println("clicked");
            }
        } catch (Exception e){
            e.printStackTrace();
        } finally{
            lock.unlock();
        }   
    }
}
@Override
public void start(Stage primaryStage) throws Exception {
    StackPane pane = new StackPane();
    new ScanWords().run();
    TextField tf = new TextField("Please enter a word");
    tf.setOnKeyPressed(e -> {});
    pane.getChildren().add(tf);
    Scene scene = new Scene(pane);
    primaryStage.setScene(scene);
    primaryStage.show();
}
}

无需创建除了等待用户事件之外什么都不执行任何操作的线程。JavaFX 框架已经为您提供了此功能(它是任何 UI 工具包的基本功能之一(。要响应文本字段中文本中的更改,您需要做的就是使用文本字段的 text 属性注册更改侦听器:

public void start(Stage primaryStage) throws Exception {
    StackPane pane = new StackPane();
    TextField tf = new TextField("Please enter a word");
    tf.textProperty().addListener((obs, oldText, newText) -> {
        System.out.println("text changed");
    });
    pane.getChildren().add(tf);
    Scene scene = new Scene(pane);
    primaryStage.setScene(scene);
    primaryStage.show();
}
如果您需要执行的响应文本

更改需要很长时间,则应在文本字段的侦听器中的后台线程中启动该过程。如果要搜索大型搜索,则可能希望取消任何现有搜索,这样就不会最终导致大量搜索同时运行。JavaFX Service类提供了为此所需的功能:

public class SearchService extends Service<List<String>> {
    // modify and access only on FX Application Thread:
    private String searchString ;
    @Override
    protected Task<List<String>> createTask() {
        final String s = searchString ;
        return new Task<List<String>>() {
            @Override
            protected List<String> call() throws Exception {
                List<String> matches = new ArrayList<>();
                // do search for strings matching s
                // be sure to check isCancelled() regularly
                return matches ;
            }
        };
    }
    public String getSearchString() {
        checkThread();
        return searchString ;
    }
    public void setSearchString(String searchString) {
        checkThread();
        this.searchString = searchString ;
    }
    private void checkThread() {
        if (! Platform.isFxApplicationThread()) {
            throw new IllegalStateException("Not on FX Application Thread");
        }
    }
}

然后你可以做

public void start(Stage primaryStage) throws Exception {
    StackPane pane = new StackPane();
    SearchService searchService = new SearchService();
    searchService.setOnSucceeded(e -> {
        List<String> matches = searchService.getValue();
        // do whatever you need with search results...
        // this is called on FX application thread
    });
    TextField tf = new TextField("Please enter a word");
    tf.textProperty().addListener((obs, oldText, newText) -> {
        searchService.cancel();
        searchService.setSearchText(newText);
        searchService.restart();
    });
    pane.getChildren().add(tf);
    Scene scene = new Scene(pane);
    primaryStage.setScene(scene);
    primaryStage.show();
}

我不使用 JavaFX,但我认为您需要使用 EventListener 。尝试使用 TextListenerInputMethodListener .例如:

StackPane pane = new StackPane();
TextField tf = new TextField("Please enter a word");
tf.addTextListener(e -> System.out.println("Pushed"));
pane.getChildren().add(tf);
Scene scene = new Scene(pane);
primaryStage.setScene(scene);
primaryStage.show();

wait方法应该在synchronized块内执行:

    try{    
        while(true){
            synchronized(this){
                this.wait();
                System.out.println("clicked");
            }
        }
    } catch (Exception e){
        e.printStackTrace();
    } finally{
        lock.unlock();
    }  

最新更新