javafx programmatically set arguments for virtual keyboard - javafx

I have a desktop application that will be used on computers with no keyboard, input will be on a touch screen. I can get the virtual keyboard to show up on textfields fine when running from eclipse. I used these arguments
-Dcom.sun.javafx.touch=true
-Dcom.sun.javafx.isEmbedded=true
-Dcom.sun.javafx.virtualKeyboard=none
The following link shows me where to add the arguments.
how to add command line parameters when running java code in Eclipse?
When I make a runnable jar file the keyboard does not show up. I am looking for a way to set these arguments programmatically so that the runnable jar file will display the virtual keyboard on any computer. Any help will be greatly appreciated.

The only working solution I could find came from here
Gradle build for javafx application: Virtual Keyboard is not working due to missing System property
Create a wrapper class and set the system properties before invoking the applications original main method.
public class MainWrapper {
public static void main(String[] args) throws Exception
{ // application - package name
Class<?> app = Class.forName("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);
}
}
When making the runnable jar file just point to the MainWrapper class for the launch configuration.

The -D option to the JVM sets a system property. So you can achieve the same by doing the following:
public class MyApplication extends Application {
#Override
public void init() {
System.setProperty("com.sun.javafx.touch", "true");
System.setProperty("com.sun.javafx.isEmbedded", "true");
System.setProperty("com.sun.javafx.virtualKeyboard", "none");
}
#Override
public void start(Stage primaryStage) {
// ...
}
}

Related

Changing from deprecated ActivityTestRule to ActivityScenarioRule breaks test

I recorded an Espresso test using the recorder in Android Studio 4.2.2, which included a single assertion that a text field on my MainActivity UI was showing with the correct text string. I then saved this to SplashActivityTest.java:
public class SplashActivityTest {
#Rule
public ActivityTestRule<SplashActivity> mActivityTestRule = new ActivityTestRule<>(SplashActivity.class);
#Before
public void registerIdlingResource() {
IdlingRegistry.getInstance().register(CountingIdlingResourceSingleton.espressoIdlingResource);
}
#After
public void unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(CountingIdlingResourceSingleton.espressoIdlingResource);
}
#Test
public void splashActivityTest() {
ViewInteraction textView = onView(
allOf(withId(R.id.playlistText), withText("My Playlists"),
withParent(withParent(withId(R.id.nav_host_fragment))),
isDisplayed()));
textView.check(matches(isDisplayed()));
ViewInteraction textView2 = onView(
allOf(withId(R.id.playlistText), withText("My Playlists"),
withParent(withParent(withId(R.id.nav_host_fragment))),
isDisplayed()));
textView2.check(matches(withText("My Playlists")));
}
}
I added use of the Idling registry to this class because in my app what actually happens is a Splash screen is the launcher activity, which then launches the activity that loads the UI that I want to test.
I have this code:
// Necessary for automated tests, decrement handled in MainActivity.onResume()
CountingIdlingResourceSingleton.increment();
In the onCreate() method of SplashActivity and this code:
// Necessary for automated tests - increment is done in SplashActivity.onCreate()
CountingIdlingResourceSingleton.decrement();
At the end of onResume() in MainActivity.
The above code runs flawlessly, the test succeeds. Yay.
However, I get a deprecation warning on my use of ActivityTestRule, in favor of using an ActivityScenarioRule instead of ActivityTestRule (kind of interesting since use of that API was what was generated by the Espresso recorder in the latest 4.2.2 Android Studio, but that's the subject of a different post!).
So I change it:
public class SplashActivityTest {
#Rule
public ActivityScenarioRule<SplashActivity> mActivityTestRule = new ActivityScenarioRule<>(SplashActivity.class);
#Before
public void registerIdlingResource() {
IdlingRegistry.getInstance().register(CountingIdlingResourceSingleton.espressoIdlingResource);
}
#After
public void unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(CountingIdlingResourceSingleton.espressoIdlingResource);
}
#Test
public void splashActivityTest() {
ViewInteraction textView = onView(
allOf(withId(R.id.playlistText), withText("My Playlists"),
withParent(withParent(withId(R.id.nav_host_fragment))),
isDisplayed()));
textView.check(matches(isDisplayed()));
ViewInteraction textView2 = onView(
allOf(withId(R.id.playlistText), withText("My Playlists"),
withParent(withParent(withId(R.id.nav_host_fragment))),
isDisplayed()));
textView2.check(matches(withText("My Playlists")));
}
}
Now it no longer runs flawlessly. My app starts, the application class runs, but the launcher class never is called. Instead I get:
java.lang.AssertionError: Activity never becomes requested state "[DESTROYED, CREATED, STARTED, RESUMED]" (last lifecycle transition = "PRE_ON_CREATE")
Why? What do I need to do differently to insure that my normal launcher activity is called?

