It is possible to use JavaFX in Groovy using the same syntax as in Java? - groovy

I am using jdk1.8.0_25.
I am trying to run a JavaFX app file below which, when named 'HelloWorldMain.java', compiles and runs OK with javac/java. I renamed it as 'HelloWorldMain.groovy' and can't run it using Groovy.
Is there a simple way to run this file using Groovy with no or minimal modification, preferably without additional software like GroovyFX? And if I have to use GroovyFX, can I run this pure Java code without modification?
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
/**
*
* #author cdea
*/
public class HelloWorldMain extends Application {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World");
Group root = new Group();
Scene scene = new Scene(root, 300, 250);
Button btn = new Button();
btn.setLayoutX(100);
btn.setLayoutY(80);
btn.setText("Hello World");
btn.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
System.out.println("Hello World");
}
});
root.getChildren().add(btn);
primaryStage.setScene(scene);
primaryStage.show();
}
}
I am trying to run it as
groovy HelloWorldMain.groovy
and getting the following output in command line:
Caught: java.lang.RuntimeException: java.lang.ClassNotFoundException: javafx.application.Application$launch
java.lang.RuntimeException: java.lang.ClassNotFoundException: javafx.application.Application$launch
at javafx.application.Application.launch(Application.java:260)
at javafx.application.Application$launch.call(Unknown Source)
at HelloWorldMain.main(HelloWorldMain.groovy:20)
Caused by: java.lang.ClassNotFoundException: javafx.application.Application$launch
at javafx.application.Application.launch(Application.java:248)
... 2 more

