JavaFX Application Menu - javafx

So I've looked around a fair bit, but I've not been able to find any information on how to make an application menu in JavaFX.
I've seen a project 'Jayatana' which seems to allow applications to have proper application menus in Ubuntu using Intellij at least (as an example).
I've also seen a few suggestions that using something like the following will work for OS X users:-
final List<MenuBase> menus = new ArrayList<>();
menus.add(GlobalMenuAdapter.adapt(menu));
Toolkit.getToolkit().getSystemMenu().setMenus(menus);
And there is also the NSMenuFX project, again for OS X.
And I've also seen the java-gnome project which I think only works for Swing.
But what I'd really like is some way of making application menus, preferably in a non-OS specific manner.
I'm happy to use a third party jar or whatever which does the heavy lifting but really, does anything like this exist?
At this point would my best bet be using Swing to create the shell of the JavaFX application and use methods which will integrate application menus with Swing instead? If that's the case, is there something that can do this automatically from JavaFX and handle the switching of the differing implementations?
edit
In the end, I simply used a combination of both Swing and JavaFX. I put the JavaFX app inside which allowed me to use the application menus which already work in Swing.
Not ideal, but it did work.

I think you are just looking for MenuBar.useSystemMenuBarProperty(). If you call this method on a menu bar, then if the platform supports system menus (e.g. OS X) the menu will not appear in the scene graph but will be used as the system menu.
SSCCE:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class SystemMenuExample extends Application {
#Override
public void start(Stage primaryStage) {
MenuBar menuBar = new MenuBar();
Menu menu = new Menu("File");
MenuItem quit = new MenuItem("Quit");
quit.setOnAction(e -> Platform.exit());
menu.getItems().add(quit);
menuBar.getMenus().add(menu);
menuBar.setUseSystemMenuBar(true);
BorderPane root = new BorderPane();
root.setTop(menuBar);
Scene scene = new Scene(root, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

The solution provided by James_D is the standard way of dealing with this in JavaFX but this solution does not work on the Mac, e.g., if you plan to internationalize your application. The Mac introduces some default menu items which you cannot properly deal with that way. That's where the NSMenuFX project comes into play.
NSMenuFX helps you to
Customize the auto-generated application menu of your JavaFX app
Automatically use the same menu bar for all stages
Create common OS X menus like the Window menu
If you can live with the deficiencies of the JavaFX solution use it, if not have a look at NSMenuFX or any of the other projects mentioned for Linux.

This is my code. Howe can i add this to my below code. After choosing start, then i want to run the game
private static final double SCREENWIDTH = 615.0;
private static final double SCREENHEIGHT = 635.0;enter code here
private GridPane root = new GridPane();
private Scene scene = new Scene(root);
private Stage primaryStage;
private GameController controller;
private boolean gewonnen;
private boolean pauze;
private int opstartSeconden;
private int aantalLevels;
private List<Level> levels;
public static void main(String args[]) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws NoPathPossibleException, StartAndEndAreThereSameException {
controller = new GameController(root, scene);// game controler wordt gemaakt
new Thread(this).start(); // we starten het spel in een nieuwe thread. we
this.primaryStage = primaryStage;
primaryStage.setTitle("HapMan9000");
primaryStage.setWidth(SCREENWIDTH);
primaryStage.setHeight(SCREENHEIGHT);
primaryStage.setResizable(false);
primaryStage.setScene(scene);
primaryStage.setOnCloseRequest(e -> closeProgram());
scene.setCursor(Cursor.NONE);
primaryStage.show();
levels = new ArrayList<>();
}
/**
* Zorgt ervoor dat het spel in zijn geheel wordt afgesloten.
*/
private void closeProgram() {
Platform.exit();
System.exit(0);
}
public void spelPauzeren() {
pauze = true;
}

Related

How to Access JavaFX Virtual Keyboard (FXVK) Using Open JDK 15 or beyond?

I use the javafx virtual keyboard with open jdk 8. At times I have to access the virtual keyboard to prevent it from displaying when certain text fields get focus. An example of this is a screen where an operator has to scan in multiple barcodes. This virtual keyboard gets in the way. With open jdk 8 we were able to disable the virtual keyboard like this:
FXVK.detach(); //after importing "com.sun.javafx.scene.control.skin.FXVK"
We are now upgrading to open jdk 15 and building our UI with gradle. "com.sun.javafx.scene.control.skin.FXVK" is no longer accessible with a modular project with gradle. I don't believe using a different virtual keyboard is an option so can anyone explain how to access this FXVK class after java 8?
Is there a way to use --add-exports or --patch-module with a JAR to patch JavaFX to gain access to the internal class?
Below is the code for a sample project that shows this problem.
This is the JavaFX Application class that simply displays a text field and shows the code I could use with java 8 to not show the virtual keyboard.
package com.test.sampleapp.application;
////not accessible in java 15
//import com.sun.javafx.scene.control.skin.FXVK;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application{
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception
{
Label label = new Label("Text field below");
TextField textField = new TextField();
VBox vbox = new VBox(label);
vbox.getChildren().add(textField);
Scene scene = new Scene(vbox);
primaryStage.setScene(scene);
primaryStage.show();
textField.focusedProperty().addListener(new ChangeListener<Boolean>()
{
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue,
Boolean newValue)
{
// If focused
if (newValue)
{
//Need this to disable the virtual keyboard when using a textfield with scanning
//FXVK.detach();
}
}
});
}
}
Then I needed to add a wrapper class to have the virtual keyboard show up. Please note that most of the time I do use the virtual keyboard when text fields get focus, it's other times where I need to be able to programmatically disable it during certain situations.
The wrapper class:
package com.test.sampleapp.application;
import java.lang.reflect.Method;
public class AppWrapper
{
public static void main(String[] args) throws Exception
{
Class<?> app = Class.forName("com.test.sampleapp.application.Main");
Method main = app.getDeclaredMethod("main", String[].class);
System.setProperty("com.sun.javafx.isEmbedded", "true");
System.setProperty("com.sun.javafx.touch", "true");
System.setProperty("com.sun.javafx.virtualKeyboard", "javafx");
Object[] arguments = new Object[]{args};
main.invoke(null, arguments);
}
}
Let me know if you need anything else such as the build.gradle file however this is mostly just an issue using java 9 or beyond.
The FXVK class still exists in the same package, so the only issue is that its package is not exported by the javafx.controls module. If you must use this internal class, then you can pass an appropriate --add-exports JVM argument both at compile-time and at run-time.
Here's a simple application that calls FXVK#detach():
// Will fail at compile-time if the '--add-exports` argument is not
// passed to 'javac'
import com.sun.javafx.scene.control.skin.FXVK;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
var root = new StackPane(new Label("Hello, World!"));
primaryStage.setScene(new Scene(root, 600, 400));
primaryStage.show();
// Will fail at run-time if the '--add-exports' argument is
// not passed to 'java'
FXVK.detach();
}
}
Assuming you put the Main.java file in your working directory, you can compile it with:
javac -p <path-to-fx> --add-modules javafx.controls --add-exports javafx.controls/com.sun.javafx.scene.control.skin=ALL-UNNAMED Main.java
And run it with:
java -p <path-to-fx> --add-modules javafx.controls --add-exports javafx.controls/com.sun.javafx.scne.control.skin=ALL-UNNAMED Main
If your code is modular then you can get rid of the --add-modules and you must change ALL-UNNAMED to the name of your module. Plus, make sure to launch your application via --module (or -m). Note the -p above is shorthand for --module-path.
If you use a build tool (e.g., Maven, Gradle, etc.), then you'll have to lookup how to set these JVM arguments for that tool. You'll also have to take into account how you deploy your application. For instance, if you use jpackage then you can use its --java-options argument to set the --add-exports option for when your application is launched.
You may also need to tell your IDE that you are giving yourself access to the internal package. Otherwise, your IDE will likely yell at you for trying to use an inaccessible type.

