Showing progress while chart is loading javafx - javafx

I'm writing a program in javafx where different charts are being shown. The chart values are based on data collected from a database. Since I have to first collect the data from the database and then do som further calculations in the code some of the charts take some time to load. I would like a progress indicator to show the progress of the chart loading. Before the chart is shown the user selects what kind of chart he/she wants and then clicks a 'Go' button to view the chart. Before the button is clicked the progress indicator looks like this and works perfectly fine:
When the user clicks the 'Go' button the chart starts loading and I would like the progress indicator to show the loading progress in percent. The problem is that as soon as the chart starts loading the progress indicator freezes. All changes that I try to do to the progress bar (and the text below it) will not be done until the entire chart is fully loaded, which kind of ruins the whole purpose of the progress indicator.
Is there any way to make the progress indicator change WHILE the chart is loading?
Thanks!

Do this in a different Thread from a Task, update the progress and bind the progress property to the progress of the Task:
#Override
public void start(Stage primaryStage) {
ProgressIndicator progressIndicator = new ProgressIndicator();
Button btn = new Button("Go");
VBox root = new VBox(10, btn, progressIndicator);
btn.setOnAction((ActionEvent event) -> {
Task<LineChart> task = new Task<LineChart>() {
#Override
protected LineChart call() throws Exception {
for (int i = 0; i < 10; i++) {
try {
// do some work
Thread.sleep(500);
} catch (InterruptedException ex) {
}
updateProgress(10 * i, 100);
}
updateProgress(100, 100);
return new LineChart(new NumberAxis(), new NumberAxis());
}
};
progressIndicator.progressProperty().bind(task.progressProperty());
task.setOnSucceeded(evt -> {
// handle successful completion of task on application thread
root.getChildren().set(root.getChildren().indexOf(progressIndicator), task.getValue());
});
new Thread(task).start();
});
Scene scene = new Scene(root, 300, 300);
primaryStage.setScene(scene);
primaryStage.show();
}

Related

JavaFX MenuItem, handling the event

I'm developing an small application and I have a problem when creating the menu bar.
This is my start method:
public void start(#SuppressWarnings("exports") Stage prymaryStage) throws Exception {
// Stats menu
Menu statsMenu = new Menu("Stats");
// PairName menu
Menu pairNameMenu = new Menu("Choose pair");
// Stats Menu items
MenuItem gStats = new MenuItem("General stats");
// Pair list
ArrayList<String> pairNameList = DatabaseMethods.returnPairNameList();
// PairName items (probably i will have to change)
for (String item : pairNameList) {
pairNameMenu.getItems().add(new MenuItem(item));
}
statsMenu.getItems().addAll(gStats, pairNameMenu);
// Main menu bar
MenuBar menuBar = new MenuBar();
menuBar.getMenus().addAll(statsMenu);
// BorderPane settings
BorderPane borderPane = new BorderPane();
borderPane.setTop(menuBar);
Scene scene = new Scene(borderPane, 1200, 800);
prymaryStage.setTitle("English minimal pair training");
prymaryStage.setScene(scene);
prymaryStage.show();
}
The problem I have is in this part of the code:
ArrayList<String> pairNameList = DatabaseMethods.returnPairNameList();
// PairName items (probably i will have to change)
for (String item : pairNameList) {
pairNameMenu.getItems().add(new MenuItem(item));
}
I was trying to create the items of a submenu from an ArrayList. This data is fetch from a database and the data is returned in form of an ArrayList. I didn't find any other way to do the menu items than pairNameMenu.getItems().add(new MenuItem(item)); inside the for loop.
Now I want to handle the click in the items but I don't know how to do it. I've tried with .setOnAction but Eclipse says the .add(new MenuItem(item)) can't be use in that case and recomends .addAll and the same happens, Eclipse says that's an error and recomends .add
I tried to add this code after new MenuItem(item)
.addEventHandler(new EventHandler<ActionEvent>() {
public void handle(ActionEvent even) {
}
})
But it didn't work either.
I'm pretty new to Java and JavaFX, this is my first project so sorry if this is a very basic question.
Thank you for your time
You have to loop through pairNameMenu items after you have created and added all the items to pairNameMenu:
pairNameMenu.getItems().foreach((item) ->{
item.addEventHandler.....
....
....
});
or do something like below when creating the MenuItems:
for (String item : pairNameList) {
MenuItem tempMenuItem = new MenuItem(item);
tempMenuItem..addEventHandler.....
....
....
pairNameMenu.getItems().add(tempMenuItem);
}

