Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically fireEvent in TextField - JavaFX

Tags:

java

javafx

Let's say a have a TextField

TextField tf = new TextField();

and I want to simulate the user pressing a key.

KeyEvent ke = new KeyEvent(KeyEvent.KEY_RELEASED, 
    KeyCode.A.toString(), KeyCode.A.toString(), 
    KeyCode.A, false, false, false, false);
tf.fireEvent(ke);

if I examine the text contents of tf, I will see this state hold true

tf.getText() == ""

What happened to my KeyEvent and why didn't the text equal "a"? I have tried this with KEY_RELEASED, KEY_PRESSED, and KEY_TYPED

Contained Example:

import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;

import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;

import java.util.concurrent.CountDownLatch;

import javax.swing.SwingUtilities;

import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

public class TextFieldExample {

    @Rule public JavaFXThreadingRule javafxRule = new JavaFXThreadingRule();
    @Test
    public void onlyAcceptValidInputs() {
        TextField tf = new TextField();
        KeyEvent ke = new KeyEvent(KeyEvent.KEY_RELEASED, 
                KeyCode.A.toString(), KeyCode.A.toString(), 
                KeyCode.A, false, false, false, false);
        tf.fireEvent(ke);
        Assert.assertEquals("A", tf.getText());
    }
}

class JavaFXThreadingRule implements TestRule {    
    /**
     * Flag for setting up the JavaFX, we only need to do this once for all tests.
     */
    private static boolean jfxIsSetup;

    @Override
    public Statement apply(Statement statement, Description description) {

        return new OnJFXThreadStatement(statement);
    }

    private static class OnJFXThreadStatement extends Statement {

        private final Statement statement;

        private OnJFXThreadStatement(Statement aStatement) {
            statement = aStatement;
        }

        private Throwable rethrownException = null;

        @Override
        public void evaluate() throws Throwable {

            if(!jfxIsSetup) {
                setupJavaFX();

                jfxIsSetup = true;
            }

            final CountDownLatch countDownLatch = new CountDownLatch(1);

            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        statement.evaluate();
                    } catch (Throwable e) {
                        rethrownException = e;
                    }
                    countDownLatch.countDown();
                }});

            countDownLatch.await();

            // if an exception was thrown by the statement during evaluation,
            // then re-throw it to fail the test
            if(rethrownException != null) {
                throw rethrownException;
            }
        }

        protected void setupJavaFX() throws InterruptedException {
            final CountDownLatch latch = new CountDownLatch(1);            
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    // initializes JavaFX environment
                    new JFXPanel();                    
                    latch.countDown();
                }
            });

            latch.await();
        }

    }
}
like image 623
Derek Avatar asked Dec 17 '25 11:12

Derek


1 Answers

It seems the text field is listening for KEY_TYPED events. Note that for KEY_TYPED events, the text should be the empty string, and the code should be KeyCode.UNDEFINED.

Note also that in your test case, the text field is never added to a live scene. Because of this, it doesn't install its skin, which contains the logic for actually processing events. So you need to force the installation of the skin by calling setSkin(...), passing in the result of the protected method createDefaultSkin():

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class TextFieldFireEvent extends Application {

    @Override
    public void start(Stage primaryStage) {
        TextField tf = new TextField() {
            {
                setSkin(createDefaultSkin());
            }
        };

        Button button = new Button("A");
        button.setOnAction(e -> {
            KeyEvent ke = new KeyEvent(KeyEvent.KEY_TYPED, 
                    "a", "", 
                    KeyCode.UNDEFINED, false, false, false, false);
                tf.fireEvent(ke);
                System.out.println(tf.getText());
        });
        VBox root =new VBox(10, /*tf,*/ button);

        root.setAlignment(Pos.CENTER);
        primaryStage.setScene(new Scene(root, 400, 400));
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
like image 141
James_D Avatar answered Dec 19 '25 23:12

James_D



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!