How to reduce slow start for picocli apps due to reflection

Picocli has to introspect the command tree. Doing so it needs to load the domain object classes for every Command which slows down the jvm startup.
What options are there to avoid this startup lag? One solution I've come up with is described in https://github.com/remkop/picocli/issues/482:
I am using reflection to postpone any class loading until after the command is selected. This way only the command classes themselves are loaded and finally the classes which implement the single command requested by the user:
abstract class BaseCommand implements Runnable {
interface CommandExecutor {
Object doExecute() throws Exception;
}
// find the CommandExecutor declared at the BaseCommand subclass.
protected Object executeReflectively() throws Exception {
Class<?> innerClass = getExecutorInnerClass();
Constructor<?> ctor = innerClass.getDeclaredConstructor(getClass());
CommandExecutor exec = (CommandExecutor) ctor.newInstance(this);
return exec.doExecute();
}
private Class<?> getExecutorInnerClass() throws ClassNotFoundException {
return getClass().getClassLoader().loadClass(getClass().getName() + "$Executor");
}
public void run() {
try {
executeReflectively();
} catch(...){
/// usual stuff
}
}
}
A concrete commend class:
#Command(...)
final class CopyProfile extends BaseCommand {
#Option String source;
#Option String dest;
// class must NOT be static and must be called "Executor"
public class Executor implements CommandExecutor {
#Override
public Object doExecute() throws Exception {
// you can basically wrap your original run() with this boilerplate
// all the CopyProfile's field are in scope!
FileUtils.copy(source, dest);
}
}
}
It seems like https://github.com/remkop/picocli/issues/500 may provide the ultimate solution to this. What are the other options until then?
UPDATE February 2020:
Upgrading to a recent version of picocli should fix this issue.
From the picocli 4.2.0 release notes:
From this release, subcommands are not instantiated until they are matched on the command line. This should improve the startup time for applications with subcommands that do a lot of initialization when they are instantiated.
An alternative that doesn’t require any code changes is to use GraalVM to compile your picocli-based application to a native image.
This article shows how to do this and the resulting startup time is 3 milliseconds.

Inject dependencies to the Java fx application

