So I have written a Controller that is supposed to navigate between multiple scenes, however, when the second scene is instantiated java.lang.NullPointerException. Here is my Controller below with a View1() and View2() in a single file mre so you can understand what is happening. My goal is just to have multiple screens and multiple models and using a switch case set different scenes on the stage.
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.canvas.*;
import javafx.scene.image.Image;
public class Controller extends Application {
private Scene scene1, scene2;
public static void main(String[] args) {
launch(args);
}
public void start(Stage theStage) {
this.scene1 = new Scene(new Group(new View1()));
this.scene2 = new Scene(new Group(new View2()));
new AnimationTimer() {
int page = 2;
#Override
public void handle(long currentNanoTime){
// System.out.println(currentNanoTime);
switch (page){
case 2:
page = 1;
theStage.setScene(scene1);
break;
case 1:
page = 2;
theStage.setScene(scene2);
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
theStage.show();
}
}
class View1 extends Group {
public View1() {
Image img = new Image("https://i.imgur.com/8tcxHWh.jpg");
Canvas canvas = new Canvas(img.getWidth(), img.getHeight());
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.drawImage(img, 0, 0, canvas.getWidth(), canvas.getHeight());
getChildren().add(canvas);
}
}
class View2 extends Group {
public View2() {
Image img = new Image("https://i.imgur.com/BF3ty6o.jpg");
Canvas canvas = new Canvas(img.getWidth(), img.getHeight());
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.drawImage(img, 0, 0, canvas.getWidth(), canvas.getHeight());
getChildren().add(canvas);
}
}
I would suggest against using AnimationTimer. I would suggest you use Buttons to load different displays. This app demos one way of using Buttons to switch between displays.
Main
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
final StackPane mainDisplay = new StackPane();
final ViewOne viewOne = new ViewOne();
final ViewTwo viewTwo = new ViewTwo();
mainDisplay.getChildren().add(viewOne);//Load first view.
Button btnStageOne = new Button("View One");
Button btnStageTwo = new Button("View Two");
btnStageOne.setOnAction((event) -> {
if(!mainDisplay.getChildren().get(0).equals(viewOne))//If sceneone is not loaded, load it.
{
mainDisplay.getChildren().set(0, viewOne);
}
});
btnStageTwo.setOnAction((event) -> {
if(!mainDisplay.getChildren().get(0).equals(viewTwo))//If scenetwo is not loaded, load it.
{
mainDisplay.getChildren().set(0, viewTwo);
}
});
HBox hbButtonPanel = new HBox(btnStageOne, btnStageTwo);
VBox root = new VBox(mainDisplay, hbButtonPanel);
Scene scene = new Scene(root);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
ViewOne
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
/**
*
* #author sedrick
*/
public final class ViewOne extends StackPane{
Label label = new Label();
public ViewOne() {
label.setText("Scene One!");
getChildren().add(label);
}
}
ViewTwo
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
/**
*
* #author sedrick
*/
public final class ViewTwo extends StackPane{
Label label = new Label();
public ViewTwo() {
label.setText("Scene Two!");
getChildren().add(label);
}
}
Related
I need some help if you can spare a few minutes.
I am in a bit of a pickle as I try to make this work.
I have a javaFX class like this
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class FoorballTeam extends Application {
int i1=0;
int i3=0;
String[] PlayerNames = new String[12];
int[] goals = new int[12];
#Override
public void start(Stage primaryStage) {
player[] playerData = new player[12];
Button btn = new Button();
btn.setText("add Player");
GridPane root = new GridPane();
root.add(btn,0,0);
int i2;
for (i2=0;i2<=11;i2++)
{playerData[i2]=new player();}
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
playerData[i3].player(root, i3);
i3++;
}
});
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public String[] getPlayerNames() {
return PlayerNames;
}
public void setPlayerNames(String[] PlayerNames) {
this.PlayerNames = PlayerNames;
}
public int[] getGoals() {
return goals;
}
public void setGoals(int[] goals) {
this.goals = goals;
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
and a second class named player like this
import javafx.event.EventType;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
public class player {
String NameOfPlayer = new String();
int goalsOfPlayer;
public void player (GridPane root,int numberOfPlayer)
{
TextField name = new TextField();
TextField goals = new TextField();
GridPane grid = new GridPane();
grid.add(name,0,0);
grid.add(goals,1,0);
root.add(grid,0,numberOfPlayer+1);
System.out.println("player " + numberOfPlayer + " added");
name.textProperty().addListener((observable, oldValue, newValue) -> {
NameOfPlayer=newValue;
});
goals.textProperty().addListener((observable, oldValue, newValue) -> {
goalsOfPlayer=Integer.parseInt(newValue);
});
}
}
I want every time that I make a change to a players name or goals to pass this change on the two arrays PlayerNames[] and goals[] of the main class.
for example if player1 changes goals from 1 to 2 I want the goals[1]=2.
Also is it possible to put a listener to this two arrays so when a player changes name or goals to trigger the listener.
Any help will be appreciated.
One simple solution is to warp the int[] array with an observable list, and listen to changes in this list :
import java.util.Arrays;
import java.util.Random;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class ListenToArrayCahnges extends Application {
private final int SIZE = 12;
private final Integer[] goals = new Integer[SIZE];
private final Random rand = new Random();
private int counter = 0;
#Override
public void start(Stage primaryStage) {
Arrays.fill(goals, 0); //initial values
//Warp array with an observable list. list back by array so it is of fixed length
ObservableList<Integer> goalsList = FXCollections.observableArrayList(Arrays.asList(goals));
//add listener to list
goalsList.addListener((ListChangeListener<Integer>) c ->{
//respond to list changes
System.out.println("Goals changed to : "+ goalsList);
});
//button to change the list
Button btn = new Button();
btn.setText("Add goal");
btn.setOnAction(event -> {
goalsList.set(counter, rand.nextInt(100));
counter = ++counter % SIZE ; //increment counter 0,1,2....11 and back to 0
});
GridPane root = new GridPane();
root.add(btn,0,0);
Scene scene = new Scene(root, 150, 50);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Note that the posted mcve represents the problem that needs to be solved (or in this case a solution to it), and not the specific application or use case.
I'm designing a stopwatch using JavaFX. The code runs well. Except for enormous cumulative memory leaks over time. The leak increases whenever I increase the Timeline's framerate. I'm currently on Ubuntu 16.04 with 4gigs of RAM, and the leak is happening at a speed of 300MB/min at 30fps. That's 5MBps. I can understand that this may happen due to the repetitive drawing over the Scene, but why would it be cumulative? Shouldn't the JVM take care of this?
Main.java :
package UI;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBar;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
primaryStage.setTitle("StopWatch");
primaryStage.setScene(new Scene(getPane(), 400, 400));
primaryStage.show();
}
private BorderPane getPane(){
BorderPane pane = new BorderPane();
ClockUI clockUI = new ClockUI();
clockUI.setMinSize(200,200);
pane.setCenter(clockUI);
ButtonBar buttonBar = new ButtonBar();
Button startButton = new Button("Start");
startButton.setOnAction(e->clockUI.startClock());
Button pauseButton = new Button("Stop");
pauseButton.setOnAction(e->clockUI.stopClock());
Button resetButton = new Button("Reset");
resetButton.setOnAction(e->clockUI.resetClock());
buttonBar.getButtons().addAll(startButton, pauseButton, resetButton);
pane.setBottom(buttonBar);
return pane;
}
public static void main(String[] args) {
System.setProperty("prism.lcdtext","false");
launch(args);
}
}
ClockUI.java :
package UI;
import javafx.animation.*;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.transform.Rotate;
import javafx.util.Duration;
/**
* Created by subhranil on 23/6/17.
*/
public class ClockUI extends StackPane {
private final Rotate hourRotate;
private final Rotate minuteRotate;
private final Rotate secondRotate;
private final Timeline hourTimeline;
private final Timeline minuteTimeline;
private final Timeline secondTimeline;
private final ParallelTransition clockTransition;
public ClockUI() {
super();
Line hourHand = getHand(80, Color.WHITE);
hourRotate = getRotate(hourHand);
hourTimeline = createRotateTimeline(Duration.hours(12), hourRotate);
Line minuteHand = getHand(100, Color.WHITE);
minuteRotate = getRotate(minuteHand);
minuteTimeline = createRotateTimeline(Duration.minutes(60), minuteRotate);
Line secondHand = getHand(90, Color.WHITE);
secondRotate = getRotate(secondHand);
secondTimeline = createRotateTimeline(Duration.seconds(60), secondRotate);
clockTransition = new ParallelTransition(hourTimeline, minuteTimeline, secondTimeline);
Circle back = new Circle(120);
back.centerXProperty().bind(widthProperty().divide(2));
back.centerYProperty().bind(heightProperty().divide(2));
back.setStyle("-fx-fill: #555555");
setStyle("-fx-background-color: #333333;");
getChildren().addAll(back, hourHand, minuteHand, secondHand);
}
private Timeline createRotateTimeline(Duration duration, Rotate rotate) {
Timeline timeline = new Timeline(30);
timeline.getKeyFrames().add(new KeyFrame(duration, new KeyValue(rotate.angleProperty(), 360)));
timeline.setCycleCount(Animation.INDEFINITE);
return timeline;
}
public void startClock() {
if (clockTransition.getStatus() != Animation.Status.RUNNING) {
clockTransition.play();
}
}
public void stopClock() {
if (clockTransition.getStatus() == Animation.Status.RUNNING) {
clockTransition.pause();
}
}
public void resetClock() {
stopClock();
clockTransition.stop();
}
private Rotate getRotate(Line line){
Rotate r = new Rotate(0);
r.pivotXProperty().bind(line.startXProperty());
r.pivotYProperty().bind(line.startYProperty());
line.getTransforms().add(r);
return r;
}
private Line getHand(int size, Paint color) {
Line hand = new Line();
hand.startXProperty().bind(widthProperty().divide(2));
hand.startYProperty().bind(heightProperty().divide(2));
hand.endXProperty().bind(widthProperty().divide(2));
hand.endYProperty().bind(heightProperty().divide(2).subtract(size));
hand.setStroke(color);
hand.setStrokeWidth(3);
return hand;
}
}
INFO : I've tried various other methods, like running an ExecutorService, using Task and Thread, but all yield same results.
Try this and see if you are having the same problem.
ClockGUI
import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.scene.shape.*;
import javafx.scene.transform.*;
/**
*
* #author Sedrick
*/
public class ClockGUI {
Circle clockFace;
Line second;
Line minute;
Line hour;
Rotate secondRotation;
Rotate minuteRotation;
Rotate hourRotation;
AnchorPane currentClockFace;
public ClockGUI()
{
currentClockFace = new AnchorPane();
currentClockFace.setPrefSize(100, 100);
clockFace = new Circle(100 / 2, 100 / 2, 100 / 2);
clockFace.setStroke(Color.BLACK);
clockFace.setFill(Color.TRANSPARENT);
second = new Line(100 / 2, 100 / 2, 100 / 2, 100 / 2 - 40);
secondRotation = new Rotate();
secondRotation.pivotXProperty().bind(second.startXProperty());
secondRotation.pivotYProperty().bind(second.startYProperty());
second.getTransforms().add(secondRotation);
minute = new Line(100 / 2, 100 / 2, 100 / 2, 100 / 2 - 30);
minuteRotation = new Rotate();
minuteRotation.pivotXProperty().bind(minute.startXProperty());
minuteRotation.pivotYProperty().bind(minute.startYProperty());
minute.getTransforms().add(minuteRotation);
hour = new Line(100 / 2, 100 / 2, 100 / 2, 100 / 2 - 20);
hourRotation = new Rotate();
hourRotation.pivotXProperty().bind(hour.startXProperty());
hourRotation.pivotYProperty().bind(hour.startYProperty());
hour.getTransforms().add(hourRotation);
currentClockFace.getChildren().addAll(clockFace, second, minute, hour);
}
public AnchorPane getCurrentClock()
{
return currentClockFace;
}
public void rotateSecondLine()
{
secondRotation.setAngle(secondRotation.getAngle() + 6);
}
public double getRotateSecondLine()
{
return secondRotation.getAngle();
}
public void setRotateSecond(double degree)
{
secondRotation.setAngle(degree);
}
public void rotateMinuteLine()
{
minuteRotation.setAngle(minuteRotation.getAngle() + 6);
}
public double getRotateMinuteLine()
{
return minuteRotation.getAngle();
}
public void setRotateMinute(double degree)
{
minuteRotation.setAngle(degree);
}
public void rotateHourLine()
{
hourRotation.setAngle(hourRotation.getAngle() + 6);
}
public double getRotateHourLine()
{
return hourRotation.getAngle();
}
public void setRotateHour(double degree)
{
hourRotation.setAngle(degree);
}
}
Main
import javafx.animation.*;
import javafx.application.*;
import javafx.event.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.*;
import javafx.util.*;
/**
*
* #author Sedrick
*/
public class JavaFXApplication54 extends Application {
#Override
public void start(Stage primaryStage)
{
VBox root = new VBox();
ClockGUI cgui = new ClockGUI();
StackPane stackpane = new StackPane();
stackpane.getChildren().add(cgui.getCurrentClock());
root.getChildren().add(stackpane);
Button btn = new Button("Rotate seconds");
btn.setOnAction((event) -> {
cgui.rotateSecondLine();
});
Button btn2 = new Button("Rotate minutes");
btn2.setOnAction((event) -> {
cgui.rotateMinuteLine();
});
Button btn3 = new Button("Rotate hours");
btn3.setOnAction((event) -> {
cgui.rotateHourLine();
});
root.getChildren().addAll(btn, btn2, btn3);
Scene scene = new Scene(root, 300, 250);
Timeline timeline = new Timeline();
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.getKeyFrames().add(
new KeyFrame(Duration.seconds(1),
new EventHandler() {
// KeyFrame event handler
#Override
public void handle(Event event)
{
System.out.println(cgui.getRotateSecondLine());
cgui.rotateSecondLine();
if (cgui.getRotateSecondLine() >= 360) {
cgui.setRotateSecond(0);
cgui.rotateMinuteLine();
}
if (cgui.getRotateMinuteLine() >= 360) {
cgui.setRotateMinute(0);
cgui.rotateHourLine();
}
if (cgui.getRotateHourLine() >= 360) {
cgui.setRotateHour(0);
}
}
}
));
timeline.playFromStart();
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}
I'm trying to use the Magnifier from jfxtras-labs 2.2 to see more details on an image. At the same time, I want to draw a rectangle on top of this image. The problem is, that the Magnifier blocks all other events.
Here is my sample code:
package magnifiertest;
import java.io.File;
import javax.imageio.ImageIO;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import jfxtras.labs.scene.control.Magnifier;
public class TestMagnifier extends Application {
Group groupForRectangles;
ImageView pageImageView;
private boolean new_rectangle_is_being_drawn;
private Rectangle new_rectangle;
private double starting_point_x;
private double starting_point_y;
public static void main(String[] args) {
launch();
}
#Override
public void start(Stage primaryStage) throws Exception {
StackPane root = new StackPane();
groupForRectangles = new Group();
groupForRectangles = new Group();
pageImageView = new ImageView();
pageImageView.setPreserveRatio(true);
pageImageView.setFitHeight(800);
pageImageView.setFitWidth(600);
pageImageView.setImage(SwingFXUtils.toFXImage(ImageIO.read(new File("/sample/Penguins.jpg")), null));
groupForRectangles.setOnMouseDragged(event -> {
setOnMouseDragged(event);
});
groupForRectangles.setOnMousePressed(event -> {
setOnMousePressed(event);
});
groupForRectangles.setOnMouseReleased(event -> {
setOnMouseReleased(event);
});
//If you outcomment the following lines, the rectangle drawing works
Magnifier m = new Magnifier(pageImageView);
groupForRectangles.getChildren().add(pageImageView);
groupForRectangles.getChildren().add(m);
root.getChildren().add(groupForRectangles);
primaryStage.setScene(new Scene(root, 800, 600));
primaryStage.show();
}
public void setOnMousePressed(MouseEvent event) {
System.out.println("mouse pressed");
if (new_rectangle_is_being_drawn == false) {
starting_point_x = event.getX();
starting_point_y = event.getY();
System.out.println(starting_point_x + " ; " + starting_point_y);
groupForRectangles.getChildren().remove(new_rectangle);
new_rectangle = new Rectangle();
new_rectangle.setFill(Color.TRANSPARENT);
new_rectangle.setStroke(Color.BLACK);
groupForRectangles.getChildren().add(new_rectangle);
new_rectangle_is_being_drawn = true;
}
}
public void setOnMouseDragged(MouseEvent event) {
if (new_rectangle_is_being_drawn == true) {
double current_ending_point_x = event.getX();// - sub.getLayoutX();
double current_ending_point_y = event.getY();// - sub.getLayoutY();
adjust_rectangle_properties(starting_point_x, starting_point_y, current_ending_point_x,
current_ending_point_y, new_rectangle);
}
}
public void setOnMouseReleased(MouseEvent event) {
if (new_rectangle_is_being_drawn == true) {
new_rectangle.setFill(Color.TRANSPARENT);
new_rectangle_is_being_drawn = false;
}
}
void adjust_rectangle_properties(double starting_point_x, double starting_point_y, double ending_point_x,
double ending_point_y, Rectangle given_rectangle) {
given_rectangle.setX(starting_point_x);
given_rectangle.setY(starting_point_y);
given_rectangle.setWidth((ending_point_x - starting_point_x));
given_rectangle.setHeight((ending_point_y - starting_point_y));
if (given_rectangle.getWidth() < 0) {
given_rectangle.setWidth(-given_rectangle.getWidth());
given_rectangle.setX(given_rectangle.getX() - given_rectangle.getWidth());
}
if (given_rectangle.getHeight() < 0) {
given_rectangle.setHeight(-given_rectangle.getHeight());
given_rectangle.setY(given_rectangle.getY() -
given_rectangle.getHeight());
}
}
}
Thanks.
I've looked around and everything always end with www.google.com looking like this: Webpage bug?
How can I open a webpage within a JFrame/JPanel and have it so that it looks like the normal whole page?
This is what I last tried:
JEditorPane website = null;
try {
website = new JEditorPane("http://www.google.com/");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
website.setEditable(false);
JFrame frame = new JFrame("Google");
frame.add(new JScrollPane(website));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.pack();
}
As MadProgrammer suggested I took a look into JavaFX and found it was just what I wanted with this creating a basic webpage:
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class WebViewSample extends Application {
private Scene scene;
#Override public void start(Stage stage) {
// create the scene
stage.setTitle("Web View");
scene = new Scene(new Browser(),750,500, Color.web("#666970"));
stage.setScene(scene);
stage.show();
}
public static void main(String[] args){
launch(args);
}
}
class Browser extends Region {
final WebView browser = new WebView();
final WebEngine webEngine = browser.getEngine();
public Browser() {
//apply the styles
getStyleClass().add("browser");
// load the web page
webEngine.load("http://www.oracle.com/products/index.html");
//add the web view to the scene
getChildren().add(browser);
}
private Node createSpacer() {
Region spacer = new Region();
HBox.setHgrow(spacer, Priority.ALWAYS);
return spacer;
}
#Override protected void layoutChildren() {
double w = getWidth();
double h = getHeight();
layoutInArea(browser,0,0,w,h,0, HPos.CENTER, VPos.CENTER);
}
#Override protected double computePrefWidth(double height) {
return 750;
}
#Override protected double computePrefHeight(double width) {
return 500;
}
}
I am having one code that send command to server.
public static void createAndSendCommand(String action, byte[] data) {
if (action.equals(OE_Constants.ACTION_UPDATE)) {
File file = new File(OE_Constants.FILE_BACKUP_TOPOLOGY);
Command command = ConnectionManager.populateData(file);
FrontEndClient.sendCommandToServer(command);
}
}
and
public static boolean sendCommandToServer(Command command) {
try {
outStream.writeObject(command);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
And I am receiving result like below.
public void receiveResultFromServer() {
try {
while(!clientSocket.isClosed()) {
CommandExecResult result;
try {
result = (CommandExecResult) inStream.readObject();
ConnectionManager.parseCommandExecutionResult(result);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
}
}
}
Now I want to wait for command to be successfully executed on server till the result of it is received by client. I want to show some Progress indicator type of UI ....how to do that?
Thanks!
Use a Task or a Service for your long running server calls.
Use Task.updateProgress() to inform on the current progress / work done.
Bind the progressProperty of your running Task to a ProgressBar or ProgressIndicator.
You specified the tags java and javafx. Here is my solution for javafx. It is a simple dialog that can be updated from 'outside' via binding.
WorkingDialog.java:
package stackoverflow.progress;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.WindowEvent;
public final class WorkingDialog extends Stage implements Initializable {
private static final Logger LOG = Logger.getLogger(WorkingDialog.class.getName());
public SimpleDoubleProperty progress = new SimpleDoubleProperty(0);
public WorkingDialog(String title, Stage owner) {
super();
setTitle(title);
initStyle(StageStyle.UTILITY);
initModality(Modality.APPLICATION_MODAL);
initOwner(owner);
double w = 300;
double h = 200;
setWidth(w);
setHeight(h);
double dx = (owner.getWidth() - w) / 2;
double dy = (owner.getHeight() - h) / 2;
setX(owner.xProperty().get() + dx);
setY(owner.yProperty().get() + dy);
setResizable(false);
showDialog(progress);
}
public void hideDialog() {
Platform.runLater(() -> {
hide();
});
}
public void setTitleText(String title) {
Platform.runLater(() -> {
setTitle(title);
});
}
private void showDialog(SimpleDoubleProperty progress) {
//scene : gridPane : 0,0->progressbar,0,1->borderpane : center->button
GridPane gridPane = new GridPane();
gridPane.setGridLinesVisible(false);
gridPane.setPadding(new Insets(10));
gridPane.setHgap(5);
gridPane.setVgap(5);
setOnCloseRequest((WindowEvent e) -> {
e.consume();
});
ProgressBar pb = new ProgressBar(-1);
pb.setPrefWidth(300);
pb.progressProperty().bind(progress);
BorderPane borderPane = new BorderPane(pb);
gridPane.add(borderPane, 0, 0);
Scene scene = new Scene(gridPane);
setScene(scene);
sizeToScene();
show();
}
#Override
public void initialize(URL location, ResourceBundle resources) {
}
}
Example for usage (WorkingDialogTest.java):
package stackoverflow.progress;
import java.util.logging.Logger;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.event.ActionEvent;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class WorkingDialogTest extends Application {
private static final Logger LOG = Logger.getLogger(WorkingDialogTest.class.getName());
#Override
public void start(Stage primaryStage) {
Group group = new Group();
Scene scene = new Scene(group);
primaryStage.setTitle("Dialogs");
primaryStage.setWidth(600);
primaryStage.setHeight(400);
Button button = new Button("function");
button.setOnAction((ActionEvent e) -> {
WorkingDialog wd = new WorkingDialog("title", primaryStage);
new Thread(() -> {
int counter = 10;
for (int i = 0; i < counter; i++) {
try {
wd.progress.set(1.0 * i / (counter - 1));
Thread.sleep(1000); //<-------- do more useful stuff here
} catch (InterruptedException ex) {
}
}
wd.hideDialog();
}).start();
});
HBox hbox = new HBox(button);
group.getChildren().addAll(hbox);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
It looks like this: