ProgressIndicator spends a lot of CPU in indeterminate mode (JavaFX) - javafx

My node shows the device that is connected to my PC. While it is not connected the progressIndicator in indeterminate mode (progress=-1) is shown (and message 'device is not turned on'). But I have problem with CPU usage - while progressIndicator is indeterminated the CPU usage is very hight (near 20%). When I turn on device the progressIndicator is hidden and the CPU usage becomes 1% or 2%.
Even in this example with one progressIndicator in indeterminate mode I have CPU usage near 12%:
import javafx.application.Application;
import javafx.scene.CacheHint;
import javafx.scene.Scene;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class Del extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Scene scene = new Scene(getTestGridPane());
primaryStage.setTitle("Welcome to JavaFX!");
primaryStage.setScene(scene);
primaryStage.sizeToScene();
primaryStage.show();
}
public GridPane getTestGridPane() {
GridPane gridPane = new GridPane();
ProgressIndicator mp = new ProgressIndicator();
mp.setCache(true);
mp.setCacheHint(CacheHint.SPEED);
mp.setCacheShape(true);
gridPane.add(mp, 0, 0);
return gridPane;
}
}
How can I use the progressIndicator in indceterminate state for a long time?

Related

JavaFX scene does not resize to fill stage if stage has minWidth/minHeight set

I need to set a minimum width and minimum height on a given window.
I've found that if I do so then the Scene does not fill the parent when the window is first shown. If you manually stretch the window it repaints correctly.
This only appears to occur when minWidth = width AND minHeight = height. It all other cases it is resized as expected (say for example minWidth = width -1).
Additionally this only appears to occur on Linux, specifically Red Hat 6, and only on Java 8.
I can't find any existing bug report for this behavior.
I'm looking for a workaround to this problem. This is a legacy project and unfortunately updating Java is not possible.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class SceneDoesntFillStage extends Application {
public static void main(String\[\] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setMinWidth(300);
primaryStage.setWidth(300);
primaryStage.setMinHeight(200);
primaryStage.setHeight(200);
HBox root = new HBox() {
protected void layoutChildren() {
super.layoutChildren();
System.out.println("Layout");
}
};
root.setStyle("-fx-background-color:red");
root.setPrefWidth(250);
root.setPrefHeight(150);
primaryStage.setScene(new Scene(root));
primaryStage.show();
System.out.println(primaryStage.getScene().getWidth() + " x " + primaryStage.getScene().getHeight());
}
}

Strange behaviour when resizing a Stage with the sizeToScene method in javafx

I have a problem with resizing a Stage with the sizeToScene method in javafx.
If I change the root node size above the maximum screen size and call sizeToScene, the window resizes well to the maximum possible screen size.
But if I recall sizeToScene, the scene becomes larger than the stage and the application is cut off.
Sometimes, the first call leads to the same behaviour as the last one described.
I don't know if it is a normal behavior and if there is a workaround solution to adjust the size of the scene to the size of the stage.
The same thing happened on linux and windows.
An example below
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
public class SceneSizeBug extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Button button = new Button("test");
button.setOnAction(e -> {
button.setPrefSize(2000, 2000);
primaryStage.sizeToScene();
});
button.setPrefSize(1280, 1024);
Scene s = new Scene(button, -1, -1);
primaryStage.setScene(s);
primaryStage.show();
}
}

How can I remove my javafx program from the taskbar

I need remove my javafx app from the taskbar. I tried StageStyle.UTILITY. This is works but I need both UNDECORATED and UTILITY stage styles or another solvings.
Thank you for your replies.
Sorry you've been waiting so long for some sort of an answer on this, the following is mainly for people who come to this in the future hoping to discover a way of achieving this.
Let me start of by saying I wouldn't consider the following a solution but more of a workaround.
Assigning more than one initStyle to a stage is not possible however hiding the application from the task-bar and assigning an initStyle other than utility to the stage that is shown is.
To achieve this one must create two stages, the stage they want the user to see, and an another stage that will be considered the parent of the main stage and will be of initStyle.UTILITY this will prevent the icon from showing in the task-bar.
Below you can see the hello world example from oracles documentation modified to allow for an undecorated window with no icon (Note if one wanted to achieve a transparent/decorated window they could do so by changing the style of mainStage).
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.StackPane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class MultipleStageStyles extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.initStyle(StageStyle.UTILITY);
primaryStage.setOpacity(0);
primaryStage.setHeight(0);
primaryStage.setWidth(0);
primaryStage.show();
Stage mainStage = new Stage();
mainStage.initOwner(primaryStage);
mainStage.initStyle(StageStyle.UNDECORATED);
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
mainStage.setScene(new Scene(root, 300, 250));
mainStage.show();
}
}

Make JavaFX wait and continue with code

Basically I am trying to make a short effect using JavaFX. I have the shape of a heart (added together from two circles and a polygon) that I can vary in size using the double value p. "Standart Size" would be p = 1.0;.
I am trying to add a pumping effect to the heart. I have the method pumpOnce():
public void pumpOnce(){
p = p + 1;
initHeart();
//Here goes what ever it takes to make stuff working!!
p = p - 1;
initHeart();
}
initHeart() draws the heart based on p.
I have found out that Thread.sleep(); or similar methods will not work due to the thread philosophy in JavaFX.
But what can I use instead?
The JavaFX animations are probably the way to go, but the "thread philosophy" in JavaFX isn't hard to work with if you want to roll your own, or do other, more complicated things in background threads.
The following code will pause and change the value in a label (full disclosure, I'm reusing code I wrote for another question):
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javax.xml.datatype.Duration;
public class DelayWithTask extends Application {
private static Label label;
public static void main(String[] args) { launch(args); }
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
label = new Label();
label.setText("Waiting...");
StackPane root = new StackPane();
root.getChildren().add(label);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
delay(5000, () -> label.setText("Hello World"));
}
public static void delay(long millis, Runnable continuation) {
Task<Void> sleeper = new Task<Void>() {
#Override
protected Void call() throws Exception {
try { Thread.sleep(millis); }
catch (InterruptedException e) { }
return null;
}
};
sleeper.setOnSucceeded(event -> continuation.run());
new Thread(sleeper).start();
}
}
The basic JavaFX background tool is the Task, any JavaFX application that actually does anything will probably be littered with these all over. Learn how to use them.
Dave's solution is great for general purpose off thread based work in JavaFX.
If you wish to use the animation facilities of JavaFX, the solutions below demonstrate this using a Timeline or a ScaleTransition. The timeline implements a discrete scale of the UI element, so every quarter of a second the UI element is scaled larger or back to it's original size. The scale transition implements a smooth scale of the UI element, so the UI element gradually gets larger then smaller using an interpolated scale factor with the default easing interpolator.
import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class BeatingHeart extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(Stage stage) {
ImageView heart = new ImageView(HEART_IMAGE_LOC);
animateUsingTimeline(heart);
// animateUsingScaleTransition(heart);
StackPane layout = new StackPane(heart);
layout.setPrefWidth(heart.getImage().getWidth() * 2);
layout.setPrefHeight(heart.getImage().getHeight() * 2);
Scene scene = new Scene(layout);
stage.setScene(scene);
stage.show();
}
private void animateUsingTimeline(ImageView heart) {
DoubleProperty scale = new SimpleDoubleProperty(1);
heart.scaleXProperty().bind(scale);
heart.scaleYProperty().bind(scale);
Timeline beat = new Timeline(
new KeyFrame(Duration.ZERO, event -> scale.setValue(1)),
new KeyFrame(Duration.seconds(0.5), event -> scale.setValue(1.1))
);
beat.setAutoReverse(true);
beat.setCycleCount(Timeline.INDEFINITE);
beat.play();
}
private void animateUsingScaleTransition(ImageView heart) {
ScaleTransition scaleTransition = new ScaleTransition(
Duration.seconds(1), heart
);
scaleTransition.setFromX(1);
scaleTransition.setFromY(1);
scaleTransition.setFromZ(1);
scaleTransition.setToX(1.1);
scaleTransition.setToY(1.1);
scaleTransition.setToZ(1.1);
scaleTransition.setAutoReverse(true);
scaleTransition.setCycleCount(Animation.INDEFINITE);
scaleTransition.play();
}
private static final String HEART_IMAGE_LOC =
"http://icons.iconarchive.com/icons/mirella-gabriele/valentine/128/Heart-red-icon.png";
// icon obtained from: http://www.iconarchive.com/show/valentine-icons-by-mirella-gabriele/Heart-red-icon.html
// icon license: Free for non-commercial use, commercial use not allowed.
}

TextArea setScrollTop

I created this simple example of TextArea
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class MainApp extends Application
{
#Override
public void start(Stage stage) throws Exception
{
HBox hbox = new HBox();
// Text Area
TextArea dataPane = new TextArea();
dataPane.setScrollTop(0);
dataPane.setEditable(false);
dataPane.prefWidthProperty().bind(hbox.widthProperty());
dataPane.setWrapText(true); // New line of the text exceeds the text area
dataPane.setPrefRowCount(10);
dataPane.appendText("Computer software, or simply software, also known as computer programs");
dataPane.appendText("\nis the non-tangible component of computers.");
dataPane.appendText("\nComputer software contrasts with computer hardware, which");
dataPane.appendText("\nis the physical component of computers.");
dataPane.appendText("Computer hardware and software require each");
dataPane.appendText("\nother and neither can be");
dataPane.appendText("\nrealistically used without the other.");
dataPane.appendText("\nComputer software");
hbox.setAlignment(Pos.CENTER);
hbox.setSpacing(1);
hbox.setPadding(new Insets(10, 0, 10, 0));
hbox.getChildren().add(dataPane);
Scene scene = new Scene(hbox, 800, 90);
stage.setTitle("JavaFX and Maven");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
I want to set by default the the position of the slider to be at the top of the TextArea.
Can you help me to fix this?
If you set dataPane.setScrollTop(0); after your stage is shown, it will work :)
So like this:
#Override
public void start(Stage stage) {
HBox hbox = new HBox();
// Text Area
TextArea dataPane = new TextArea();
dataPane.setEditable(false);
dataPane.prefWidthProperty().bind(hbox.widthProperty());
dataPane.setWrapText(true); // New line of the text exceeds the text area
dataPane.setPrefRowCount(10);
dataPane.appendText("Computer software, or simply software, also known as computer programs");
dataPane.appendText("\nis the non-tangible component of computers.");
dataPane.appendText("\nComputer software contrasts with computer hardware, which");
dataPane.appendText("\nis the physical component of computers.");
dataPane.appendText("Computer hardware and software require each");
dataPane.appendText("\nother and neither can be");
dataPane.appendText("\nrealistically used without the other.");
dataPane.appendText("\nComputer software");
hbox.setAlignment(Pos.CENTER);
hbox.setSpacing(1);
hbox.setPadding(new Insets(10, 0, 10, 0));
hbox.getChildren().add(dataPane);
Scene scene = new Scene(hbox, 800, 90);
stage.setTitle("JavaFX and Maven");
stage.setScene(scene);
stage.show();
dataPane.setScrollTop(0.0);
}

Resources