Probably I miss somehting out, but I'm struggeling to find a solution how I can pass dependencies like an instance of my event bus and some service interfaces to my javafx application.
I got an UI-Init class which does not much more than starting the application and receiving some dependencies for the UI like an eventBus:
public class Frontend {
public Frontend(MBassador<EventBase> eventBus) {
Application.launch(AppGui.class);
}
My AppGui class extends Application and loads an FXML:
public class AppGui extends Application {
private Stage primaryStage;
private GridPane rootLayout;
#Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
try {
// Load root layout from fxml file.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("RootLayout.fxml"));
rootLayout = (GridPane) loader.load();
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
scene.setFill(null);
primaryStage.setScene(scene);
RootLayoutController rootController = loader.getController();
rootController.init(/*here I would like to inject my eventBus*/);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
Now, how can I pass my eventBus and other service interfaces to this controller? I've read about using DI frameworks like guice (How can JavaFX controllers access other services?) or afterburner.fx to use it. But even if I use guice for the rest of my application, somehow I need to pass the Injector instance to the JavaFX application?.
But Application.launch(AppGui.class); is static and internally creates an AppGui instance on the javafx thread, which I don't get access to. So how I can inject dependencies to my AppGui object without using static variables?
Here is what I do:
The Application class has a couple of lifecycle callbacks, init() and stop().
From the Javadocs:
public void init() throws java.lang.Exception
The application initialization method. This method is called immediately after the Application class is loaded and constructed. An application may override this method to perform initialization prior to the actual starting of the application.
public void stop() throws java.lang.Exception
This method is called when the application should stop, and provides a convenient place to prepare for application exit and destroy resources.
Also from the Javadocs, the lifecycle:
Constructs an instance of the specified Application class
Calls the init() method
Calls the start(javafx.stage.Stage) method
Waits for the application to finish, which happens when either of the following occur:
the application calls Platform.exit()
the last window has been closed and the implicitExit attribute on Platform is true
Calls the stop() method
I start the IoC container in init() and stop it in stop(). Now my Application class has a reference to the IoC container and can supply the first controller with its dependencies.
As a matter of fact, I let the IoC framework manage the controllers. I set them to the loaded FXML using FXMLLoader.setController(), instead of specifying them with fx:controller.
You can pass a static reference to your application class before you call launch(). Something like:
public class Frontend {
public Frontend(MBassador<EventBase> eventBus) {
AppGui.setEventBus(eventBus);
Application.launch(AppGui.class);
}
}
public class AppGui extends Application {
private static MBassador<EventBase> eventBus;
public static void setEventBus(MBassador<EventBase> eventBus) {
this.eventBus = eventBus;
}
private MBassador<EventBase> eventBus;
#Override
public void init() {
if (AppGui.eventBus == null) {
throw new IllegalStateException();
// or however you want to handle that state
} else {
this.eventBus = AppGui.eventBus;
AppGui.eventBus = null;
}
}
}
Whether you keep and use the static reference, or you copy the static reference to a local reference is up to you and the design of your application. If you expect to instantiate more than one copy of AppGui, you may need the local reference.
No idea if this is thread safe (probably not). The advice from #Nikos and #James_D is solid and preferred... but sometimes you just need a hack. :) YMMV

Calling a non-parental Activity method from fragment without creating a new instance

I have my MainActivity and inside that I have a number of fragments. I also have another activity that works as my launcher and does everything to do with the Google Drive section of my app. On start up this activity launches, connects to Drive and then launches the MainActivity. I have a button in one of my fragments that, when pushed, needs to call a method in the DriveActivity. I can't create a new instance of DriveActivity because then googleApiClient will be null. Is this possible and how would I go about doing it? I've already tried using getActivity and casting but I'm assuming that isn't working because DriveActivity isn't the fragments parent.
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//TODO for test only remove
directory = new Directory(SDCARD + LOCAL_STORAGE);
byte[] zippedFile = directory.getZippedFile(SDCARD + STORAGE_LOCATION + directory.getZipFileName());
//Here I need to somehow call DriveActivity.uploadFileToDrive(zippedFile);
//((DriveActivity)getActivity()).uploadFileToDrive(zippedFile);
}
});
Right, so I'm having a bit of difficulty with the heirarchy but I think what you want to do is define a method in the fragment that the activity will be required to override to use.
This will allow you to press the button, and then fire a method whos actual implementation is inside the parent.
public interface Callbacks {
/**
* Callback for when an item has been selected.
*/
public void onItemSelected(String id);
}
example implementation:
private static Callbacks sDummyCallbacks = new Callbacks() {
#Override
public void onItemSelected(String id) {
//Button fired logic
}
};
so in the child you'd do just call:
this.onItemSelected("ID of Class");
EDITED
In retrospect what I believe you need is an activity whos sole purpose is to upload files, not fire off other activities.
Heres an example of a 'create file' activity:Google Demo for creating a file on drive
Heres an example of the 'base upload' activity' Base Service creator

