I like old Java applets. But because I really like the way JFX works, I want write some games using it (or even game making system, who knows?), but I'd like to be able to post them on my website. How would one go about doing this?
Yes, you can embed a JavaFX GUI into the Swing-based JApplet. You can do this by using the JFXPanel - it is essentially an adaptor between Swing and JavaFX panels.
Complete example:
The FXApplet class that sets-up the JavaFX GUI:
public class FXApplet extends JApplet {
protected Scene scene;
protected Group root;
#Override
public final void init() { // This method is invoked when applet is loaded
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
initSwing();
}
});
}
private void initSwing() { // This method is invoked on Swing thread
final JFXPanel fxPanel = new JFXPanel();
add(fxPanel);
Platform.runLater(new Runnable() {
#Override
public void run() {
initFX(fxPanel);
initApplet();
}
});
}
private void initFX(JFXPanel fxPanel) { // This method is invoked on JavaFX thread
root = new Group();
scene = new Scene(root);
fxPanel.setScene(scene);
}
public void initApplet() {
// Add custom initialization code here
}
}
And a test implementation for it:
public class MyFXApplet extends FXApplet {
// protected fields scene & root are available
#Override
public void initApplet() {
// this method is called once applet has been loaded & JavaFX has been set-up
Label label = new Label("Hello World!");
root.getChildren().add(label);
Rectangle r = new Rectangle(25,25,250,250);
r.setFill(Color.BLUE);
root.getChildren().add(r);
}
}
Alternatively, you can use the FXApplet gist, which also includes some documentation.
Yes, you should be able to embed JavaFX in your web page:
http://docs.oracle.com/javase/8/docs/technotes/guides/deploy/deployment_toolkit.html#BABJHEJA
http://docs.oracle.com/javase/8/javase-clienttechnologies.htm
Related
I am working on a Java project that makes use of JavaFX's ProgressBar. From what I found on StackOverflow, usually a thread needs to be added, or the program needs to implement Runnable, in order to update the ProgressBar's value dynamically, say when program is running in for loop.
However, looking at java doc and answers in stackoverflow, I am still not sure how, or what is the best way to solve my issue.
Since I have completely no knowledge on JavaFX, can anyone please provide me some hint?
Below is the Application.java as given from the project
public class MyApplication extends Application {
private static final String UI_FILE = "/ui.fxml";
#Override
public void start(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource(UI_FILE));
VBox root = (VBox) loader.load();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("Team T-03: Course Scraper");
stage.show();
}
public static void main(String args[]) {
Application.launch(args);
}
}
The Controller.java that I should implement the related loops and methods
public class Controller {
#FXML
private ProgressBar progressbar;
#FXML
void doSomething() {
for (String object : objectList) {
List<someObject> v = someOtherFunc(object);
totalObjectCount += v.size();
progress = (double) ++objectCount / v.size();
progressbar.setProgress(progress);
}
}
}
Use a Task,
and run it in a new Thread. A Task has its own progress property, and an updateProgress method that ensures the change to the progress is executed on the FX Application Thread. You can then bind your progress bar's progress to the task's:
#FXML
void doSomething() {
Task<Void> task = new Task<>() {
#Override
public Void call() {
for (String object : objectList) {
List<someObject> v = someOtherFunc(object);
totalObjectCount += v.size();
updateProgress(++objectCount, objectList.size());
}
return null ;
}
}
progressBar.progressProperty().bind(task.progressProperty());
new Thread(task).start();
}
I went through almost every post here regarding the matter but most of them doesn't explain what to do properly.
To the question:
I created a javaFX application, a dice game, human player vs. computer, but during any time while playing the game human player should be able to click button "new game" and what it should do is to restart the game from beginning.
I tried relaunching the stage again but in javafx we cannot call the launch method twice.
1)Is there a way i can implement this without restarting the whole application?
2)if not how can i restart the application completely using a button click?
Main class
public class Main {
public static void main(String[] args) {
GameUI gameUI = new GameUI();
gameUI.launch(GameUI.class, args);
}
GameUI
(i removed many codes from this class to make it short. codes that i think enough to give an idea is included. sorry if it is too long.)
public class GameUI extends Application {
//all btn and label declarations
//creating instances for necessary classes
private Scene scene;
#Override
public void start(Stage primaryStage) throws Exception {
//Displaying Dice for Player and Computer
setLabelsPlyr(diesP);
setLabels(diesC);
btnThrow = new Button("Throw");
btnThrow.setPrefSize(70, 40);
//Throw action is performed
btnThrow.setOnAction(e -> {
//setting and displaying dies
DieClass[] com = getNewDiceArrC();
lblDiceOneC.setGraphic(new ImageView(diesC[0].getDieImageC()));
//so on.....
DieClass[] playerAr = getNewDiceArrP();
lblDiceOnePlyr.setGraphic(new ImageView(diesP[0].getDieImageP()));
//so on...
});
btnNewGame = new Button("New Game");
btnNewGame.setOnAction(e -> {
**//WHAT TO DO HERE?????**
});
//setting layouts
GridPane gridPane = new GridPane();
gridPane.add(lblComputer, 0, 0);
//so on.....
Scene scene = new Scene(gridPane, 1100, 400);
primaryStage.setScene(scene);
primaryStage.setTitle("dice Game");
primaryStage.show();
}
//some other methods
public void setLabels(DieClass[] dies) {
for (int i=0; i < dies.length; i++) {
lblDiceOneC = new Label();
lblDiceOneC.setGraphic(new ImageView(dies[0].getDieImageC()));
++i;
//so on.....
break;
}
}
public void setLabelsPlyr(DieClass[] dies){
for (int i=0; i<dies.length; i++) {
lblDiceOnePlyr = new Label();
lblDiceOnePlyr.setGraphic(new ImageView(dies[0].getDieImageP()));
++i;
lblDiceTwoPlyr = new Label();
//so on......
break;
}
}
p.s I am very new to JavaFX and somewhat new to java programming.
You already noticed that you cannot do the launching process again. Therefore your best option is to rewrite the application class and move the initialisation logic to a new method:
void cleanup() {
// stop animations reset model ect.
}
void startGame(Stage stage) {
// initialisation from start method goes here
btnNewGame.setOnAction(e -> {
restart(stage);
});
stage.show();
}
void restart(Stage stage) {
cleanup();
startGame(stage);
}
#Override
public void start(Stage primaryStage) {
startGame(primaryStage);
}
Notes
Depending on the parts of the scene changed, it may be enough to change the state of some of the nodes (more efficient than creating a new scene). (Just take a look at the changes you made during the game and decide for yourself)
launch() is a static method and you should not create a instance of your application class yourself for that reason. Use Application.launch(GameUI.class, args); instead and let the method handle the creation of the GameUI instance.
It may be a better design to move the UI creation to a class different to the application class. This way reuse of the code is easier, since it does not require the creation of a instance of a subclass of Application.
In your Start() function, add the following line:
Platform.setImplicitExit(false);
This will make your application run in background without exiting.
Now, use a wrapper function to start the second time, say:
void displayApplication() {
Platform.runLater(new Runnable() {
#Override
public void run() {
try {
start(new Stage());
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
i have an application in java, and this have a one popup with javafx application (embed videos from Youtube). I see this correctly but when i close this popup, the javafx thread not close and javafx application running in background. This is my javafx class:
public class JavaFXClass extends Application {
#Override
public void start(final Stage stage) throws Exception {
final WebView webview = new WebView();
/*...*/
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
Platform.runLater( new Runnable() {
#Override
public void run() {
//I need stop javafx when this class close.
}
});
}
});
stage.show();
}
public static void LoadClass(String Data) { //I use this function to load class
/*...*/
launch(); //return error when i re-call this function (already launch).
}
If i put webview.getEngine().load(null); Platform.exit(); code in the "OnCloseRequest" works fine but an exception is created ("Attempt to call defer when toolkit not running")
i need use webview.getEngine().load(null); or similar because if i not use this, the video in webview remain playing in background. And if i not use Platform.exit() the main frame crashes (lock).
Sorry for my bad english, tried to write the best I could
use this:
[...]
stage.setOnCloseRequest(this.getCloseSystemEvent());
}
public EventHandler<WindowEvent> getCloseSystemEvent() {
return new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
Platform.exit();
}
};
}
Also, you should check the concurrency API. Your code prevents the runtime from closing the thread properly.
How to call the launch() more than once in java i am given an exception as "ERROR IN MAIN:java.lang.IllegalStateException: Application launch must not be called more than once"
I have create rest cleint in my java application when request comes it call javafx and opening webview after completing webview operarion am closing javafx windows using Platform.exit() method. when second request comes am getting this error how to reslove this error.
JavaFx Application Code:
public class AppWebview extends Application {
public static Stage stage;
#Override
public void start(Stage _stage) throws Exception {
stage = _stage;
StackPane root = new StackPane();
WebView view = new WebView();
WebEngine engine = view.getEngine();
engine.load(PaymentServerRestAPI.BROWSER_URL);
root.getChildren().add(view);
engine.setJavaScriptEnabled(true);
Scene scene = new Scene(root, 800, 600);
stage.setScene(scene);
engine.setOnResized(new EventHandler<WebEvent<Rectangle2D>>() {
public void handle(WebEvent<Rectangle2D> ev) {
Rectangle2D r = ev.getData();
stage.setWidth(r.getWidth());
stage.setHeight(r.getHeight());
}
});
JSObject window = (JSObject) engine.executeScript("window");
window.setMember("app", new BrowserApp());
stage.show();
}
public static void main(String[] args) {
launch(args);
}
RestClient Method:
Calling to JavaFX application
// method 1 to lanch javafx
javafx.application.Application.launch(AppWebview.class);
// method 2 to lanch javafx
String[] arguments = new String[] {"123"};
AppWebview .main(arguments);
You can't call launch() on a JavaFX application more than once, it's not allowed.
From the javadoc:
It must not be called more than once or an exception will be thrown.
Suggestion for showing a window periodically
Just call Application.launch() once.
Keep the JavaFX runtime running in the background using Platform.setImplicitExit(false), so that JavaFX does not shutdown automatically when you hide the last application window.
The next time you need another window, wrap the window show() call in Platform.runLater(), so that the call gets executed on the JavaFX application thread.
For a short summary implementation of this approach:
See the answer by sergioFC
If you are mixing Swing you can use a JFXPanel instead of an Application, but the usage pattern will be similar to that outlined above.
For an example of the JFXPanel apprach, see Irshad Babar
s answer.
Wumpus Sample
This example is bit more complicated than it needs to be because it also involves timer tasks. However it does provide a complete stand-alone example, which might help sometimes.
import javafx.animation.PauseTransition;
import javafx.application.*;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.*;
// hunt the Wumpus....
public class Wumpus extends Application {
private static final Insets SAFETY_ZONE = new Insets(10);
private Label cowerInFear = new Label();
private Stage mainStage;
#Override
public void start(final Stage stage) {
// wumpus rulez
mainStage = stage;
mainStage.setAlwaysOnTop(true);
// the wumpus doesn't leave when the last stage is hidden.
Platform.setImplicitExit(false);
// the savage Wumpus will attack
// in the background when we least expect
// (at regular intervals ;-).
Timer timer = new Timer();
timer.schedule(new WumpusAttack(), 0, 5_000);
// every time we cower in fear
// from the last savage attack
// the wumpus will hide two seconds later.
cowerInFear.setPadding(SAFETY_ZONE);
cowerInFear.textProperty().addListener((observable, oldValue, newValue) -> {
PauseTransition pause = new PauseTransition(
Duration.seconds(2)
);
pause.setOnFinished(event -> stage.hide());
pause.play();
});
// when we just can't take it anymore,
// a simple click will quiet the Wumpus,
// but you have to be quick...
cowerInFear.setOnMouseClicked(event -> {
timer.cancel();
Platform.exit();
});
stage.setScene(new Scene(cowerInFear));
}
// it's so scary...
public class WumpusAttack extends TimerTask {
private String[] attacks = {
"hugs you",
"reads you a bedtime story",
"sings you a lullaby",
"puts you to sleep"
};
// the restaurant at the end of the universe.
private Random random = new Random(42);
#Override
public void run() {
// use runlater when we mess with the scene graph,
// so we don't cross the streams, as that would be bad.
Platform.runLater(() -> {
cowerInFear.setText("The Wumpus " + nextAttack() + "!");
mainStage.sizeToScene();
mainStage.show();
});
}
private String nextAttack() {
return attacks[random.nextInt(attacks.length)];
}
}
public static void main(String[] args) {
launch(args);
}
}
Update, Jan 2020
Java 9 added a new feature called Platform.startup(), which you can use to trigger startup of the JavaFX runtime without defining a class derived from Application and calling launch() on it. Platform.startup() has similar restrictions to the launch() method (you cannot call Platform.startup() more than once), so the elements of how it can be applied is similar to the launch() discussion and Wumpus example in this answer.
For a demonstration on how Platform.startup() can be used, see Fabian's answer to How to achieve JavaFX and non-JavaFX interaction?
I use something like this, similar to other answers.
private static volatile boolean javaFxLaunched = false;
public static void myLaunch(Class<? extends Application> applicationClass) {
if (!javaFxLaunched) { // First time
Platform.setImplicitExit(false);
new Thread(()->Application.launch(applicationClass)).start();
javaFxLaunched = true;
} else { // Next times
Platform.runLater(()->{
try {
Application application = applicationClass.newInstance();
Stage primaryStage = new Stage();
application.start(primaryStage);
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
try this, I tried this and found successful
#Override
public void start() {
super.start();
try {
// Because we need to init the JavaFX toolkit - which usually Application.launch does
// I'm not sure if this way of launching has any effect on anything
new JFXPanel();
Platform.runLater(new Runnable() {
#Override
public void run() {
// Your class that extends Application
new ArtisanArmourerInterface().start(new Stage());
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
I am displaying html web pages in java swing using JAVA FX controls now i want to highlight a given word in the webview using JFXPanel with the help of javaFx. To display the html page i am using the following code.
public class abc extends JFrame
{
JFXPanel fxpanel;
Container cp;
public abc()
{
cp=this.getContentPane();
cp.setLayout(null);
fxpanel= new JFXPanel();
cp.add(fxpanel);
fxpanel.setBounds(600,200,400,500);
Platform.runLater(new Runnable())
{
public void run()
{
init Fx(fxpanel);
}}
);
}
public static void main(String args[])
{
abc frm= new abc();
frm.show();
}
private static void initFX(final JFXPanel fxpanel)
{
Group group = ne Group();
Scene scene= new Scene(group);
fxpanel.setScene(scene);
WebView webview= new WebView();
group.getChildren().add(webview);
webview.setMinSize(500,500);
webview.setMaxSize(500,500);
eng=webview.getEngine();
File file= new File("d:/new folder/abc.html");
try
{
eng.load(file.toURI().toURL().toString());
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
JavaFX Web Engine is capable of establishing comminucation between JavaFX and JavaScript.
So may be you can use a JavaScript to select the words in the HTML page and execute that script from the JavaFX.
Webview
JavaFX <-> JavaScript