JavaFX 2.1: Toolkit not initialized - javafx-2

My application is Swing-based. I would like to introduce JavaFX and configure it to render a Scene on a secondary display.
I could use a JFrame to hold a JFXPanel which could hold a JFXPanel but I would like to achieve this with JavaFX API.
Subclassing com.sun.glass.ui.Application and using Application.launch(this) is not an option because the invoking thread would be blocked.
When instantiating a Stage from Swing EDT, the error I get is:
java.lang.IllegalStateException: Toolkit not initialized
Any pointers?
EDIT: Conclusions
Problem: Non-trivial Swing GUI application needs to run JavaFX components. Application's startup process initializes the GUI after starting up a dependent service layer.
Solutions
Subclass JavaFX Application class and run it in a separate thread e.g.:
public class JavaFXInitializer extends Application {
#Override
public void start(Stage stage) throws Exception {
// JavaFX should be initialized
someGlobalVar.setInitialized(true);
}
}
Sidenote: Because Application.launch() method takes a Class<? extends Application> as an argument, one has to use a global variable to signal JavaFX environment has been initialized.
Alternative approach: instantiate JFXPanel in Swing Event Dispatcher Thread:
final CountDownLatch latch = new CountDownLatch(1);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new JFXPanel(); // initializes JavaFX environment
latch.countDown();
}
});
latch.await();
By using this approach the calling thread will wait until JavaFX environment is set up.
Pick any solution you see fit. I went with the second one because it doesn't need a global variable to signal the initialization of JavaFX environment and also doesn't waste a thread.

Found a solution. If I just create a JFXPanel from Swing EDT before invoking JavaFX Platform.runLater it works.
I don't know how reliable this solution is, I might choose JFXPanel and JFrame if turns out to be unstable.
public class BootJavaFX {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new JFXPanel(); // this will prepare JavaFX toolkit and environment
Platform.runLater(new Runnable() {
#Override
public void run() {
StageBuilder.create()
.scene(SceneBuilder.create()
.width(320)
.height(240)
.root(LabelBuilder.create()
.font(Font.font("Arial", 54))
.text("JavaFX")
.build())
.build())
.onCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent windowEvent) {
System.exit(0);
}
})
.build()
.show();
}
});
}
});
}
}

Since JavaFX 9, you can run JavaFX application without extending Application class, by calling Platform.startup():
Platform.startup(() ->
{
// This block will be executed on JavaFX Thread
});
This method starts the JavaFX runtime.

The only way to work with JavaFX is to subclass Application or use JFXPanel, exactly because they prepare env and toolkit.
Blocking thread can be solved by using new Thread(...).
Although I suggest to use JFXPanel if you are using JavaFX in the same VM as Swing/AWT, you can find more details here: Is it OK to use AWT with JavaFx?

I checked the source code and this is to initialize it
com.sun.javafx.application.PlatformImpl.startup(()->{});
and to exit it
com.sun.javafx.application.PlatformImpl.exit();

I used following when creating unittests for testing javaFX tableview updates
public class testingTableView {
#BeforeClass
public static void initToolkit() throws InterruptedException
{
final CountDownLatch latch = new CountDownLatch(1);
SwingUtilities.invokeLater(() -> {
new JFXPanel(); // initializes JavaFX environment
latch.countDown();
});
if (!latch.await(5L, TimeUnit.SECONDS))
throw new ExceptionInInitializerError();
}
#Test
public void updateTableView() throws Exception {
TableView<yourclassDefiningEntries> yourTable = new TableView<>();
.... do your testing stuff
}
}
even though this post is not test related, then it helped me to get my unittest to work
without the BeforeClass initToolkit, then the instantiation of TableView in the unittest would yield a message of missing toolkit

There's also way to initialize toolkit explicitly, by calling:
com.sun.javafx.application.PlatformImpl#startup(Runnable)
Little bit hacky, due to using *Impl, but is useful, if you don't want to use Application or JXFPanel for some reason.
re-posting myself from this post

private static Thread thread;
public static void main(String[] args) {
Main main = new Main();
startup(main);
thread = new Thread(main);
thread.start();
}
public static void startup(Runnable r) {
com.sun.javafx.application.PlatformImpl.startup(r);
}
#Override
public void run() {
SoundPlayer.play("BelievexBelieve.mp3");
}
This is my solution. The class is named Main and implements Runnable. Method startup(Runnable r) is the key.

Using Jack Lin’s answer, I found that it fired off the run() twice. With a few modifications that also made the answer more concise, I offer the following;
import com.sun.javafx.application.PlatformImpl;
public class MyFxTest implements Runnable {
public static void main(String[] args) {
MyFxTest main = new MyFxTest();
PlatformImpl.startup((Runnable) main);
}
#Override
public void run() {
// do your testing;
System.out.println("Here 'tis");
System.exit(0); // Optional
}
}

Related

how to do something when liferay module stop

i am making cron job like loop to do something using new thread.
when module stop, this thread keeps running, so when i deployed updated module, i'm afraid it will make duplicate thread doing similar task
#Component(immediate = true, service = ExportImportLifecycleListener.class)
public class StaticUtils extends Utils{
private StaticUtils() {}
private static class SingletonHelper{
private static final StaticUtils INSTANCE = new StaticUtils();
}
public static StaticUtils getInstance() {
return SingletonHelper.INSTANCE;
}
}
public class Utils extends BaseExportImportLifecycleListener{
public Utils() {
startTask();
}
protected Boolean CRON_START = true;
private void startTask() {
new Thread(new Runnable() {
public void run() {
while (CRON_START) {
System.out.println("test naon bae lah ");
}
}
}).start();
}
#Deactivate
protected void deactivate() {
CRON_START = false;
System.out.println(
"cron stop lah woooooooooooooooooy");
}
}
i'm using liferay 7
I have populated task that i store from db, so this thread is checking is there a task that it must do, then if it exist execute it.
I'm quite new in osgi and liferay. i've try to use scheduler and failed and also exportimportlifecycle listener but dont really get it yet
think again: Do you really need something to run all the time in the background, or do you just need some asynchronous processing in the background, when triggered? It might be better to start a background task as a one-off, that automatically terminates
Liferay provides an internal MessageBus, that you can utilize to listen to events and implement background processing, without the need for a custom thread
You're in the OSGi world, so you can utilize #Activate, #Modified, #Deactivate (from org.osgi.service.component.annotations) or use a org.osgi.framework.BundleActivator.
But, in general, it's preferable if you don't start your own thread

Timers and javafx

I am trying to write a code that will make things appear on the screen at predetermined but irregular intervals using javafx. I tried to use a timer (java.util, not javax.swing) but it turns out you can't change anything in the application if you are working from a separate thread.(Like a Timer) Can anyone tell me how I could get a Timer to interact with the application if they are both separate threads?
You don't need java.util.Timer or java.util.concurrent.ScheduledExecutorService to schedule future actions on the JavaFX application thread. You can use JavaFX Timeline as a timer:
new Timeline(new KeyFrame(
Duration.millis(2500),
ae -> doSomething()))
.play();
Alternatively, you can use a convenience method from ReactFX:
FxTimer.runLater(
Duration.ofMillis(2500),
() -> doSomething());
Note that you don't need to wrap the action in Platform.runLater, because it is already executed on the JavaFX application thread.
berry120 answer works with java.util.Timer too so you can do
Timer timer = new java.util.Timer();
timer.schedule(new TimerTask() {
public void run() {
Platform.runLater(new Runnable() {
public void run() {
label.update();
javafxcomponent.doSomething();
}
});
}
}, delay, period);
I used this and it works perfectly
If you touch any JavaFX component you must do so from the Platform thread (which is essentially the event dispatch thread for JavaFX.) You do this easily by calling Platform.runLater(). So, for instance, it's perfectly safe to do this:
new Thread() {
public void run() {
//Do some stuff in another thread
Platform.runLater(new Runnable() {
public void run() {
label.update();
javafxcomponent.doSomething();
}
});
}
}.start();

JavaFX: How to bind two values?

