Skip to content

Instantly share code, notes, and snippets.

@brcolow
Created December 3, 2017 21:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brcolow/26370db6cab0355186d4a1d13b30fc19 to your computer and use it in GitHub Desktop.
Save brcolow/26370db6cab0355186d4a1d13b30fc19 to your computer and use it in GitHub Desktop.
JavaFX Robot Public API

TestFX, the JavaFX GUI testing framework currently requires 4 (four) classes that are part of the JDK's private API. They are:

In order to compile the project with Java 9, we use the following flags:

--add-exports javafx.graphics/com.sun.glass.ui=org.testfx
--add-exports javafx.graphics/com.sun.javafx.application=org.testfx

If the --add-exports flags are disabled in a future Java release TestFX will require these four classes to be moved into the public API to continue working.

While these classes are probably not very useful for applications to use directly, any JavaFX application wanting to write UI tests will most likely use TestFX and thus they will indirectly be using these classes.

JavaFX internal tests also use these classes for essentially the same purpose (UI tests).

Details of Usage For Each Private API Class

com.sun.javafx.application.ParametersImpl

TestFX Usage
ParametersImpl parameters = new ParametersImpl(applicationArgs);
ParametersImpl.registerParameters(application, parameters);

The parameters are set on a constructed Application.

Suggested Public API Replacement

javafx.application.Application:

/**
 * Sets the parameters for this Application.
 *
 * <p>
 * NOTE: this method should not be called from the Application constructor,
 * as it will return null. It may be called in the init() method or any
 * time after that.
 * </p>
 *
 * @param parameters the parameters to set for this Application
 */
public final Parameters setParameters(String... parameters) {
    ParametersImpl parameters = new ParametersImpl(parameters);
    ParametersImpl.registerParameters(this, parameters);
}

com.sun.glass.ui.Application

TestFX Usage
return Application.GetApplication().createRobot();

The Application class is used to instantiate a Robot.

Suggested Public API Replacement

javafx.application.Application:

https://github.com/brcolow/openjfx/blob/master/modules/javafx.graphics/src/main/java/javafx/application/Application.java#L527

com.sun.glass.ui.Pixels

TestFX Usage
@Override
public Image getCaptureRegion(Rectangle2D region) {
    return waitForAsyncFx(RETRIEVAL_TIMEOUT_IN_MILLIS, () -> {
        Pixels glassPixels = useRobot().getScreenCapture(
            (int) region.getMinX(), (int) region.getMinY(),
            (int) region.getWidth(), (int) region.getHeight()
        );
        return convertFromGlassPixels(glassPixels);
    });
}
    
private Image convertFromGlassPixels(Pixels glassPixels) {
    int width = glassPixels.getWidth();
    int height = glassPixels.getHeight();
    WritableImage image = new WritableImage(width, height);

    int bytesPerComponent = glassPixels.getBytesPerComponent();
    if (bytesPerComponent == INT_BUFFER_BYTES_PER_COMPONENT) {
        IntBuffer intBuffer = (IntBuffer) glassPixels.getPixels();
        writeIntBufferToImage(intBuffer, image);
    }

    return image;
}

private void writeIntBufferToImage(IntBuffer intBuffer,
                                   WritableImage image) {
    PixelWriter pixelWriter = image.getPixelWriter();
    double width = image.getWidth();
    double height = image.getHeight();

    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            int argb = intBuffer.get();
            pixelWriter.setArgb(x, y, argb);
        }
    }
}

Pixels is used to create a screen capture.

Suggested Public API Replacement

Bypass needing to expose the Pixels class to the public API by changing the getScreenCapture method of Robot - that is, changing:

public Pixels getScreenCapture(int x, int y, int width, int height)

to:

public Image getScreenCapture(int x, int y, int width, int height)

com.sun.glass.ui.Robot

TestFX Usage

Essentially every method of Robot is used:

public void keyPress(int code)
public void keyRelease(int code)
public int getMouseX()
public int getMouseY()
public void mouseMove(int x, int y)
public void mousePress(int buttons)
public void mouseRelease(int buttons)
public void mouseWheel(int wheelAmt)
public int getPixelColor(int x, int y)
public Pixels getScreenCapture(int x, int y, int width, int height) 
Suggested Public API Replacement

https://github.com/brcolow/openjfx/blob/master/modules/javafx.graphics/src/main/java/javafx/scene/robot/Robot.java

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment