1

I want to change the text under Progress Indicator. By default, when the ProgressIndicator has completed its Progress the text is Done, I want to be able to edit this text with any user-defined text or text depending on the locale.

When I run the program output shows that text has been changed, but on the GUI it doesn't change. Please look at the following pictures :

enter image description here enter image description here

MCVE

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class Main extends Application {
    Task copyWorker;
    public static void main(String[] args) {
        Application.launch(args);
    }
    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Background Processes");
        Group root = new Group();
        Scene scene = new Scene(root, 330, 120, Color.WHITE);

        BorderPane mainPane = new BorderPane();
        root.getChildren().add(mainPane);

        final Label label = new Label("Files Transfer:");
        final ProgressIndicator progressIndicator = new ProgressIndicator(0);
        progressIndicator.progressProperty().addListener(new ChangeListener<Number>() {  
        @Override  
        public void changed(ObservableValue<? extends Number> ov, Number t, Number newValue) {  
            progressIndicator .applyCss();  

            // If progress is 100% then show Text  
            if (newValue.doubleValue() >= 1.0) {  
                // Apply CSS so you can lookup the text  
                Text text = (Text) progressIndicator .lookup(".percentage");//also I checked .lookup(.text.percentage) version  
                System.out.println(text.getText());  
                // This text replaces "Done"  
                text.setText("some text");  
                //for testing  
                Text x= (Text) progressIndicator .lookup(".percentage");                 
                System.out.println(x.getText());//output shows that the text under progress indicator is changed  
                }  
      }}); 
        final HBox hb = new HBox();
        hb.setSpacing(5);
        hb.setAlignment(Pos.CENTER);
        hb.getChildren().addAll(label, progressIndicator);
        mainPane.setTop(hb);

        final Button startButton = new Button("Start");
        final Button cancelButton = new Button("Cancel");
        final HBox hb2 = new HBox();
        hb2.setSpacing(5);
        hb2.setAlignment(Pos.CENTER);
        hb2.getChildren().addAll(startButton, cancelButton);
        mainPane.setBottom(hb2);

        startButton.setOnAction(new EventHandler<ActionEvent>() {

            public void handle(ActionEvent event) {
                startButton.setDisable(true);
                progressIndicator.setProgress(0);
                cancelButton.setDisable(false);
                copyWorker = createWorker();

                progressIndicator.progressProperty().unbind();
                progressIndicator.progressProperty().bind(copyWorker.progressProperty());

                copyWorker.messageProperty().addListener(new ChangeListener<String>() {
                    public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                        System.out.println(newValue);
                    }
                });

                new Thread(copyWorker).start();
            }
        });
        cancelButton.setOnAction(new EventHandler<ActionEvent>() {
            public void handle(ActionEvent event) {
                startButton.setDisable(false);
                cancelButton.setDisable(true);
                copyWorker.cancel(true);
                progressIndicator.progressProperty().unbind();
                progressIndicator.setProgress(0);
                System.out.println("cancelled.");
            }
        });
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public Task createWorker() {
        return new Task() {
            @Override
            protected Object call() throws Exception {
                for (int i = 0; i < 10; i++) {
                    Thread.sleep(100);
                    updateMessage("100 milliseconds");
                    updateProgress(i + 1, 10);
                }
                return true;
            }
        };
    }
}
ItachiUchiha
  • 36,135
  • 10
  • 122
  • 176
sancho
  • 598
  • 2
  • 8
  • 22
  • Can you add the code which you have tried, if possible please post a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve). – ItachiUchiha Nov 08 '15 at 09:51
  • You can clone the whole project https://github.com/shikimaru/XDMExamples.git – sancho Nov 08 '15 at 10:23
  • Why would I do that? If you need help, you must value the time and effort of people who are here to help you. – ItachiUchiha Nov 08 '15 at 11:14

2 Answers2

1

You need to change the text of the ProgressIndicator as well as set the width of the ProgressIndicator to the new width of the Text.

progressIndicator.progressProperty().addListener((ov, oldValue, newValue) -> {
     Text text = (Text) progressIndicator.lookup(".percentage");
     if(text!=null && text.getText().equals("Done")){
        text.setText("New Text");
        progressIndicator.setPrefWidth(text.getLayoutBounds().getWidth());
     }
});

enter image description here

Complete Code

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class Main extends Application {
    Task copyWorker;

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Background Processes");
        Group root = new Group();
        Scene scene = new Scene(root, 330, 120, Color.WHITE);

        BorderPane mainPane = new BorderPane();
        root.getChildren().add(mainPane);

        final Label label = new Label("Files Transfer:");
        final ProgressIndicator progressIndicator = new ProgressIndicator(0);

        final HBox hb = new HBox();
        hb.setSpacing(5);
        hb.setAlignment(Pos.CENTER);
        hb.getChildren().addAll(label, progressIndicator);
        mainPane.setTop(hb);

        final Button startButton = new Button("Start");
        final Button cancelButton = new Button("Cancel");
        final HBox hb2 = new HBox();
        hb2.setSpacing(5);
        hb2.setAlignment(Pos.CENTER);
        hb2.getChildren().addAll(startButton, cancelButton);
        mainPane.setBottom(hb2);

        startButton.setOnAction(event -> {
            startButton.setDisable(true);
            progressIndicator.setProgress(0);
            cancelButton.setDisable(false);
            copyWorker = createWorker();

            progressIndicator.progressProperty().unbind();
            progressIndicator.progressProperty().bind(copyWorker.progressProperty());

            new Thread(copyWorker).start();
        });

        cancelButton.setOnAction(event -> {
            startButton.setDisable(false);
            cancelButton.setDisable(true);
            copyWorker.cancel(true);
            progressIndicator.progressProperty().unbind();
            progressIndicator.setProgress(0);
        });

        primaryStage.setScene(scene);
        primaryStage.show();

        progressIndicator.progressProperty().addListener((observable, oldValue, newValue) -> {
            Text text = (Text) progressIndicator.lookup(".percentage");
            if (text != null && text.getText().equals("Done")) {
                text.setText("New Text");
                progressIndicator.setPrefWidth(text.getLayoutBounds().getWidth());
            }
        });
    }

    public Task createWorker() {
        return new Task() {
            @Override
            protected Object call() throws Exception {
                for (int i = 0; i < 10; i++) {
                    Thread.sleep(500);
                    updateMessage("2000 milliseconds");
                    updateProgress(i + 1, 10);
                }
                return true;
            }
        };
    }

    public static void main(String[] args) {
        Application.launch(args);
    }
}
ItachiUchiha
  • 36,135
  • 10
  • 122
  • 176
  • your solution works on this project. but when I use the same thing in my origin project it doesn't work. I don't know why. my java version is 1.8.60 – sancho Nov 08 '15 at 12:36
  • Well, I have tested this on JDK 1.8.0_60 and it works, so the issue is not with the version. There must be some issue with the implementation. – ItachiUchiha Nov 08 '15 at 12:38
  • ok thank you very much Itachi. sorry for take your time. have a nice day – sancho Nov 08 '15 at 12:41
  • Itachi is there any another way? I checked all implementation but the result the same text does not change :( – sancho Nov 09 '15 at 11:22
  • Can I do the same thing with fxml? – sancho Nov 09 '15 at 11:32
  • I am afraid its not possible through FXML. Since the text is updated dynamically, you need to trace it and update it. FMXLs are static view and cannot perform such operations. – ItachiUchiha Nov 09 '15 at 11:35
  • I don't understand what is the problem. output shows that text is changed but on the gui does not effect. – sancho Nov 09 '15 at 11:40
  • Did you resize the progress indicator according to the text size? If yes, can you try `text.applyCss(); ` just before setting the size. I would recommend to first try with smaller text, may be of 3 characters. – ItachiUchiha Nov 09 '15 at 11:49
  • You may want to reproduce your issue and post a new question. – ItachiUchiha Nov 09 '15 at 17:40
  • there are lots of question like this. and all solutions the same. I don't understand why some times works and sometimes not. is not perfect but may be solve my problem just hide text under progress indicator and use text – sancho Nov 09 '15 at 18:41
  • Yeah that is one more option :) – ItachiUchiha Nov 10 '15 at 04:12
0

It's posiible to change ProgressIndicator label (and all other default labels, like TextField context menu labels) by overwrite controls bundle file. In this file you have field:

ProgressIndicator.doneString=YourTextHere

How to overwrite ResourceBundle file you'll find here: https://stackoverflow.com/a/48773353/7746751

MTretowski
  • 23
  • 4