使用内部带有 'wait()' 的 JavaFX 创建任务

Creating a Task with JavaFX with a 'wait()' inside

我使用 javafx,我有一个 TextField 和一个 Button,当按下按钮时,它会将 TextField 中写入的内容保存在一个字符串中。我想要创建的是一种标记暂停的方法,同时等待按钮被按下。

我有一个名为 pause.java 的 class,我试图在按下按钮的事件中放置一个 obj.wait(); 和一个 notifyAll();,但是 window 在此期间无法访问,我无法按下按钮或在 TextField 中输入任何内容。

所以我发现是把obj.wait();放在一个task里面,然后不知道为什么直接break out了wait

这是我的 pause.java

package net.jpajavafx;

import java.util.logging.*;
import javafx.concurrent.Task;

public class pause {
    Logger logger = Logger.getLogger(pause.class.getName());
    MainController obj = new MainController();

    public void waitinput() {
        Task<Void> sleeper = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                synchronized (obj) {
                    try {
                        String write = "Waiting for input...";
                        logger.log(Level.INFO, write);
                        obj.wait();
                        logger.log(Level.INFO, "Done");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                return null;
            }
        };
        new Thread(sleeper).start();

    }
}

我如何修改它以使其等待,同时仍然可以访问 GUI?

这是我针对问题简化的代码:

AlbumManager.java,我的主要是

package net.jpajavafx;


import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.*;
import javafx.application.*;
import javafx.fxml.FXMLLoader;

public class AlbumManager extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {

        Parent root = FXMLLoader.load(getClass().getResource("Main.fxml"));
        Scene scene = new Scene(root);

        primaryStage.setTitle("Album Manager");
        primaryStage.setScene(scene);
        primaryStage.show();

    }

    public static void main(String[] args) {

        launch(args);

    }

}

MainController.java:

package net.jpajavafx;
import javafx.event.ActionEvent;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.fxml.FXML;
import java.util.logging.*;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

public class MainController {

    @FXML
    private TextArea textarea;
    @FXML
    private TextField textfield;

   Variablesstoring stock = new Variablesstoring();
    
    public void ok(ActionEvent event) {
        String getValue = textfield.getText();
        stock.setEntrystr(getValue);          //here i have something to put in an Int, I put it aside to reduce the length
        textfield.setText("");
        notifyAll();
    }
    
    public void startprogram() {
        int etat = 0;
        int run = 1;
        while (run == 1) {
            textarea.setText("1: launch method");
            pause.waitinput();     // here I want to wait for an input
            etat = stock.getEntrystr();
            switch (etat) {
            case 1:
                //runs a method
                break;
            default:
                break;
            }
        }   
    }
}


您必须 start another thread using a Runnable,这样您的 UI 线程就不会在 save-operation 完成时被阻塞。

您可以通过在按钮上放置一个侦听器来实现此目的,当单击该按钮时,该侦听器将在新线程上启动 save-operation。 将侦听器添加到启动新线程的按钮的代码如下所示:

//Creating the mouse event handler 
  EventHandler<MouseEvent> eventHandler = new EventHandler<MouseEvent>() { 
     @Override 
     public void handle(MouseEvent e) { 
     MainController controller = new MainController();
     controller.start();
     } 
  };  
//Registering the event filter 
button.addEventFilter(MouseEvent.MOUSE_CLICKED, eventHandler);   

您发布的代码实际上没有任何作用。您对 waitinput() 的调用仅记录和调用 wait()wait() 不是您想要的,因为此操作旨在暂停线程直到收到通知,而不是在单独的线程中执行任务。删除 obj.wait(),并添加一个在单击按钮时调用您的日志记录方法的侦听器。另外,去掉 while-loop。 EventHandler 将在后台处理事件。

真的不清楚你在这里想要实现什么需要一个单独的线程:所有单独的线程似乎都试图做的是等到按钮被按下,然后执行一些代码。 JavaFX 中的事件管理系统已经提供了该功能(对于任何 UI 工具包也是如此):只需执行事件处理程序中的代码。

(顺便说一句,您对 wait() 的使用是不正确的,如果您修复该问题,线程将永远不会唤醒,因为您没有在您调用的同一对象上调用 notifyAll()正在呼叫 wait().)

您可以通过

轻松实现您似乎想做的事情
package net.jpajavafx;
import javafx.event.ActionEvent;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.fxml.FXML;
import java.util.logging.*;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

public class MainController {

    @FXML
    private TextArea textarea;
    @FXML
    private TextField textfield;

   Variablesstoring stock = new Variablesstoring();
    
    public void ok(ActionEvent event) {
        String getValue = textfield.getText();
        stock.setEntrystr(getValue);          //here i have something to put in an Int, I put it aside to reduce the length
        textfield.setText("");
        processInput();
    }
    
    public void processInput() {
        int etat = stock.getEntrystr();
        switch (etat) {
        case 1:
            //runs a method
            break;
        default:
            break;
        }   
    }
}