Separating Javafx 8 GUI from remaining code - javafx-8

When reading javafx 8 tutorials, this seems to be the main work flow:
public class Test extends Application{
public static void main(String[] args){
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader(TestFXController.class.getResource("test.fxml"));
Parent root;
try {
root = fxmlLoader.load();
Scene scene = new Scene(root, 1200, 800);
primaryStage.setScene(scene);
primaryStage.show();
TestFXController controller = fxmlLoader.getController();
controller.plotSomething();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Let's say that I have an Algorithm which I want to run. After starting the above application I may end up with an interface containing a "run algorithm" button. After pressing the button, an action handler invokes the algorithm.
I then have: start java application -> build interface -> press button to solve Algorithm -> display solution. All that separates the graphical stuff from the algorithm is a button. In fact, the graphical interface 'drives' the application in the sense that it is responsible for launching the algorithm.
What I would prefer however is something like this:
public class Test2{
public void main(String[] args){
Algorithm alg=new Algorithm();
alg.solve();
GUI gui =new GUI(); //Spawns a Javafx 8 Graphical User Interface
gui.displaySolution(alg.getSolution());
}
}
To me, this seems a lot cleaner? I'm however not sure how to do this with javafx 8, or whether this is even possible? Any examples or references are highly appreciated. What should I put in the GUI class such that it launches a javafx 8 interface?
The example in Test2 would also open up possibilities to use a clean Observer Design Pattern like this:
public class Test3{
public void main(String[] args){
Algorithm alg=new Algorithm();
alg.addListener(new GUI()); //Add a Javafx 8 GUI as a listener.
alg.addListener(new TextualLogger());
alg.solve();
}
}
Notice that in the classes Test2 and Test3, the GUI no longer drives the application.
To clarify, my main question would be: what should be the implementation of the GUI class if I would run the code in Test2? Something like this:
public class GUI extends Application{
public GUI(){
//What should I put here? Perhaps launch(new String[]); ?
}
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader(TestFXController.class.getResource("test.fxml"));
Parent root;
try {
root = fxmlLoader.load();
Scene scene = new Scene(root, 1200, 800);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public void displaySolution(Solution sol){
...
}
}

In a JavaFX application, you should think of the start(...) method essentially as the equivalent of the main(...) method in a "regular" Java application. (In fact, in Java 8, a JavaFX application does not need a main(...) method at all.) This mechanism for launching a JavaFX application was introduced in order to force the programmer, as much as possible, to initialize the UI on the correct thread (in comparison to Swing, where there is a large amount of code published which launches the GUI incorrectly). For convenience, the start(...) method is passed an initial stage, but there is no requirement for you to use it if you prefer to use a different one.
So you can just do
public class Test2 extends Application {
#Override
public void start(Stage primaryStage) {
Algorithm alg = new Algorithm();
alg.solve();
GUI gui = new GUI();
gui.displaySolution(alg.getSolution());
}
// included for the benefit of IDEs that do not support
// launching an Application without a main method:
public static void main(String[] args) { launch(args); }
}
and now GUI is not an Application subclass (which makes sense, because it represents the GUI, not an application):
public class GUI {
public GUI(){
FXMLLoader fxmlLoader = new FXMLLoader(TestFXController.class.getResource("test.fxml"));
Parent root;
try {
root = fxmlLoader.load();
Scene scene = new Scene(root, 1200, 800);
Stage stage = new Stage();
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public void displaySolution(Solution sol){
...
}
}
One thing to bear in mind here is that start(...) is executed on the FX Application Thread. Consequently, once you have shown the UI, any further long-running processes that need to be performed should be executed on background threads. In the use-case you've described, all the heavy lifting is done before you show the UI, so this is not an issue, but you may need to consider this if you try to extend this pattern at all.

I am not sure I follow exactly what you are attempting to do - are you trying to open a second JavaFX Window?
Would something like this work?
Scene resultScene = algorithm.getSolution();
Stage resultStage = new Stage();
resultStage.setScene(resultScene);
resultStage.addEventHandler() or addEventFilter()
resultStage.show();
This stage can be it's own window or a child of the primaryStage so that if you close the parent, it will also close.

If you really want to open second JavaFX window from one already running. You can visit.
Launch JavaFX application from another class
It will solve your issue.
below is the code how to run new JavaFx Application
Platform.runLater(new Runnable(){
#Override
public void run(){
new MainApp().start(new Stage()); // MainApp is the class name of your second Application
}
});
Make your class extend Application and Implement Runnable and add below mention code in that class
#Override
public void run(){
launch();
}
launch() method will be called from run() method. Do not use Main() method in the second class, else it with throw exception.

Related

Replace default pop-up window when exception throws on top level in RCP 4 application

How can I replace default pop-up window when exception throws on top level in RCP 4 application?
You can set a class implementing IEventLoopAdvisor in the application Eclipse Context. This is given all unhandled errors.
Something like:
class EventLoopAdvisor implements IEventLoopAdvisor
{
#Override
public void eventLoopIdle(final Display display)
{
display.sleep();
}
#Override
public void eventLoopException(final Throwable exception)
{
// TODO Your code
}
}
Note: It is extremely important to call display.sleep in the eventLoopIdle method.
A good place to set this up is the #PostContextCreate of your LifeCycle class (if you have one):
#PostContextCreate
public void postContextCreate(final IEclipseContext context)
{
context.set(IEventLoopAdvisor.class, new EventLoopAdvisor());
}
Note: IEventLoopAdvisor is an internal class so normally I would not advise using it, but this use does seem to be allowed.

How to cancel the creation of a view in Eclipse RCP e4?

Is it possible to cancel the creation of a view in the #PostConstruct phase? I have:
#PostConstruct
public void createPartControl(Composite parent) {
try {
// do something where an exception is thrown
} catch (Exception e) {
// I want to cancel construction, close the view and show an error dialog
}
}
You can run the part service hide part immediately after the part creation has finished using something like:
#PostConstruct
public void postConstruct(Composite parent, UISynchronize uiSync,
EPartService partService, MPart part)
{
// Other code
// Run hidePart as soon as possible after part creation has finished
uiSync.asyncExec(() -> partService.hidePart(part));
}
(Above is using Java 8 lambda).
Just close the view, e4 style
MPart part = partService.findPart(viewId);
part.setVisible(true);

Display two windows at the same time using JavaFX Scene Builder 2.0

I'm working on a mini application where I need to display to users 2 windows at the same time.
I'm working with JavaFx Scene Builder 2.0 on NetBeans 8.0.1
is it possible to do this? if so, how it can be done ?
Thank you!
By "screen" I assume you mean "window".
Just create a second stage in your start() method and do exactly the same with it as you do your primary stage:
public class MyApp extends Application {
#Override
public void start(Stage primaryStage) {
Stage anotherStage = new Stage();
try {
FXMLLoader loader = new FXMLLoader(...); // FXML for primary stage
Parent root = loader.load();
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
FXMLLoader anotherLoader = new FXMLLoader(...) ; // FXML for second stage
Parent anotherRoot = anotherLoader.load();
Scene anotherScene = new Scene(anotherRoot);
anotherStage.setScene(anotherScene);
anotherStage.show();
} catch (Exception exc) {
exc.printStackTrace();
}
}
public static void main(String[] args) { launch(args); }
}

GWT is making an unexpected event call

My code is below: I am seeing that on running the app the loadWidget method gets invoked even when the adminLink is not clicked. This is not want I want, but I'm not sure what is causing the issue. Please advise
public class LoginModule implements EntryPoint {
LoginPopup loginPopup;
private class LoginPopup extends PopupPanel {
public LoginPopup() {
super(true);
}
public void loadWidget(){
System.out.println("I am called 1");
CommonUi cUi = new CommonUi();
//#342 moved code to common area
FormPanel loginForm = cUi.getLoginFormUi();
setWidget(loginForm);
}
}
#Override
public void onModuleLoad() {
//#251 improved login popup ui.
final Anchor adminLink = new Anchor("User Login");
// final Label adminLink = new Label("User Login");
adminLink.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
// Instantiate the popup and show it.
loginPopup = new LoginPopup();
loginPopup.loadWidget();
loginPopup.showRelativeTo(adminLink);
loginPopup.show();
}
});
if(RootPanel.get("admin") !=null)
RootPanel.get("admin").add(adminLink);
}
}
Running Dev Mode, set a breakpoint in that method in your Java IDE, and take a look at the current stack, what code is calling that method. If that is the only code in your app, then this only appears to be invokable from that onClick handlers, so it is a matter of figuring out why that is being invoked.

How can I correctly update a progress bar for an operation of unknown duration within an Eclipse wizard?

I have implemented a wizard for my Eclipse plug-in, showing several pages. One of these pages needs some lengthy initialization, that means it consists of a SWT table, which needs to be populated by information coming from an external source. This source needs to be activated first (one single method call that returns after a couple of seconds - I can not know in advance how long it will take exactly), before it can be used as input for for the table viewer. This initialization is currently done by the table model provider when it needs to access the external source for the first time.
Therefore, when I enter the wizard page, I would like to show a dummy progress bar that just counts up for a while. My approach was the following, but unfortunately does not work at all:
private void initViewer() {
IRunnableWithProgress runnable = new IRunnableWithProgress() { // needed to embed long running operation into the wizard page
#Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
SubMonitor progress = SubMonitor.convert(monitor);
Thread thread = new Thread() {
#Override
public void run() {
Display.getDefault().syncExec(new Runnable() {
public void run() {
viewer.setInput(ResourcesPlugin.getWorkspace().getRoot()); // this will make the table provider initialize the external source.
}
});
}
};
thread.start();
while(thread.isAlive()) {
progress.setWorkRemaining(10000);
progress.worked(1);
}
progress.done();
}
};
try {
getContainer().run(false, false, runnable);
} catch(Exception e) {
throw new Exception("Could not access data store", e);
}
}
This method gets then invoked when the wizard page's setVisible()-method is called and should, after a couple of seconds, set the viewer's input. This, however, never happens, because the inner-most run()-method never gets executed.
Any hints on how to deal with long-running (where an exact estimate is not available) initializations in Eclipse wizards would be very appreciated!
I have given below a simple example on how to use IRunnableWithProgress along with a ProgressMonitorDialog to perform a task of unknown quantity. To start with, have an implementation to IRunnableWithProgress from where the actual task is performed. This implementation could be an inner class.
public class MyRunnableWithProgress implements IRunnableWithProgress {
private String _fileName;
public MyRunnableWithProgress(String fileName) {
_fileName = fileName;
}
#Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
int totalUnitsOfWork = IProgressMonitor.UNKNOWN;
monitor.beginTask("Performing read. Please wait...", totalUnitsOfWork);
performRead(_fileName, monitor); // This only performs the tasks
monitor.done();
}
}
Now, a generic implementation to ProgressMonitorDialog can be created as below which could be used for other places where a progress monitor dialog is required.
public class MyProgressMonitorDialog extends ProgressMonitorDialog {
private boolean cancellable;
public MyProgressMonitorDialog(Shell parent, boolean cancellable) {
super(parent);
this.cancellable = cancellable;
}
#Override
public Composite createDialogArea(Composite parent) {
Composite container = (Composite) super.createDialogArea(parent);
setCancelable(cancellable);
return container;
}
}
Having got the required implementation, the task can be invoked as below to get it processed with a progress dialog.
boolean cancellable = false;
IRunnableWithProgress myRunnable = new MyRunnableWithProgress(receivedFileName);
ProgressMonitorDialog progressMonitorDialog = new MyProgressMonitorDialog(getShell(), cancellable);
try {
progressMonitorDialog.run(true, true, myRunnable);
} catch (InvocationTargetException e) {
// Catch in your best way
throw new RuntimeException(e);
} catch (InterruptedException e) {
//Catch in your best way
Thread.currentThread().interrupt();
}
Hope this helps!
I assume the reason why it's "not working" for you is that the preparation of input is done in UI thread meaning that the progress bar cannot be updated. A better approach is to prepare input in advance and only set input to viewer after that.