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

huangapple go评论76阅读模式
英文:

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

问题

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();
    }
}
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);
        textfield.setText("");
        notifyAll();
    }

    public void startprogram() {
        int etat = 0;
        int run = 1;
        while (run == 1) {
            textarea.setText("1: launch method");
            pause.waitinput();
            etat = stock.getEntrystr();
            switch (etat) {
                case 1:
                    // runs a method
                    break;
                default:
                    break;
            }
        }
    }
}
英文:

I use javafx, I have a TextField and a Button, when the button is pressed, it saves what is written in the TextField in a String. What I want to create is a method to mark a pause, while waiting for the Button to get pressed.

I have a class named pause.java, where I tried to put a obj.wait(); and a notifyAll(); in the event where the button is pressed, but the window isn't accessible during this time, I can't press the button or enter anything in the TextField.

So what I found was to put the obj.wait(); in a task, then I don't know why but it directly breaks out of the wait.

Here is my 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&lt;Void&gt; sleeper = new Task&lt;Void&gt;() {
			@Override
			protected Void call() throws Exception {
				synchronized (obj) {
					try {
						String write = &quot;Waiting for input...&quot;;
						logger.log(Level.INFO, write);
						obj.wait();
						logger.log(Level.INFO, &quot;Done&quot;);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				return null;
			}
		};
		new Thread(sleeper).start();

	}
}

How do I have to modify it to make it wait, while still having access to the GUI?

Here's my code simplified for the problem:

AlbumManager.java, where my main is.

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(&quot;Main.fxml&quot;));
		Scene scene = new Scene(root);

		primaryStage.setTitle(&quot;Album Manager&quot;);
		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(&quot;&quot;);
		notifyAll();
	}
	
	public void startprogram() {
		int etat = 0;
		int run = 1;
		while (run == 1) {
			textarea.setText(&quot;1: launch method&quot;);
			pause.waitinput();     // here I want to wait for an input
            etat = stock.getEntrystr();
			switch (etat) {
			case 1:
				//runs a method
                break;
			default:
				break;
			}
		}	
	}
}


答案1

得分: 1

以下是翻译好的内容:

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

(另外,您对wait()的使用是错误的,如果您修复了这个问题,线程永远不会被唤醒,因为您在调用wait()的相同对象上没有调用notifyAll()。)

您可以通过以下方式实现您似乎想要做的事情:

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;
        }   
    }
}

请注意,我已经将代码中的特殊字符(例如&quot;)替换为了正确的字符。

英文:

It's really not clear what you're trying to achieve here that needs a separate thread: all the separate thread seems to try to do is wait until the button is pressed, and then execute some code. That functionality is already provided by the event management system in JavaFX (and the same is true for any UI toolkit): just execute the code in the event handler.

(As an aside, your use of wait() is incorrect, and if you fix that, the thread will never wake up because you are not calling notifyAll() on the same object on which you are calling wait().)

You can achieve what you seem to be trying to do simply with

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(&quot;&quot;);
        processInput();
    }
    
    public void processInput() {
        int etat = stock.getEntrystr();
        switch (etat) {
        case 1:
            //runs a method
            break;
        default:
            break;
        }   
    }
}

答案2

得分: -2

你需要使用一个Runnable来启动另一个线程,这样在保存操作完成时不会阻塞你的UI线程。

你可以通过在按钮上设置监听器来实现这一点,当按钮被点击时,它会在新线程上启动保存操作。
添加监听器到按钮并在新线程上启动操作的代码如下所示:

// 创建鼠标事件处理程序
EventHandler<MouseEvent> eventHandler = new EventHandler<MouseEvent>() {
    @Override
    public void handle(MouseEvent e) {
        MainController controller = new MainController();
        controller.start();
    }
};
// 注册事件过滤器
button.addEventFilter(MouseEvent.MOUSE_CLICKED, eventHandler);

你发布的代码实际上没有做任何事情。你对waitinput()的调用只是打印日志并调用了wait()wait()不是你想要的,因为这个操作的目的是将线程挂起,直到它被通知,而不是为了在单独的线程中执行任务。移除obj.wait(),并添加一个在按钮被点击时调用你的日志记录方法的监听器。同时,去掉这个while循环。EventHandler会在后台处理事件。

英文:

You have to start another thread using a Runnable, so your UI thread does not get blocked while the save-operation completes.

You can do this by placing a listener on the button that will start the save-operation on a new thread when the button is clicked.
The code for adding a listener to a button that starts a new thread would look something like this:

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

The code you posted doesn't really do anything. Your call to waitinput() only logs and calls wait(). wait() is not what you want, since this operation is intended for putting a thread on hold until it is notified, not for executing a task in a seperate thread. Remove the obj.wait(), and add a listener that calls your logging method when the button is clicked. Also, get rid of the while-loop. The EventHandler will take care of events in the background.

huangapple
  • 本文由 发表于 2020年8月25日 20:55:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/63579319.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定