I'm new guy here :)
I have a small problem which concerns binding in JavaFX. I have created Task which is working as a clock and returns value which has to be set in a special label (label_Time). This label presents how many seconds left for player's answer in quiz.
The problem is how to automatically change value in label using the timer task? I tried to link value from timer Task (seconds) to label_Time value in such a way...
label_Time.textProperty().bind(timer.getSeconds());
...but it doesn't work. Is it any way to do this thing?
Thanks in advance for your answer! :)
Initialize method in Controller class:
public void initialize(URL url, ResourceBundle rb) {
Timer2 timer = new Timer2();
label_Time.textProperty().bind(timer.getSeconds());
new Thread(timer).start();
}
Task class "Timer2":
public class Timer2 extends Task{
private static final int SLEEP_TIME = 1000;
private static int sec;
private StringProperty seconds;
public Timer2(){
Timer2.sec = 180;
this.seconds = new SimpleStringProperty("180");
}
#Override protected StringProperty call() throws Exception {
int iterations;
for (iterations = 0; iterations < 1000; iterations++) {
if (isCancelled()) {
updateMessage("Cancelled");
break;
}
System.out.println("TIK! " + sec);
seconds.setValue(String.valueOf(sec));
System.out.println("TAK! " + seconds.getValue());
// From the counter we subtract one second
sec--;
//Block the thread for a short time, but be sure
//to check the InterruptedException for cancellation
try {
Thread.sleep(10);
} catch (InterruptedException interrupted) {
if (isCancelled()) {
updateMessage("Cancelled");
break;
}
}
}
return seconds;
}
public StringProperty getSeconds(){
return this.seconds;
}
}
Why your app does not work
What is happening is that you run the task on it's own thread, set the seconds property in the task, then the binding triggers an immediate update of the label text while still on the task thread.
This violates a rule for JavaFX thread processing:
An application must attach nodes to a Scene, and modify nodes that are already attached to a Scene, on the JavaFX Application Thread.
This is the reason that your originally posted program does not work.
How to fix it
To modify your original program so that it will work, wrap the modification of the property in the task inside a Platform.runLater construct:
Platform.runLater(new Runnable() {
#Override public void run() {
System.out.println("TIK! " + sec);
seconds.setValue(String.valueOf(sec));
System.out.println("TAK! " + seconds.getValue());
}
});
This ensures that when you write out to the property, you are already on the JavaFX application thread, so that when the subsequent change fires for the bound label text, that change will also occur on the JavaFX application thread.
On Property Naming Conventions
It is true that the program does not correspond to JavaFX bean conventions as Matthew points out. Conforming to those conventions is both useful in making the program more readily understandable and also for making use of things like the PropertyValueFactory which reflect on property method names to allow table and list cells to automatically update their values as the underlying property is updated. However, for your example, not following JavaFX bean conventions does not explain why the program does not work.
Alternate Solution
Here is an alternate solution to your countdown binding problem which uses the JavaFX animation framework rather than the concurrency framework. I prefer this because it keeps everything on the JavaFX application thread and you don't need to worry about concurrency issues which are difficult to understand and debug.
import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.*;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
import javafx.event.*;
import javafx.geometry.Pos;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
public class CountdownTimer extends Application {
#Override public void start(final Stage stage) throws Exception {
final CountDown countdown = new CountDown(10);
final CountDownLabel countdownLabel = new CountDownLabel(countdown);
final Button countdownButton = new Button(" Start ");
countdownButton.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent t) {
countdownButton.setText("Restart");
countdown.start();
}
});
VBox layout = new VBox(10);
layout.getChildren().addAll(countdownLabel, countdownButton);
layout.setAlignment(Pos.BASELINE_RIGHT);
layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 20; -fx-font-size: 20;");
stage.setScene(new Scene(layout));
stage.show();
}
public static void main(String[] args) throws Exception {
launch(args);
}
}
class CountDownLabel extends Label {
public CountDownLabel(final CountDown countdown) {
textProperty().bind(Bindings.format("%3d", countdown.timeLeftProperty()));
}
}
class CountDown {
private final ReadOnlyIntegerWrapper timeLeft;
private final ReadOnlyDoubleWrapper timeLeftDouble;
private final Timeline timeline;
public ReadOnlyIntegerProperty timeLeftProperty() {
return timeLeft.getReadOnlyProperty();
}
public CountDown(final int time) {
timeLeft = new ReadOnlyIntegerWrapper(time);
timeLeftDouble = new ReadOnlyDoubleWrapper(time);
timeline = new Timeline(
new KeyFrame(
Duration.ZERO,
new KeyValue(timeLeftDouble, time)
),
new KeyFrame(
Duration.seconds(time),
new KeyValue(timeLeftDouble, 0)
)
);
timeLeftDouble.addListener(new InvalidationListener() {
#Override public void invalidated(Observable o) {
timeLeft.set((int) Math.ceil(timeLeftDouble.get()));
}
});
}
public void start() {
timeline.playFromStart();
}
}
Update for additional questions on Task execution strategy
Is it possible to run more than one Task which includes a Platform.runLater(new Runnable()) method ?
Yes, you can use multiple tasks. Each task can be of the same type or a different type.
You can create a single thread and run each task on the thread sequentially, or you can create multiple threads and run the tasks in parallel.
For managing multiple tasks, you can create an overseer Task. Sometimes it is appropriate to use a Service for managing the multiple tasks and the Executors framework for managing multiple threads.
There is an example of a Task, Service, Executors co-ordination approach: Creating multiple parallel tasks by a single service In each task.
In each task you can place no runlater call, a single runlater call or multiple runlater calls.
So there is a great deal of flexibility available.
Or maybe I should create one general task which will be only take data from other Tasks and updating a UI?
Yes you can use a co-ordinating task approach like this if complexity warrants it. There is an example of such an approach in in Render 300 charts off screen and save them to files.
Your "Timer2" class doesn't conform to the JavaFX bean conventions:
public String getSeconds();
public void setSeconds(String seconds);
public StringProperty secondsProperty();

Create new Tooltip on not JavaFX Application Thread

is there a way how to create javafx.scene.control.Tooltip in thread which is not "JavaFX Application Thread"?
Because of performance I prepare some visual elements in one thread and keep them in memory. And when I need them I use Application Thread for showing them. But new Tooltip() seems to require Application Thread only.
is there a way how to create javafx.scene.control.Tooltip in thread which is not "JavaFX Application Thread"?
For JavaFX 2.2 - No.
See this JavaFX issue tracker tiecket: Tooltip of Tab (and other controls) cannot be set of FXApplicationThread.
There is a suggested workaround in the ticket to create the Tooltip in a Platform.runLater call.
package fxthread_25127_wrongthread;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.control.Tooltip;
import javafx.stage.Stage;
/**
*
* #author mickf
*/
public class Main extends Application {
Tooltip tooltip;
public static void main(String[] args) {
Application.launch(args);
}
#Override public void init() throws Exception {
Platform.runLater(new Runnable() {
#Override public void run() {
tooltip = new Tooltip("Top tip : use runLater()");
}
});
/*
* this will cause an ISE
*/
//tooltip = new Tooltip("flip");
}
#Override public void start(Stage s) {
System.exit(0);
}
}
A description of how Platform.runLater works from it's javadoc:
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.

Is it possible to reference FacesContext from a TimerTask or ScheduledExecutorService on application startup?

I am attempting to create functionality in a JSF1.2/ADF web app that will periodically & dynamically generate a sitemap for a website that will have hundreds of pages whose content will change daily. The catch is that I need to read some config from the application to use as the basis of the sitemap and to do so, I need FacesContext.
Here is what I have attempted to do: I created a class that implements a ServletContextListener and instantiates an application scoped bean. This bean does the heavy lifting to create sitemap.xml using FacesContext. I created a class that extends TimerTask that accesses the bean from application scope, calls the sitemap method and schedules future occurrences. When I run the application, the class that implements ServletContextListener fires and the bean appears to be created, but the class that extends TimerTask is never fired. Any help would be appreciated. If I can answer any questions or if I left anything out, please let me know.
Here are my code samples:
public class WebhomesApplicationContextListener implements ServletContextListener {
private static final String attribute = "SiteMapGenerator";
public void contextInitialized(ServletContextEvent event) {
SiteMapGenerator myObject = new SiteMapGenerator();
event.getServletContext().setAttribute(attribute, myObject);
}
public void contextDestroyed(ServletContextEvent event) {
SiteMapGenerator myObject = (SiteMapGenerator) event.getServletContext().getAttribute(attribute);
event.getServletContext().removeAttribute(attribute);
}
}
public class SiteMapGenerator {
public void generateSitemap() {
// code to generate map...
}
}
public class Scheduler extends TimerTask {
public void run() {
SiteMapGenerator sitemap = (SiteMapGenerator)FacesContext.getCurrentInstance().getExternalContext().getApplicationMap().get("SiteMapGenerator");
sitemap.generateSitemap();
}
}
class MainApplication {
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(
new Scheduler(),
1000 * 60);
}
}
No, you can't. The FacesContext is only available in the thread associated with the HTTP servlet request whose URL matched the URL pattern of the FacesServlet and has invoked it. Instead, just pass the SiteMapGenerator to the Scheduler on its construction.
public class Scheduler {
private SiteMapGenerator sitemap;
public Scheduler(SiteMapGenerator sitemap) {
this.sitemap = sitemap;
}
// ...
}
The SiteMapGenerator is surely available at the point you're constructing the Scheduler.
Unrelated to the concrete problem, It's strongly discouraged to use TimerTask in a Java EE application. See also Spawning threads in a JSF managed bean for scheduled tasks using a timer.

Resources