Filling a Health Bar over time Javafx [duplicate]

I try to run in JavaFX application background thread periodically, which modifies some GUI property.
I think I know how to use Task and Service classes from javafx.concurrent and can't figure it out how to run such periodic task without using Thread#sleep() method. It would be nice if I can use some Executor from Executors fabricate methods (Executors.newSingleThreadScheduledExecutor())
I tried to run Runnable every 5 sec, which restarts javafx.concurrent.Service but it hangs immediately as service.restart or even service.getState() is called.
So finally I use Executors.newSingleThreadScheduledExecutor(), which fires my Runnable every 5 sec and that Runnable runs another Runnable using:
Platform.runLater(new Runnable() {
//here i can modify GUI properties
}
It looks very nasty :( Is there a better way to do this using Task or Service classes?
You can use Timeline for that task:
Timeline fiveSecondsWonder = new Timeline(
new KeyFrame(Duration.seconds(5),
new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("this is called every 5 seconds on UI thread");
}
}));
fiveSecondsWonder.setCycleCount(Timeline.INDEFINITE);
fiveSecondsWonder.play();
for the background processes (which don't do anything to the UI) you can use old good java.util.Timer:
new Timer().schedule(
new TimerTask() {
#Override
public void run() {
System.out.println("ping");
}
}, 0, 5000);
Preface: This question is often the duplicate target for questions which ask how to perform periodic actions in JavaFX, whether the action should be done in the background or not. While there are already great answers to this question, this answer attempts to consolidate all the given information (and more) into a single answer and explain/show the differences between each approach.
This answer focuses on the APIs available in JavaSE and JavaFX and not third-party libraries such as ReactFX (showcased in Tomas Mikula's answer).
Background Information: JavaFX & Threads
Like most mainstream GUI frameworks, JavaFX is single-threaded. This means there's a single thread dedicated to reading and writing the state of the UI and processing user-generated events (e.g. mouse events, key events, etc.). In JavaFX this thread is called the "JavaFX Application Thread", sometimes shortened to just "FX thread", but other frameworks may call it something else. Some other names include "UI thread", "event-dispatch thread", and "main thread".
It is absolutely paramount that anything connected to the GUI showing on screen is only ever accessed or manipulated on the JavaFX Application Thread. The JavaFX framework is not thread-safe and using a different thread to improperly read or write the state of the UI can lead to undefined behavior. Even if you don't see any externally-visible problems, access to state shared between threads without the necessary synchronization is broken code.
Many GUI objects, however, can be manipulated on any thread as long as they aren't "live". From the documentation of javafx.scene.Node:
Node objects may be constructed and modified on any thread as long they are not yet attached to a Scene in a Window that is showing [emphasis added]. An application must attach nodes to such a Scene or modify them on the JavaFX Application Thread.
But other GUI objects, such as Window and even some subclasses of Node (e.g. WebView), are more strict. For instance, from the documentation of javafx.stage.Window:
Window objects must be constructed and modified on the JavaFX Application Thread.
If you're unsure about the threading rules of a GUI object, its documentation should provide the needed information.
Since JavaFX is single-threaded you also have to make sure never to block or otherwise monopolize the FX thread. If the thread is not free to do its job then the UI is never redrawn and new user-generated events can't be processed. Not following this rule can lead to the infamous unresponsive/frozen UI and your users are not happy.
It's virtually always wrong to sleep the JavaFX Application Thread.
Periodic Tasks
There are two different kinds of periodic tasks, at least for the purposes of this answer:
Periodic foreground "tasks".
This could include things such as a "blinking" node or periodically switching between images.
Periodic background tasks.
An example might be periodically checking a remote server for updates and, if there are any, downloading the new information and displaying it to the user.
Periodic Foreground Tasks
If your periodic task is short and simple then using a background thread is overkill and just adds unnecessary complexity. The more appropriate solution is to use the javafx.animation API. Animations are asynchronous but stay entirely within the JavaFX Application Thread. In other words, animations provide a way to "loop" on the FX thread, with delays between each iteration, without actually using loops.
There are three classes uniquely suited to periodic foreground tasks.
Timeline
A Timeline is made up of one or more KeyFrames. Each KeyFrame has a specified time of when it should complete. Each one can also have an "on finished" handler which is invoked after the specified amount of time has elapsed. This means you can create a Timeline with a single KeyFrame that periodically executes an action, looping as many times as you want (including forever).
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class App extends Application {
#Override
public void start(Stage primaryStage) {
Rectangle rect = new Rectangle(100, 100);
// toggle the visibility of 'rect' every 500ms
Timeline timeline =
new Timeline(new KeyFrame(Duration.millis(500), e -> rect.setVisible(!rect.isVisible())));
timeline.setCycleCount(Animation.INDEFINITE); // loop forever
timeline.play();
primaryStage.setScene(new Scene(new StackPane(rect), 200, 200));
primaryStage.show();
}
}
Since a Timeline can have more than one KeyFrame it's possible to have actions being executed at different intervals. Just keep in mind that the times of each KeyFrame do not stack. If you have one KeyFrame with a time of two seconds followed by another KeyFrame with a time of two seconds, both KeyFrames will finish two seconds after the animation is started. To have the second KeyFrame finish two seconds after the first one, its time needs to be four seconds.
PauseTransition
Unlike the other animation classes, a PauseTransition is not used to actually animate anything. It's main purpose is to be used as a child of SequentialTransition to put a pause between two other animations. However, like all subclassses of Animation it can have an "on finished" handler that's executed after it completes, allowing it to be used for periodic tasks.
import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class App extends Application {
#Override
public void start(Stage primaryStage) {
Rectangle rect = new Rectangle(100, 100);
// toggle the visibility of 'rect' every 500ms
PauseTransition pause = new PauseTransition(Duration.millis(500));
pause.setOnFinished(
e -> {
rect.setVisible(!rect.isVisible());
pause.playFromStart(); // loop again
});
pause.play();
primaryStage.setScene(new Scene(new StackPane(rect), 200, 200));
primaryStage.show();
}
}
Notice the on-finished handler invokes playFromStart(). This is necessary to "loop" the animation again. The cycleCount property can't be used since the on-finished handler is not invoked at the end of each cycle, it's only invoked at the end of the last cycle. The same thing is true of Timeline; the reason it works with Timeline above is because the on-finished handler isn't registered with the Timeline but with the KeyFrame.
Since the cycleCount property can't be used for PauseTransition for multiple cycles it makes it more difficult to loop only a certain number of times (rather than forever). You have to keep track of the state yourself and only invoke playFromStart() when appropriate. Keep in mind that local variables declared outside a lambda expression or anonymous class but used inside said lambda expression or anonymous class must be final or effectively final.
AnimationTimer
The AnimationTimer class is the lowest level of JavaFX's animation API. It's not a subclass of Animation and thus doesn't have any of the properties that were used above. Instead, it has an abstract method that, when the timer is started, is invoked once per frame with the timestamp (in nanoseconds) of the current frame: #handle(long). In order to execute something periodically with AnimationTimer (other than once per frame) will require manually calculating the time differences between invocations of handle using the method's argument.
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class App extends Application {
#Override
public void start(Stage primaryStage) {
Rectangle rect = new Rectangle(100, 100);
// toggle the visibility of 'rect' every 500ms
AnimationTimer timer =
new AnimationTimer() {
private long lastToggle;
#Override
public void handle(long now) {
if (lastToggle == 0L) {
lastToggle = now;
} else {
long diff = now - lastToggle;
if (diff >= 500_000_000L) { // 500,000,000ns == 500ms
rect.setVisible(!rect.isVisible());
lastToggle = now;
}
}
}
};
timer.start();
primaryStage.setScene(new Scene(new StackPane(rect), 200, 200));
primaryStage.show();
}
}
For most use cases similar to the above, using either Timeline or PauseTransition would be the better option.
Periodic Background Tasks
If your periodic task is time-consuming (e.g. expensive computations) or blocking (e.g. I/O) then a background thread needs to be used. JavaFX comes with some concurrency utilities built-in to aid with communication between background threads and the FX thread. These utilities are described in:
The Concurrency in JavaFX tutorial, and
The documentation of the classes in the javafx.concurrent package.
For periodic background tasks that need to communicate with the FX thread, the class to use is javafx.concurrent.ScheduledService. That class will execute its task periodically, restarting after successful execution, based on a specified period. If configured to do so it will even retry a configurable amount of times after failed executions.
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.concurrent.ScheduledService;
import javafx.concurrent.Task;
import javafx.concurrent.Worker.State;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
public class App extends Application {
// maintain a strong reference to the service
private UpdateCheckService service;
#Override
public void start(Stage primaryStage) {
service = new UpdateCheckService();
service.setPeriod(Duration.seconds(5));
Label resultLabel = new Label();
service.setOnRunning(e -> resultLabel.setText(null));
service.setOnSucceeded(
e -> {
if (service.getValue()) {
resultLabel.setText("UPDATES AVAILABLE");
} else {
resultLabel.setText("UP-TO-DATE");
}
});
Label msgLabel = new Label();
msgLabel.textProperty().bind(service.messageProperty());
ProgressBar progBar = new ProgressBar();
progBar.setMaxWidth(Double.MAX_VALUE);
progBar.progressProperty().bind(service.progressProperty());
progBar.visibleProperty().bind(service.stateProperty().isEqualTo(State.RUNNING));
VBox box = new VBox(3, msgLabel, progBar);
box.setMaxHeight(Region.USE_PREF_SIZE);
box.setPadding(new Insets(3));
StackPane root = new StackPane(resultLabel, box);
StackPane.setAlignment(box, Pos.BOTTOM_LEFT);
primaryStage.setScene(new Scene(root, 400, 200));
primaryStage.show();
service.start();
}
private static class UpdateCheckService extends ScheduledService<Boolean> {
#Override
protected Task<Boolean> createTask() {
return new Task<>() {
#Override
protected Boolean call() throws Exception {
updateMessage("Checking for updates...");
for (int i = 0; i < 1000; i++) {
updateProgress(i + 1, 1000);
Thread.sleep(1L); // fake time-consuming work
}
return Math.random() < 0.5; // 50-50 chance updates are "available"
}
};
}
}
}
Here's a note from the documentation of ScheduledService:
Timing for this class is not absolutely reliable. A very busy event thread might introduce some timing lag into the beginning of the execution of the background Task, so very small values for the period or delay are likely to be inaccurate. A delay or period in the hundreds of milliseconds or larger should be fairly reliable.
And another:
The ScheduledService introduces a new property called lastValue. The lastValue is the value that was last successfully computed. Because a Service clears its value property on each run, and because the ScheduledService will reschedule a run immediately after completion (unless it enters the cancelled or failed states), the value property is not overly useful on a ScheduledService. In most cases you will want to instead use the value returned by lastValue.
The last note means binding to the value property of a ScheduledService is in all likelihood useless. The example above works despite querying the value property because the property is queried in the onSucceeded handler, before the service is rescheduled.
No Interaction with UI
If the periodic background task does not need to interact with the UI then you can use the standard APIs of Java instead. More specifically, either:
The java.util.Timer class (not javax.swing.Timer),
Or the more modern java.util.concurrent.ScheduledExecutorService interface.
Note that ScheduledExecutorService supports thread pools, unlike Timer which only supports a single thread.
ScheduledService is not an Option
If for whatever reason you can't use ScheduledService, but need to need to interact with the UI anyway, then you need to make sure the code interacting with the UI, and only that code, is executed on the FX thread. This can be accomplished by using Platform#runLater(Runnable).
Run the specified Runnable on the JavaFX Application Thread at some unspecified time in the future. This method, which may be called from any thread, will post the Runnable to an event queue and then return immediately to the caller. The Runnables are executed in the order they are posted. A runnable passed into the runLater method will be executed before any Runnable passed into a subsequent call to runLater. If this method is called after the JavaFX runtime has been shutdown, the call will be ignored: the Runnable will not be executed and no exception will be thrown.
NOTE: applications should avoid flooding JavaFX with too many pending Runnables. Otherwise, the application may become unresponsive. Applications are encouraged to batch up multiple operations into fewer runLater calls. Additionally, long-running operations should be done on a background thread where possible, freeing up the JavaFX Application Thread for GUI operations.
[...]
Heed the note from the above documentation. The javafx.concurent.Task class avoids this by coalescing updates to its message, progress, and value properties. This is currently implemented by using an AtomicReference and strategic get-and-set operations. If interested, you can take a look at the implementation (JavaFX is open source).
I would Prefer the PauseTransition:
PauseTransition wait = new PauseTransition(Duration.seconds(5));
wait.setOnFinished((e) -> {
/*YOUR METHOD*/
wait.playFromStart();
});
wait.play();
Here is a solution using Java 8 and ReactFX. Say that you want to periodically recompute the value of Label.textProperty().
Label label = ...;
EventStreams.ticks(Duration.ofSeconds(5)) // emits periodic ticks
.supplyCompletionStage(() -> getStatusAsync()) // starts a background task on each tick
.await() // emits task results, when ready
.subscribe(label::setText); // performs label.setText() for each result
CompletionStage<String> getStatusAsync() {
return CompletableFuture.supplyAsync(() -> getStatusFromNetwork());
}
String getStatusFromNetwork() {
// ...
}
Compared to Sergey's solution, you don't dedicate the whole thread to getting status from the network, but instead use the shared thread pool for that.
You can use ScheduledService too. I am using this alternative after noticing that during the use of Timeline and PauseTransition occurred some UI freezes in my application, especially when the user interacts with the elements of a MenuBar (on JavaFX 12). Using the ScheduledService these problems no longer occurred.
class UpdateLabel extends ScheduledService<Void> {
private Label label;
public UpdateLabel(Label label){
this.label = label;
}
#Override
protected Task<Void> createTask(){
return new Task<Void>(){
#Override
protected Void call(){
Platform.runLater(() -> {
/* Modify you GUI properties... */
label.setText(new Random().toString());
});
return null;
}
}
}
}
And then, use it:
class WindowController implements Initializable {
private #FXML Label randomNumber;
#Override
public void initialize(URL u, ResourceBundle res){
var service = new UpdateLabel(randomNumber);
service.setPeriod(Duration.seconds(2)); // The interval between executions.
service.play()
}
}
Was not easy find the way to programing this kind of behavior may be because my process reads I/O, works in milliseconds and I felt was often interrupted by GUI thread, but I made it by creating a BackgroundProcess class & with the help of ScheduledExecutorService.
In the controlle side, I use PauseTransition to read volatile (no contention) info only.
Sample code :
public class HelloApplication extends Application {
final ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor();
final BackgroundProcess backgroundProcess = new BackgroundProcess();
#Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 720, 610);
HelloController helloController = fxmlLoader.getController();
helloController.setBackgroundProcess(backgroundProcess);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
scheduledExecutor.scheduleWithFixedDelay(
backgroundProcess,
0, 111, TimeUnit.MILLISECONDS);
}
#Override
public void stop() throws Exception {
super.stop();
scheduledExecutor.shutdown();
}
...
}
public class BackgroundProcess implements Runnable{
volatile String status = "";
#Override
public void run() {
status = newStatus();
}
...
}
public class HelloController {
#FXML
protected void initialize() {
PauseTransition refresh = new PauseTransition(Duration.millis(111));
wait.setOnFinished((e) -> {
statusLabel.setText(backgroundProcess.status);
refresh.playFromStart();
});
refresh.play();
}
...
}
To read synchronized (contention) info I use ScheduledService to prepare the info and prevent interruptions in the JavaFX thread.
This is a more complex sample code:
public class HelloApplication extends Application {
final ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor();
final BackgroundProcess backgroundProcess = new BackgroundProcess();
#Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 720, 610);
HelloController helloController = fxmlLoader.getController();
helloController.setBackgroundProcess(backgroundProcess);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
scheduledExecutor.scheduleWithFixedDelay(
backgroundProcess,
0, 111, TimeUnit.MILLISECONDS);
}
#Override
public void stop() throws Exception {
super.stop();
scheduledExecutor.shutdown();
}
...
}
public class BackgroundProcess implements Runnable{
volatile String status = "";
LinkedTransferQueue<String> queue = new LinkedTransferQueue();
#Override
public void run() {
status = newStatus();
addToQueue();
}
...
}
public class HelloController {
static class SynchronizedInformation {
ArrayList<String> list;
}
private SynchronizedInformation prepareSynchronizedInformation() {
if (backgroundProcess.queue.isEmpty()) {
return null;
}
final SynchronizedInformation r = new SynchronizedInformation();
int size = backgroundProcess.queue.size();
r.list = new ArrayList<>(size);
String line;
while (r.list.size() < size && null != (line = backgroundProcess.queue.poll())) {
r.list.add(line);
}
return r;
}
private void refreshSynchronizedInformation(SynchronizedInformation synchronizedInformation) {
if (null != synchronizedInformation) {
synchronizedInformation.list.forEach(textArea::appendText);
}
statusLabel.setText(backgroundProcess.incoming);
}
#FXML
protected void initialize() {
ScheduledService<SynchronizedInformation> svc = new ScheduledService<>() {
#Override
protected Task<SynchronizedInformation> createTask() {
return new Task<SynchronizedInformation>() {
#Override
protected SynchronizedInformation call() throws Exception {
return prepareSynchronizedInformation();
}
};
}
};
svc.setDelay(Duration.millis(111));
svc.setOnSucceeded(e -> refreshSynchronizedInformation(svc.getValue()));
svc.start();
...
}

Is it possible to launch a JavaFX application through another JavaFX application?

Can I know why there is an error when I say.
Stage s = new Stage();
new CaeserCipherFX().start(s);
This is my code below. I need to launch another JavaFX Application from this one. Please help. Thank you.
public class Main extends Application
{
String args[];
#Override
public void start(Stage stage) throws Exception
{
// creating types of encryptions (Button)
Button caeserCipher = new Button("1. Caeser Cipher");
Button runningKeyCipher = new Button("2. Running Key Cipher");
Button trithemiusCipher = new Button("3. Trithemius Cipher");
Button vignereCipher = new Button("4. Vignere Cipher");
//setting styles
caeserCipher.setTextFill(Color.BLUE);
runningKeyCipher.setTextFill(Color.BLUE);
trithemiusCipher.setTextFill(Color.BLUE);
vignereCipher.setTextFill(Color.BLUE);
/*need to add more!*/
//setting action listeners
String arr [] = {"CaeserCipher","RunningKeyCipher","TrithemiusCipher","VignereCipher"};
caeserCipher.setOnAction((ActionEvent event)->{
//open caeser cipher
Stage s = new Stage();
new CaeserCipherFX().start(s);
});
runningKeyCipher.setOnAction((ActionEvent event)->{
//open running key cipher
stage.hide();
});
trithemiusCipher.setOnAction((ActionEvent event)->{
//open trithemius cipher
stage.hide();
});
vignereCipher.setOnAction((ActionEvent event)->{
//open vignere cipher
stage.hide();
});
// creating flowpane(FlowPane)
FlowPane menu = new FlowPane();
menu.setHgap(25);
menu.setVgap(25);
menu.setMargin(caeserCipher, new Insets(20, 0, 20, 20));
//list for Flowpane(ObservableList)
ObservableList list = menu.getChildren();
//adding list to flowpane
list.addAll(caeserCipher,runningKeyCipher,trithemiusCipher,vignereCipher);
//scene for stage
Scene scene = new Scene(menu);
stage.setTitle("Main Menu");
stage.setScene(scene);
// stage.initStyle(StageStyle.UTILITY);
stage.setHeight(100);
stage.setWidth(600);
stage.setResizable(false);
// Show the Stage (window)
stage.show();
}
}
And I want to launch the code below:
public class CaeserCipherFX extends Application
{
#Override
public void start(Stage stage) throws Exception
{//some other code
//some other code
}
}
There is a ubiquitous JavaFX main application thread which takes a while to get used to.
Think of it like the front-end thread. Theoretically, you should use that thread to handle UI updates and complex cpu tasks such as looking up something in a BD or figuring out the 100000th decimal of PI should be done in a background thread. If you don't do this, the UI will become unresponsive until the DB data is returned, or that decimal is found.
public class TestClass extends Application {
public static void main(String[] args) {
System.out.println("here");
Application.launch(TestClass.class, args);
System.out.println("this is called once application launch is terminated.");
}
#Override
public void init() throws Exception {
super.init(); //To change body of generated methods, choose Tools | Templates.
System.out.println("message from init");
}
#Override
public void start(Stage primaryStage) throws Exception { // this is abstract.
System.out.println("message from start");
Platform.exit(); // if you remove this line, the application won't exit.
}
}
Since JavaFX comes with some prerequisites, you need to start you rapplication using a front-end. You can work around this, but technically,
public void start(Stage primaryStage)
is what , for all intensive purposes, starts your program.
From here, you can use the primaryStage to control most of your application. It's a good idea to put a .onCloseRequest() on it in which you call Platform.exit();
If you want to have multiple windows in your application, you could use something like
public class TestClass extends Application {
public static void main(String[] args) {
System.out.println("here");
Application.launch(TestClass.class, args);
System.out.println("this is called once application launch is terminated.");
}
#Override
public void init() throws Exception {
super.init(); //To change body of generated methods, choose Tools | Templates.
System.out.println("message from init");
}
#Override
public void start(Stage primaryStage) throws Exception { // this is abstract.
primaryStage.setScene(new Scene(new TextArea("this is the first stage (window)")));
primaryStage.setTitle("stage 1");
primaryStage.show();
primaryStage.setOnCloseRequest((event) -> {
Platform.exit();
});
Stage secondaryStage = new Stage();
secondaryStage.setTitle("stage 2");
TextArea ta2 = new TextArea("this is a different stage.");
Scene scene = new Scene(ta2);
secondaryStage.setScene(scene);
secondaryStage.show();
primaryStage.setX(200);
secondaryStage.setX(200 + primaryStage.getWidth() + 50);
}
}
This is what I assume you want to do. Basically create a new window whenever you press a button. You can create stages like this.
The reason for which you can't do it your way is because you are attempting to start another javafx thread by invoking new CaeserCipherFX which is an application object, not a Stage.
new CaeserCipherFX().start(s); // this can only be called once.
IF you absolutely want to have 2 distinct applications (note: not application windows), then you need to have 2 distinct processes.
Lastly, the primaryStage parameter used in either examples is in the beginning basically a placeholder (as in it's constructed, but there's nothing really in it... like a new String()). You can use different stage objects as your "primary" UI.
Lastly, if depending on the stuff you want to decrypt, you may need to use background threads if you want to keep the UI responsiveness. For this you will need to check out the concurrency part of the javafx tutorial.
Is it possible to launch a JavaFX application through another JavaFX application? Not really.
Alternatively, you can use java.lang.ProcessBuilder
This class essentially sends command lines to your operating system shell.
You can use it to run something like "java -jar XXX\YYY\CaeserCipherFX.jar" whenever you click a button. (you'll have to build a CaeserCypherFX project into a jar file)
This will create a new JVM. This means no memory state sharing. You can handle this through IPC.

After updating Windows to 1903 (May 2019) JavaFX fails to create stage

I updated my Windows 10 laptop with May 2019 build (1903) and JavaFX does not seem to work anymore. After launching any JavaFX application, I see an icon on the taskbar, but no window is created. My java is the latest Java 8, latest Eclipse as IDE.
Is this a known issue or am I doing something wrong? Is there are a work-around or fix?
Thanks
I have created a small app that reproduces the problem.
If I comment out the following line
primaryStage.initStyle(StageStyle.UNDECORATED);
then it works as expected. Otherwise Windows 10 (1903) hangs, no window is shown. Be warned that you will need to use task-manager in windows to kill the JVM.
package com.alam33;
import java.io.IOException;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class Win10_1903Test extends Application {
public Win10_1903Test() {
}
#Override
public void start(Stage primaryStage) throws IOException {
VBox vbox = new VBox();
vbox.setPrefHeight(200);
vbox.setPrefWidth(300);
Scene scene = new Scene(vbox);
primaryStage.setTitle("Win10_1903Test");
primaryStage.setScene(scene);
primaryStage.setFullScreen(true);
/* THIS IS THE OFFENDING LINE */
primaryStage.initStyle(StageStyle.UNDECORATED);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
This is a workaround provided by Oracle, although they could not reproduce it. I suspect the problem is specific to the hardware in my machines.
Workaround: add jvm option
-Dprism.order=sw
As noted below, it is not a proper solution but I take it as an answer because it does help to make sure that your code is OK, which is important during development.

JavaFX UI issue(css and colors are not appearing) in windows 10 virtual box

Can any one help me on the below issue..
I am working on JavaFX and i have developed an standalone application using javafx. when i run the application in windows 10 it is working and the same is not working on windows 10 virtual box.
i have developed this application using JDK8u60 and created an executable jar file.when i run the jar file i am getting below issue.
Issue : colors of javafx ui is not appearing properly/UI shaded on virtual box. i have commented css and checked but still facing the same issue.
can any one please let me know a proper solution or root cause for this issue and let me know if any input required.
public class My_UI extends Application {
public static My_Controller controller;
private Stage stage;
private BorderPane root;
#Override
public void start(final Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(My_UI.class.getResource("My_GUI.fxml"));
root = (BorderPane) loader.load();
controller = (My_Controller)loader.getController();
Platform.setImplicitExit(false);
stage.setMaximized(true);
stage.setScene(new Scene(root));
stage.initStyle(StageStyle.UNIFIED);
stage.show();
}
}

Resources