I have strange problems with JavaFX that look a lot like a bug. I want to do the following:
Entering fullscren when starting my application
Press escape to exit the application (not fullscreen, the entire application)
So far, I have the following code:
public class AppTest extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(Stage stage) {
stage.setOnCloseRequest(t -> {
Platform.exit();
System.exit(0);
});
stage.setFullScreenExitHint("Press ESCAPE to exit");
stage.setFullScreenExitKeyCombination(KeyCombination.NO_MATCH);
stage.setFullScreen(true);
Rectangle2D screenBounds = Screen.getPrimary().getBounds();
stage.setX(screenBounds.getMinX());
stage.setY(screenBounds.getMinY());
double screenWidth = screenBounds.getWidth();
double screenHeight = screenBounds.getHeight();
stage.setWidth(screenWidth);
stage.setHeight(screenHeight);
Group root = new Group();
Scene scene = new Scene(root);
stage.setScene(scene);
scene.setOnKeyTyped(event -> {
if(event.getCode() == KeyCode.ESCAPE) {
stage.close();
}
});
Canvas canvas = new Canvas(screenWidth, screenHeight);
root.getChildren().add(canvas);
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setFill(Color.BLUE);
gc.fillRect(0,0, screenWidth, screenHeight);
stage.show();
}
}
I'm on macOS.
In general it goes fullscreen. I'm saying in general because the real version of this code doesn't always. Sometimes, it is just a maximized window.
Then, when pressing escape, I get a maximized window instead of exiting the application.
How can I fix that?
Change:
scene.setOnKeyTyped
To:
scene.setOnKeyReleased
This explains why.
Related
Please, consider the following code:
public class JavaFxTest4 extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Button button = new Button();
button.setText("dialog");
button.setOnAction((e) -> {
Dialog<?> d = new Dialog<>();
final Window window = d.getDialogPane().getScene().getWindow();
Stage stage = (Stage) window;
stage.setMinHeight(450);
stage.setMaxHeight(450);
stage.setHeight(450);
stage.setMinWidth(600);
stage.setMaxWidth(600);
stage.setWidth(600);
window.setY(300); //<---- note this line
window.setX(660); //<---- note this line
d.showAndWait();
});
VBox root = new VBox();
root.getChildren().addAll(button);
var scene = new Scene(root, 1920, 1000);
primaryStage.setScene(scene);
primaryStage.show();
}
}
As you can see window position is 660 (x) and 300 (y). And this is the result:
As you can see x position is correct, but y position is not. Is this a bug or I misunderstand something? I use javafx 19-ea+3 and openjdk version "14.0.2" on Ubuntu 20.
It is a bug in JavaFX. Issue is here
Im building an application that shows a window that ask the user if he want to suspend the computer with two button options, one of them its a YES and the PC suspends.
The other button named "Later" supposed to hide the window and after an hour it appears again and ask the same question.
Code for the "later buttton"
noButton.setOnAction(event -> {
Done=false; //boolean to close and open the frame
Gui gui = new Gui();
try {
gui.start(classStage);
} catch (Exception e) {
e.printStackTrace();
}
});
The boolean that you see in the code is bc it was the way i think i could control that, trust me i tried in different ways but no one just help me with the issue, here is the code of the GUI class
public class Gui extends Application {
public Stage classStage = new Stage();
public static boolean Done=true;
public static boolean flag=true;
public Gui() {
}
#Override
public void start(Stage primaryStage) throws Exception {
Done = Controller.isDone();
classStage = primaryStage;
Rectangle2D primaryScreenBounds = Screen.getPrimary().getVisualBounds();
primaryStage.setX(primaryScreenBounds.getMaxX() - primaryScreenBounds.getWidth());
primaryStage.setY(primaryScreenBounds.getMaxY() - primaryScreenBounds.getHeight());
primaryStage.setAlwaysOnTop(true);
Parent root = FXMLLoader.load(getClass().getResource("MainWindow.fxml"));
primaryStage.setTitle("Alerta suspencion de equipo");
primaryStage.setScene(new Scene(root));
primaryStage.setResizable(false);
primaryStage.initStyle(StageStyle.UNDECORATED);
if (Controller.isDone() == true) {
primaryStage.show();
} else if(Controller.isDone() == false) {
primaryStage.hide();
Platform.exit(); // this is the only way that the windows close
}
}
i know that Platform.exit(); kills the program but when i only use .hide(); of the Stage nothing happens, the window never closed, the worst part is that when i use the Platform.exit() command i cant make the frame appear again...
Anyone knows a way maybe easier to hide and show a window after certain time? maybe im doing this wrong.
Regards.
It's not really clear what's going on in the code in your question. The bottom line is that you should never create an instance of Application yourself; the only Application instance should be the one created for you.
I don't actually see any need to have a separate class for the functionality you've shown (though you could, of course). All you need to do is hide classStage if the no button is pressed, and open it again in an hour:
noButton.setOnAction(event -> {
Done=false; //boolean to close and open the frame
classStage.hide();
PauseTransition oneHourPause = new PauseTransition(Duration.hours(1));
oneHourPause.setOnFinished(e -> showUI(classStage));
oneHourPause.play();
});
// ...
private void showUI(Stage stage) {
Rectangle2D primaryScreenBounds = Screen.getPrimary().getVisualBounds();
stage.setX(primaryScreenBounds.getMaxX() - primaryScreenBounds.getWidth());
stage.setY(primaryScreenBounds.getMaxY() - primaryScreenBounds.getHeight());
stage.setAlwaysOnTop(true);
Parent root = FXMLLoader.load(getClass().getResource("MainWindow.fxml"));
stage.setTitle("Alerta suspencion de equipo");
stage.setScene(new Scene(root));
stage.setResizable(false);
stage.initStyle(StageStyle.UNDECORATED);
stage.show();
}
Note that the FX Application will exit if the last window is closed, by default. So you should call Platform.setImplicitExit(false); in your init() or start() method.
I am assuming you are reloading the FXML file because the UI might have changed since it was previously loaded. Obviously if that's not the case, all you have to do is show the stage again as it is:
noButton.setOnAction(event -> {
Done=false; //boolean to close and open the frame
classStage.hide();
PauseTransition oneHourPause = new PauseTransition(Duration.hours(1));
oneHourPause.setOnFinished(e -> classStage.show());
oneHourPause.play();
});
I am wondering how to draw sharp thin lines using JavaFX. I would like my lines to be black, and 1 pixel high. Here is what I have at the moment:
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();
root.setSnapToPixel(true);
Scene scene = new Scene(root,400,400);
Line line = new Line();
Line line2 = new Line();
line.setStartX(0.0f);
line.setEndX(100f);
line.setStartY(30f);
line.setEndY(30f);
line.setStrokeWidth(1f);
line.setStrokeType(StrokeType.OUTSIDE);
line.setStroke(Color.BLACK);
line2.setStartX(50.0f);
line2.setEndX(200f);
line2.setStartY(100f);
line2.setEndY(100f);
line2.setStrokeWidth(1f);
line2.setStrokeType(StrokeType.OUTSIDE);
line2.setStroke(Color.BLACK);
root.getChildren().addAll(line, line2);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Here is what I get :
The lines are quite thick, and calling the setStrokeWidth() method with a value < 1 has no effect on the height, but makes the black color fade off. Any idea how to get a 1 pixel high line?
I can achieve it by using rectangles with a height of 1 pixel, but it seems a bit dirty.
If you use StrokeType.CENTERED, and start the x/y values on a half unit, then the lines appear to be hairlines to me.
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();
root.setSnapToPixel(true);
Scene scene = new Scene(root, 400, 400);
Line line = new Line();
Line line2 = new Line();
line.setStartX(0.5);
line.setEndX(100.5);
line.setStartY(30.5);
line.setEndY(30.5);
line.setStrokeWidth(1.0);
line.setStrokeType(StrokeType.CENTERED);
line.setStroke(Color.BLACK);
line2.setStartX(50.5);
line2.setEndX(200.5);
line2.setStartY(100.5);
line2.setEndY(100.5);
line2.setStrokeWidth(1.0);
line2.setStrokeType(StrokeType.CENTERED);
line2.setStroke(Color.BLACK);
root.getChildren().addAll(line, line2);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
My guess is that unit numbers in JavaFX are for the corners of the pixels, so specifying location + 0.5 places the line in the middle of said pixel.
I currently use the following code to switch between scenes. I want to switch between windows and KEEP the window size (so when the users change the windows size manually by resizing the window, it will stay at the chosen size even after scene change).
Scene scene = new Scene(pane); // new Scene(pane, userChosenWidth??, userChosenHeight??);
stage.setScene(scene);
stage.sizeToScene();
Does anyone know how to accomplish this?
Just call getWidth() and getHeight() on the current Scene. If you don't have a reference to the current scene, you can get one with stage.getScene().
Setting width and height in Stage worked for me.
double prevWidth = stage.getWidth();
double prevHeight = stage.getHeight();
stage.setScene(scene);
stage.setHeight(prevHeight);
stage.setWidth(prevWidth);
I created this class:
public class AppSize {
private static final String HEIGHT = "Height";
private static final String WIDTH = "Width";
private static final String Y = "Y";
private static final String X = "X";
private final static Preferences prefs = Preferences.userNodeForPackage(AppSize.class);
public static void setSize(Stage stage) {
Optional.ofNullable(prefs.getDouble(X, -1)).filter(x->x>=0).ifPresent(stage::setX);
Optional.ofNullable(prefs.getDouble(Y, -1)).filter(y->y>=0).ifPresent(stage::setY);
Optional.ofNullable(prefs.getDouble(WIDTH, -1)).filter(width->width>=0).ifPresent(stage::setWidth);
Optional.ofNullable(prefs.getDouble(HEIGHT, -1)).filter(height->height>=0).ifPresent(stage::setHeight);
stage.setOnCloseRequest(
e->{
if(stage.isFullScreen()) {
return;
}
prefs.putDouble(X, stage.getX());
prefs.putDouble(Y, stage.getY());
prefs.putDouble(WIDTH, stage.getWidth());
prefs.putDouble(HEIGHT, stage.getHeight());
});
}
}
its use:
public class App extends Application {
#Override
public void start(Stage stage) {
var label = new Label("AppSize test.");
var scene = new Scene(new StackPane(label), 640, 480);
stage.setScene(scene);
AppSize.setSize(stage);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
Looks like Transform class in JavaFX contains 3 coordinates (x, y and z).
What will happen if I rotate out of plane? Will it do perspective?
UPDATE
Actually object disappears if rotated out of plane even by 1 degree. Why?
public class TransformTry extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Drawing Operations Test");
Group root = new Group();
Canvas canvas = new Canvas(300, 250);
//canvas.getTransforms().add(new Rotate(1, new Point3D(0, 1, 0))); // square disappears
canvas.getTransforms().add(new Rotate(1, new Point3D(0, 0, 1))); // rotates correctly
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.strokeRect(-50, -50, 100, 100);
root.getChildren().add(canvas);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
UPDATE 2
I found a way to use perspective camera, but it works strange: it looks always from above the center of a window, so out-of-plane object changes on window resize:
public class ShapeTry01 extends Application {
#Override
public void start(Stage stage) throws Exception {
Shape shape = new Rectangle(100,100,50,50);
shape.setStroke(Color.RED);
shape.setFill(null);
Group group = new Group();
group.getChildren().add(shape);
//group.getTransforms().add(new Rotate(10, new Point3D(0, 0, 1)));
group.getTransforms().add(new Rotate(10, new Point3D(0, 1, 0)));
PerspectiveCamera camera = new PerspectiveCamera();
camera.setFieldOfView(45);
Scene scene = new Scene(group);
scene.setCamera( camera );
stage.setTitle("ShapeTry01");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
JavaFX 2 was started with 3D in mind, thus a lot of API has z coordinate mentioned. But actually useful 3D was added only in JavaFX8 (to be released in next year).
You can see documentation here: http://docs.oracle.com/javafx/8/3d_graphics/jfxpub-3d_graphics.htm and try developers preview: https://jdk8.java.net/download.html