JavaFX keyboard input stops working after adding buttons

I am building a game engine as a school project. When I add button to the same group as where I have my canvas, I can't control my player anymore with keyboard. Buttons and everything else still works like normal.
My code is pretty huge, so this is a simplified code of the problem:
public abstract class GEngine extends Application {
public void start(Stage theStage) throws Exception {
try {
this.stage = theStage;
Group root = new Group();
Scene theScene = new Scene(root);
stage.setScene(theScene);
Canvas canvas = new Canvas(windowWidth, windowHeight);
root.getChildren().add(canvas);
Button btn = new Button("new");
btn.setOnMousePressed(e->System.out.println("press"));
root.getChildren().add(btn);
Timeline gameLoop = new Timeline();
gameLoop.setCycleCount(Timeline.INDEFINITE);
// Handle input
theScene.setOnKeyPressed(Input::handlePressed);
theScene.setOnKeyReleased(Input::handleReleased);
// Control game loop and it's speed
KeyFrame kf = new KeyFrame(
Duration.seconds(0.017), // 60 FPS
(e)->this.controlGameLoop());
gameLoop.getKeyFrames().add( kf );
gameLoop.play();
stage.show();
} catch (Exception e) {
e.printStackTrace();
stop();
}
}
}
There is probably something happening on the background which I just don't understand. I can show my Input class code too if somebody wants to see it, but in my understanding it's not necessary.
I have tried using AnchorPane as main root and make a separate groups for buttons and canvas which I add the to the AnchorPane, but that did not help at all. That was pretty much the only offered solution I could find from google.
Adding btn.setFocusTraversable(false); fixed the problem, thanks to Luxusproblem for providing the answer!

How to handle wrong drop location in JavaFx?

In my GUI I create some dices (ImageView) and I can drag and drop them in one specific GridPane. When I drop a dice into the specific GridPane, the dice disappears from the initial location and it moves to the right position. This works fine only if I choose the right drop location.
The problem is how can I manage the wrong drop location?
Actually if I drop a dice in a wrong location (like outside the Gridpane) the dice disappears like it was moved to the right position.
I want to restore the dice to the original location if the dice isn't placed to the GridPane.
Is there a method can help me to check if I drop into the right location? Or something can prevent to drop into the wrong location?
You can check the transferMode property of the DragEvent passed to the onDragDone event:
dragSource.setOnDragDone(evt -> {
if (evt.getTransferMode() == null) {
System.out.println("drag aborted");
} else {
System.out.println("drag successfully completed");
}
});
Note: this requires you to mark the drag gesture as completed in the onDragDropped event handler using setDropCompleted. Example:
#Override
public void start(Stage primaryStage) {
Button source = new Button("Not dragged yet");
Button target = new Button("target");
HBox root = new HBox(20, source, target);
source.setOnDragDetected(evt -> {
Dragboard db = source.startDragAndDrop(TransferMode.COPY);
ClipboardContent content = new ClipboardContent();
content.putString(source.getText());
db.setContent(content);
});
source.setOnDragDone(evt -> {
source.setText(evt.getTransferMode() == null ? "failure" : "success");
});
target.setOnDragOver(evt -> {
if (evt.getDragboard().hasString()) {
evt.acceptTransferModes(TransferMode.COPY);
evt.consume();
}
});
target.setOnDragDropped(evt -> {
String value = evt.getDragboard().getString();
target.setText(value);
evt.setDropCompleted(true);
evt.consume();
});
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}

Add level in JavaFX during loading operation

