I'm trying to launch a JavaFx application from within a JavaFx application, but it looks like Application.launch() can only be called once. Does this mean I have to start a separate JVM... as in exec("java... or is there another way?
More background info. I want my JavaFx app to be able to build and run JavaFx apps. Right now it compiles classes in-memory, loads the classes... it would be really unfortunate to have to resort to writing everything to the filesystem so I can get a jar on the filesystem, so I can use exec to start it up.
As a secondary question... Is there a way to open another JavaFx window and get the stage and pass it to my newly compiled and loaded Application sub-class?
If you want to execute another JavaFX application in the same JVM you can just create instance of it, manually create Stage and call Application#start()
public void runAnotherApp(Class<? extends Application> anotherAppClass) throws Exception {
Application app2 = anotherAppClass.newInstance();
Stage anotherStage = new Stage();
app2.start(anotherStage);
}
N.B.: it wouldn't work if you use special features of standard initialization in anotherApp, e.g. Application.init() or Application.getParameters()
Related
I have a JavaFX 8 desktop application and I'm creating an .app application bundle to distribute the application to Mac users. I use the Oracle “Self-Contained Application Packaging” tool to generate the bundle.
The problem that I have relates to the files associated with my application. I am associating the extension .wordy with these files. If I have the application open and I double click one of these files in the Mac Finder, my application receives an OpenFilesEvent containing the path to the file and everything works perfectly. If, however, the application is not open, double clicking a .wordy file in the Finder opens my application as I would expect but I never receive the event containing the path to the file that the user double-clicked on.
The file association is done in the Ant script for the Oracle “Self-Contained Application Packaging” tool, as follows:
<project name="VocabHunter Packaging" basedir=""
xmlns:fx="javafx:com.sun.javafx.tools.ant">
...
<fx:info title="VocabHunter">
<fx:association description="VocabHunter session"
extension="wordy"
mimetype="application/x-vnd.VocabHunterSession"
icon="${basedir}/icons/mac/VocabHunterSession.icns"/>
</fx:info>
...
</project>
In the Java code, I obtain an instance of com.apple.eawt.Application and then register the listener for the OpenFilesEvent as follows:
Application application = Application.getApplication();
application.setOpenFileHandler(new OsxOpenFilesHandler(listener));
You can see the full code here.
Does anyone know how to fix this so that I receive an event containing the path to the .wordy file even if the application was not running at the moment that the file was double clicked?
In the interests of completeness, I'm using the Oracle JDK 1.8.0_66 for Mac.
I tested with your code and also met this problem.
But when I used code directly in start(Stage primaryStage) method in to listen like this:
Application lowLevelApp = com.sun.glass.ui.Application.GetApplication();
lowLevelApp.setEventHandler {...}
I can get the OpenFilesEvent when first double clicked on file.
There is an entry in the bug database for this issue.
https://bugs.openjdk.java.net/browse/JDK-8187992
You probably call the application.setOpenFileHandler() code too late during the application initialization. Try calling it as early as possible in main() and see if that solves the problem. I am not sure exactly when Mac OS X passes the OpenFile event to Java, but if at that time you haven't prepared by calling application.setOpenFileHandler() then the event will get lost.
For future reference: getting the openFileHandler to work correctly can be very tricky. The handler is invoked from an event handler on the UI event thread, which means there is no guarantee that main() has completed when the handler is run. For best results, the openFileHandler should be set up using a static initializer, and main() and the open file handler should both invoke the same initialization code on the UI event thread, and the initialization code should be written to work if called more than once.
I'm building a multi-window and multi-module simulation application, and I use JavaFX for GUI.
From what I understood, to make a JavaFX project run, you need to run Application.launch( MyApplicationSubclass.class ) and use the primary stage given in the start(Stage primaryStage) method to get started. Everything in the start method and beyond happens in a JavaFX thread.
My app is a multi-moduled application. Today, a Main class bootstraps the program and launches several modules (which are distinct Maven modules), including the one in charge of the GUI. In the beginning (when I designed the current architecture), I planned to create only one window. So, once loaded, the GUI module would make the Application.launch( MyOnlyMainWindow.class ) call, and everything would work fine.
Today, I'd like to add a console window, launched before any module, and used to "live-log" the application (by redirecting the System.out stream, between other things, into a TextFlow). But with the architecture previously described, it's impossible, because if I want ot keep the Application.launch() call in the GUI module, then I can't make it in the Console window, which is not a part of the GUI module. It would also be impossible to add another GUI module that would manage another set of window.
So I can think of two and a half ways to solve this:
Centralize, somehow, the Application.launch() call so that it is available to every class that would need it. I don't know how to do it though.
Change the Main class to heritate from javaFx Application class. But wouldn't that make me execute all my module instanciations into the JavaFX Thread? I would guess this is a bad way of doing things. Or even, if I decide to create other threads for module instanciation, those threads would have been created in the JavaFX thread.
(Use Swing for the Console Window, though it does not actually solve my problem a viable way... What if I need to create another window in another GUI module?)
What would be a viable way of creating and managing a multiple window application with JavaFX? How could I, for instance, centralize the JavaFX Application.launch() calls?
Or, in other words
Is it a good practice to decentralize the JavaFX Application implementation in a module and launch the module from the main() class, or is it better to implement it in the main() class, even if I try to make my program modular?
I am making an application that will sit in the system tray and open a window when a user clicks it, the problem is I want the application to be run from start up using an exe, adding the application to the system tray without opening a window. but when the user opens the application on their own I want the window to pop up. how can i determine weather the application was run on boot up or by the user?
You can write a class that through JNI you call some windows libraries that has a Enum with all the processes and information about it. This way you find your process and see who executed it. Process Information
You can run the main method of your class with different args or have two different classes with main methods for each use case.
I want to close and then restart a already running application (automatically) that I am making, by clicking a button or something like that, I want to do that for the purpose of re-launching the application in an other language, I'm new to JavaFx and Java in general, please can you give me a solution for this problem ?
This question lacks details. You did mention a JavaFX application but it is important to know how that application is being deployed. Is it running in the web browser, as a java webstart application, a stand-alone jar, or a self-contained native application? How are you starting the application to begin with? Having the answer to these questions will make it easier to answer your question with specifics.
While the following example is not JavaFX, the approach used here would work for some of the ways in which a JavaFX application can be deployed. One approach for restarting an application that works nicely is to start the application from a script. Inside the script would be a while loop that continually restarts the program based on the program exit code. Here is an example for a bash shell script which starts IntelliJ on a Linux platform:
while true ; do
eval "$JDK/bin/java" $ALL_JVM_ARGS -Djb.restart.code=88 $MAIN_CLASS_NAME $*
test $? -ne 88 && break
done
In this example, the startup script is passing "jb.restart.code" as an application parameter. If IntelliJ wishes to restart, it will return that value 88 as the exit code. The script observes the application exit code, and restarts the application if the value is 88.
This approach works well on most platforms, but requires the application to be initiated via a script.
One solution is to pass commandline and working dir in your start script to your main() method. Using ProcessBuilder you then can restart the appliation. Another possibility is to start the whole application in a custom classloader (e.g. Spring project has suitable classloaders in their source base), you then can basically restart by starting your main in anouther classloader, however you then need proper housekeeping to free threads and resources of the first instance.
retstart.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
if(getOnCloseRequest()!=null){
getOnCloseRequest().handle(new WindowEvent(getScene().getWindow(), WindowEvent.WINDOW_CLOSE_REQUEST));
//write code to invoke application instance again
}else{
close();
}
}
});
I'm doing a Java Record/Replay tool and I need to launch Java applications from my main Java app.
I need access to the EventDispatchThread in order to intercept the events and record them, so I'm launching the application through reflection with (code snippet simplified):
Class<?> app = Class.forName(mainClass);
Method m = app.getMethod("main", new Class[] { String[].class });
m.invoke(null, new Object[] { new String[] {} });
I previously dynamically load all the jars to the classpath and the application is launching almost perfectly.
The problem occurs when the application needs to access any file and does it with relative paths. Because the application is launched through my application the path is not the same as launched from its normal path and the files are not found.
What can I do to solve this problem? dynamically change the execution environment? any ideas?
I would suggest loading your code as a "Java Agent" whilst starting the target application.
(With your method you will also find that the system class loader is wrong.)
In general, there's no way to do this.
http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=30b24551130ee4ffffffffc17df8d7ce8a9c3?bug_id=4117557
You can try System.setProperty("user.dir", "C:\\Some\\Location"); but it probably won't work for all cases and will give you weird behavior.
It's a pretty bad design for an app to rely on the directory from which it was launched.
The best advice I can give you is to launch your app from the directory from which the misbehaving app expects to be launched (assuming you know what that directory is).
Otherwise, hell, copy/symlink the data files into your directory so that the client app can find them...