JavaFx in headless mode

Is it possible to run JavaFx in headless mode(in Java 7)? It is being used to generate images on the server but is asking for an X-Server. Does there exist something like java.awt.headless in JavaFx ?(I can't use Xvfb )
Here is how I solved this problem for server-side image geneartion on Ubuntu linux environment with jetty application server. It uses xvfb but only as a "library" - without any additional special actions on server:
apt-get install xvfb
// then on application server start:
export DISPLAY=":99"
start-stop-daemon --start --background --user jetty --exec "/usr/bin/sudo" -- -u jetty /usr/bin/Xvfb :99 -screen 0 1024x768x24
You can see the details of my server-side image generation solution in this SO question.
This is a kind of problem which I encountered while capturing images in Mac OS.
I have solved this issue by using
static {
System.setProperty("java.awt.headless", "false");
}
See for reference : Headless environment error in java.awt.Robot class with MAC OS
Answer by Shreyas Dave didn't work for me anymore. Though I don't know why, here is what I did:
public static void main(String[] args) {
// to avoid
// [JRSAppKitAWT markAppIsDaemon]: Process manager already initialized: can't fully enable headless mode.
System.setProperty("javafx.macosx.embedded", "true");
java.awt.Toolkit.getDefaultToolkit();
// end
launch(args);
}
This was also pointed out here: JavaFX screencapture headless exception on OSX
If you have the source code of the JavaFX application you could also try to use TestFX run the application in a headless mode, to control it and to make screenshots. To run your TestFX application in headless mode you have to start it with the following JVM parameters (to enable Monocle):
-Dtestfx.robot=glass -Dglass.platform=Monocle -Dmonocle.platform=Headless -Dprism.order=sw
Moreover you might need to install Monocle first. See Headless testing with JavaFx and TestFx for more information.
I have an application that can be used interactively (displaying JavaFx dialogs) but also must be able to run non-interactive on a server without display.
Even though no GUI element is used in non-interactive mode, we got
Caused by: java.lang.UnsupportedOperationException: Unable to open DISPLAY
at com.sun.glass.ui.gtk.GtkApplication.<init>(GtkApplication.java:68)
This happens as soon as a class derived from javafx.application.Application is instantiated, which you normally do with your main class.
Here is the way I solved the problem:
I created an additional class GuiAppExecution:
import java.util.List;
import javafx.application.Application;
import javafx.stage.Stage;
/**
* JavaFx launch class for {#link AppExecution}.
*/
public class GuiAppExecution extends Application {
#Override
public void start(Stage stage) throws Exception {
List<String> parameters = getParameters().getRaw();
AppExecution appExecution = new AppExecution();
appExecution.launch(parameters);
}
/**
* Launches the {#link AppExecution} as JavaFx {#link Application}.
*
* #param parameters program parameters
*/
public void launchGui(String[] parameters) {
launch(parameters);
}
}
In the main class AppExecution I created a method
public void launch(List<String> parameters) {
which parses the parameters and launches the application for both interactive and non-interactive execution.
The main method looks like this:
public static void main(String[] parameters) {
List<String> parameterList = Arrays.asList(parameters);
if (parameterList.stream().anyMatch(p -> p.equalsIgnoreCase(BATCH_PARAMETER))) {
AppExecution appExecution = new AppExecution();
appExecution.launch(parameterList);
}
else {
GuiAppExecution guiAppExecution = new GuiAppExecution();
guiAppExecution.launchGui(parameters);
}
}
with
private static final String BATCH_PARAMETER = "-batch";
as the program option that request the non-interactive execution.
Since GuiAppExecution (which is derived from javafx.application.Application) is not instantiated for non-interactive execution, the JavaFx environment is not started.

Resources