replace the main method with:
public static void main(String[] args) {
launch(HelloWorldMain, args);
}
The error basically gives you the answer: no you can not just copy the files in all cases. There are differences between groovy and java (e.g. http://groovy-lang.org/differences.html). Groovy comes with a tool called java2groovy that might help migrate.
But as groovy runs fine with java code, why bother? Migrate the parts, that are better off using groovy and keep the java parts around for now.

Related

Google Map crash at specific location and zoom level 15

Google Map crashes with zoom level 15 at specific location (35.670, 139.760) on Android 8 (API level 26).
No crash with other zoom levels (say: 1,2,10, or 14 etc.)
When crash, the Logcat output is:
E/AndroidRuntime: FATAL EXCEPTION: GLThread 279
Process: test.map, PID: 5690
java.lang.StackOverflowError: stack size 1038KB
at java.util.Collections$UnmodifiableList.<init>(Collections.java:1344)
at java.util.Collections$UnmodifiableRandomAccessList.<init>(Collections.java:1437)
at java.util.Collections.unmodifiableList(Collections.java:1330)
at com.google.maps.api.android.lib6.common.g.<init>(:com.google.android.gms.DynamiteModulesB#11951470:9)
at com.google.maps.api.android.lib6.gmm6.indoor.o.b(:com.google.android.gms.DynamiteModulesB#11951470:142)
at com.google.maps.api.android.lib6.gmm6.indoor.o.c(:com.google.android.gms.DynamiteModulesB#11951470:144)
at com.google.maps.api.android.lib6.gmm6.indoor.o.e(:com.google.android.gms.DynamiteModulesB#11951470:286)
at com.google.maps.api.android.lib6.gmm6.indoor.o.d(:com.google.android.gms.DynamiteModulesB#11951470:182)
at com.google.maps.api.android.lib6.gmm6.indoor.o.a(:com.google.android.gms.DynamiteModulesB#11951470:180)
at com.google.maps.api.android.lib6.gmm6.indoor.o.a(:com.google.android.gms.DynamiteModulesB#11951470:82)
at com.google.maps.api.android.lib6.gmm6.indoor.o.a(:com.google.android.gms.DynamiteModulesB#11951470:70)
at com.google.maps.api.android.lib6.gmm6.indoor.o.c(:com.google.android.gms.DynamiteModulesB#11951470:147)
at com.google.maps.api.android.lib6.gmm6.indoor.o.e(:com.google.android.gms.DynamiteModulesB#11951470:286)
at com.google.maps.api.android.lib6.gmm6.indoor.o.d(:com.google.android.gms.DynamiteModulesB#11951470:182)
at com.google.maps.api.android.lib6.gmm6.indoor.o.a(:com.google.android.gms.DynamiteModulesB#11951470:180)
at com.google.maps.api.android.lib6.gmm6.indoor.o.a(:com.google.android.gms.DynamiteModulesB#11951470:82)
at com.google.maps.api.android.lib6.gmm6.indoor.o.a(:com.google.android.gms.DynamiteModulesB#11951470:70)
at com.google.maps.api.android.lib6.gmm6.indoor.o.c(:com.google.android.gms.DynamiteModulesB#11951470:147)
at com.google.maps.api.android.lib6.gmm6.indoor.o.e(:com.google.android.gms.DynamiteModulesB#11951470:286)
at com.google.maps.api.android.lib6.gmm6.indoor.o.d(:com.google.android.gms.DynamiteModulesB#11951470:182)
......
It's very easy to reproduce by running the following code in Nexus5X Android 8 emulator
package test.map;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.LinearLayout;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.LatLng;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);
setContentView(ll);
//
MapView mapView = new MapView(this);
mapView.onCreate(null);
mapView.onResume();
mapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(final GoogleMap googleMap) {
final LatLng latLng = new LatLng(35.670, 139.760);
final CameraUpdate update = CameraUpdateFactory.newLatLngZoom(latLng, 15.0f);
googleMap.moveCamera(update);
}
});
ll.addView(mapView, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT));
}
}
This is a long standing bug in Google Maps SDK, see https://issuetracker.google.com/issues/35829548
You can the issue this by disabling indoor maps:
#Override public void onMapReady(GoogleMap googleMap) {
googleMap.setIndoorEnabled(false);
}
Question is also a duplicate of Is there a workaround/fix to these Google Maps v2 StackOverflowError crashes?

setText() not reflecting changes when called from another thread

I am a beginner in javaFX and am stuck in this one area. Any help will be appreciated a lot.
This is sample app I have made for clear understanding using scene builder. There is a text area and a button.I want to set data into the text area on the button click. The setting happens in another thread.
The code is as follows:
import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.stage.Stage;
public class TpController{
#FXML
private ScrollPane scrollPane;
#FXML
private Button button;
#FXML
public TextArea txtArea ;
private Stage stage;
public void setTextArea(TextArea txt)
{
this.txtArea = txt ;
}
public TextArea getTextArea()
{
return txtArea;
}
public void setStage(Stage stage)
{
this.stage = stage;
}
public Stage getStage()
{
return stage;
}
public void setTopText(String text) {
// set text from another class
txtArea.setText(text);
}
public void buttonHandler()
{
tpThread t = new tpThread();
t.start();
}
The tpThread class is as follows:
import java.io.IOException;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.control.TextArea;
import javafx.stage.Stage;
public class tpThread extends Thread {
#Override
public void run() {
// TODO Auto-generated method stub
FXMLLoader loader = new FXMLLoader(getClass().getResource("Justtp.fxml"));
try {
Parent root = (Parent) loader.load();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
TpController myController = loader.getController();
TextArea t = myController.getTextArea();
String data = "hi\nhello\nhow are you\nnice to meet you\nhahaha";
//System.out.println(t.setData("hi"));
myController.setTopText(data);
}
Instead of using setTopText, i have also directly used
t.setText(data);
But no use. My final output does nothing on the button click.
There are many issues with your code.
Modifications to the active scene graph off of the JavaFX application thread must be performed via Platform.runLater().
You don't need another thread to accomplish something on a button click.
You can just define an action handler for the button using setOnAction().
Event handler methods on controllers can also be cross-referenced in FXML via onAction="#handleButtonAction" where handleButtonAction is defined as a public void handleButtonAction(ActionEvent event) method in your controller.
All event handlers are invoked by the JavaFX runtime on the JavaFX application thread, so you don't need to worry about multi-threading when writing event handlers - the JavaFX event handling programming model is single threaded.
Loading an FXML as you do in your code and not attaching the resultant node to a scene is pointless as the user will never see anything that is not attached to a scene.
There may be other issues with your code which cause it not to work as you expect.
In general, for assistance debugging an issue, provide an mcve. Note it should be both minimal and complete so that somebody could copy and paste the code to replicate the issue (and pretty much nothing else).

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.

LWUIT TextArea NullPointerException

I run LWUITDemo, Some UI can not be shown successful.All of them are TextArea contained by Form.If I change TextArea to Label, it work well.
Sorry, I run it in nokia s40 sdk 2.0. When I run most of codes that include TextArea, exception ocurred;
The Code Like That(From LWUITDemo):
Form aboutForm = new Form("About");
aboutForm.setScrollable(true);
aboutForm.setLayout(new BorderLayout());
TextArea aboutText = new TextArea(getAboutText(), 5, 10);
aboutText.setEditable(false);
aboutForm.addComponent(BorderLayout.CENTER, aboutText);
aboutForm.show();
When I run it, it faild:
Form: showModal
java.lang.NullPointerException
at com.sun.lwuit.TextArea.shouldShowHint(+21)
at com.sun.lwuit.TextArea.calcPreferredSize(+4)
at com.sun.lwuit.Component.preferredSize(+63)
...
You Could Check below Code:
import com.sun.lwuit.Display;
import com.sun.lwuit.Form;
import com.sun.lwuit.TextArea;
import com.sun.lwuit.layouts.BorderLayout;
import javax.microedition.midlet.*;
public class TextMidlet extends MIDlet {
private Form aboutForm;
public TextMidlet() {
Display.init(this);
aboutForm = new Form();
aboutForm.setScrollable(true);
aboutForm.setLayout(new BorderLayout());
}
public void startApp() {
TextArea aboutText = new TextArea("hiiiiiiiiiiiiii", 5, 10);
aboutText.setEditable(false);
aboutForm.addComponent(BorderLayout.CENTER, aboutText);
aboutForm.show();
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
}
The code looks good to me. Please check that getAboutText() returns a String and does not return null.
If this does not help, you can use the LWUIT-Sources to debug your code. Set a breakpoint at TextArea.shouldShowHint and find out what it is that is null.
Check
import com.sun.lwuit.TextArea;

LWUIT assistance

import com.sun.lwuit.Button;
import com.sun.lwuit.Command;
import com.sun.lwuit.Display;
import com.sun.lwuit.Label;
import com.sun.lwuit.events.ActionEvent;
import com.sun.lwuit.events.ActionListener;
import com.sun.lwuit.layouts.BorderLayout;
import com.sun.lwuit.plaf.UIManager;
import com.sun.lwuit.util.Resources;
import java.io.IOException;
public class Ruwwa extends javax.microedition.midlet.MIDlet
implements ActionListener{
Form f;
Button mybutton1;
Button mybutton2;
Command exit;
Command ok;
public void startApp() {
Display.init(this);
f = new Form();
try {
Resources r = Resources.open("/mairuwa.res");
UIManager.getInstance().setThemeProps(r.getTheme("Mairuwa Theme"));
} catch (IOException ioe) {
ioe.printStackTrace();
}
mybutton1=new Button("Report A Problem");
mybutton2=new Button("Request Info");
f.setLayout(new BorderLayout());
f.addComponent(BorderLayout.CENTER, new Label("The Mairuwa Portal"));
ok = new Command("OK");
exit = new Command("Exit");
f.addCommand(ok);
f.addCommand(exit);
f.addCommandListener(this);
f.show();
}
public void pauseApp() {}
public void destroyApp(boolean unconditional) {}
public void actionPerformed(ActionEvent ae) {
notifyDestroyed();
}
}
I would like to add another label under the "The Mairuwa Portal" and also place two buttons ("Report A Problem","Request Information") beneath this as well. An illustration of what I am describing is
label: The Mairuwa Portal
then another label beneath it: I want to:
Then two buttons beneath this Button:Report Problem Button: Request Information
I have been able to add OK and EXIT button to the project,but this above buttons I talked about should as I described.
These buttons will carry functionality. I hope this can be done in LWUIT.
You need to include all JSR's when compiling a LWUIT application in the IDE. LWUIT doesn't require them all to run but requires 184, 226, MMAPI & file connector to compile. This is causing your verification error.
I would recommend developing with the Sun/Oracle simulators and using the more device like emulators for QA.
The exception you got means your application was built incorrectly, see that Ruwwa is in the jar file that was produced by your build. If not fix your build.

Resources