I have the following UI
So , you insert a keyword and then press "Cerca" (it's like Search in Italian) , then the Google Custom Search Api show the first 10 pictures. During the Custom search API are processing the results (the pictures) I want to show an other picture like this
(I know it's big but the dimension is not the main point now). My idea is simple, I want to put the picture one "level"(don't know exactly how to call ) over the UI, then the picture will be not visible in 3 case: 1) When the API will end their job 2)If I don't have results 3) If I get an exception. My question is, which is the best approach to do this ? And then, Should I use Threads?
I hope I was clear
UPDATE:
This is the code of "cerca" button
cerca.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
// Task<Boolean> task = new Task <Boolean>(){
//
// #Override
// protected Boolean call() throws Exception {
// // TODO Auto-generated method stub
// return null;
// }
//
//
// };
String searchKeyWord = userTextField.getText();
result = getSearchResult(searchKeyWord);
for ( i=0; i<result.size(); i++)
{
System.out.println("" +result.get(i));
ImageView resultview;
resultview = new ImageView(result.get(i));
resultview.setFitWidth(130);
resultview.setFitHeight(130);
// resultview.setStyle("-fx-border:6; -fx-border-color: green;");
if(j==4)
{
j=0;
k++;
}
resultgrid.add(resultview, j,k );
j++;
VBox vbox = new VBox();
resultgrid.setHgap(50);
resultgrid.setVgap(50);
// resultgrid.setStyle("-fx-border:1; -fx-border-color: red;");
vbox.getChildren().add(resultgrid);
vbox.setSpacing(10);
vbox.setPadding(new Insets(90, 0, 10, 220)); //TOP RIGHT BOTTOM LEFT
// content.setAlignment(resultgrid, Pos.TOP_RIGHT);
getChildren().add(vbox);
final int ind = i;
resultview.setOnMouseClicked((ev) ->{
if (ev.getClickCount()==2)
{
image = SwingFXUtils.fromFXImage(resultview.getImage(), null);
parent.setCrop(image);
}
});
}
}
});
Have a look at Task. It has setOnSucceeded() and setOnFailed() which will come handy in your case.
You can basically create a new Task when the search takes place. The search will run in background and you can show the loading UI in the screen.
If the task completes successfully, you can load the new screen with the results.
If the task fails, you can show an error message near the search TextField.
In case of exception, you can catch it and write the necessary code.

JavaFX Timeline - How to stop it from elsewhere in class?

first post on here so please be gentle...
I am fairly new to JavaFX and have successfully set up quite a complicated GUI which reads a csv file in order to populate certain components within the GUI.
I'm using a timeline in the intialize function for the GUI Controller which fires a button every second on the GUI - the button calls a function which reads the csv file form disc.. all this is working fine.
When I quit/exit the GUI stage I want to stop the timeline from running... but can't seem to manage this...
I have a small function which loads the Stage and also has an event listener to detect when it's closed... what I'd like to do is be able to close the timeline at the commented line... in the try/catch section.
public void Show_MACD() throws IOException
{
Parent root = FXMLLoader.load(getClass().getResource("MACD Turbo.fxml"));
Scene scene = new Scene(root);
Stage stage = new Stage();
stage.setScene(scene);
stage.setTitle("FX AlgoTrader MACD Turbo");
stage.show();
JavaFX.thisstage=stage;
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent we) {
LoginController sp=new LoginController();
try {
//how can I stop the timeline here?
sp.Show_Products(); // this loads up another stage - a menu in fact
} catch (IOException ex) {
Logger.getLogger(MACD_Controller.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
//System.out.println("running");
}
Here's the section in the initialize function where the timeline is set up and run from....(this is in the same class as the controller called 'MACD_Controller' which is also home to the 'Show_MACD' function which has a event listener for window close events.. that's kind of where I would like to stop the timeline ie when the window closes)
#Override
public void initialize(URL url, ResourceBundle rb) {
final Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent)
{
Refresh.fire(); //Refresh is a button on the GUI which calls the csv file
}
}));
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.play();
}
I know I need to somehow create a reference to 'timeline' so that I can use the 'timeline.stop' function... I've tried all sorts of mumbo jumbo but I keep getting an NPE.
I know this is super basic but I'm a bit stuck..
Cheers
Crispin

Resources