I have been trying to remove the percentage text below the ProgressIndicator, but is unsuccessful. I have found several mentions of this and tried the accepted answer, but it does not work
Using Java 8 Update 121
package com.company.mytest;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class ProgressApp extends Application {
public static void main(String[] args) {
launch(args);
}
/* (non-Javadoc)
* #see javafx.application.Application#start(javafx.stage.Stage)
*/
#Override
public void start(Stage stage) throws Exception {
ProgressIndicator progress = new ProgressIndicator();
progress.setProgress(0.5f);
StackPane root = new StackPane();
root.getChildren().add(progress);
Scene scene = new Scene(root);
scene.getStylesheets()
.add(getClass().getResource("progress.css").toExternalForm());
stage.setScene(scene);
stage.setWidth(300);
stage.setHeight(300);
stage.setTitle("JavaFX 8 app");
stage.show();
}
}
I know the CSS is loaded, because I am able to change the percentage font size. This is the CSS content of the progress.css file.
.progress-indicator .percentage {
visibility: hidden;
}
Setting the -fx-fill attribute to null seems solving the problem:
.progress-indicator .percentage {
-fx-fill:null;
}
Update:
Setting only this attribute hides the percentage text, but still takes up the space.
A possible workaround is to set the -fx-padding attribute of the ProgressIndicator:
.progress-indicator .percentage {
-fx-fill:null;
}
.progress-indicator {
-fx-padding: 0 0 -16 0;
}
The only problem is the hardcoded value: if the CSS for .progress-indicator .percentage is changed (e.g. bigger font size) then this also has to be adapted.
Alternatively a programatic solution in this answer: How can I avoid the display of percentage values, when using the ProgressIndicator of JavaFX UI Controls
Related
I am having trouble changing the application icon with JavaFX (code is below with my attempts commented out). I tried implementing several solutions from previous stack overflow answers but I'm not sure if those methods are now deprecated. I am using NetBeans 8.2 (and the icon is in a folder called images under the source package).
1st Attempt: Illegal start of expression. identifier expected: JavaFX Application Icon
2nd Attempt: No suitable method found for add(java.awt.Image): Changing the icon of my java application
3rd Attempt: Cannot find symbol. Cannot instantiate the type Image java?
5th Attempt: Image is abstract it cannot be instantiated. http://docs.oracle.com/javafx/2/deployment/self-contained-packaging.htm
package javafxapplication1;
import java.awt.Image;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent;
import javax.imageio.ImageIO;
public class JavaFXApplication1 extends Application {
private double xOffset = 0;
private double yOffset = 0;
#Override
public void start(Stage stage) throws Exception {
//stage.getIcons().add(Image(<JavaFXApplication1>.class.getResourceAsStream( "/images/fiji.png" ));
Image i = ImageIO.read(getClass().getResource("/images/fiji.png"));
//setIconImage(i);
//stage.getIcons().add(i);
//stage.getIcons().add(Image("/images/fiji.png"));
// stage.getIcons().add(ImageIO.read(getClass().getResource("/images/fiji.png")));
//stage.getIcons().add(new Image(this.getClass().getResourceAsStream("/images/fiji.png")));
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
//stage.initStyle(StageStyle.UNDECORATED);
// makes it moveble
// LOOK INTO!!!!!!!!!!!
root.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
xOffset = event.getSceneX();
yOffset = event.getSceneY();
}
});
root.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
stage.setX(event.getScreenX() - xOffset);
stage.setY(event.getScreenY() - yOffset);
}
});
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
You need to load an Image and add it to the stage's icons.
import javafx.scene.image.Image;
Image icon = new Image(Controller.class.getResource("/game.png").toExternalForm(), false);
primaryStage.getIcons().add(icon);
However, on Ubuntu these icons do not get displayed. This JavaFX defect hasn't been solved for a long time.
It seems that your first attempt is missing the new keyword for the Image instantiation, and make sure it is a javafx.scene.image.Image, not a java.awt.Image image, which has a different constructor. Try this:
stage.getIcons().add(new Image(JavaFXApplication1.class.getResource( "/images/fiji.png" ).toExternalForm());
First, load an image and then add to the stage object. Please make sure to give path starting from the inside of the resource folder, not from the resource folder, or else use the whole project path.
Image favicon = new Image('URL_OF_THE_IMAGE');
stage.getIcons.add(favicon);
I have a ListView with some Labels in it. The labels' width property is bound to the width property of the ListView but they seem to be slightly larger meaning that a horizontal scrollbar is shown on the list view. What I want is to fit the labels in the list view without the scrollbar on the bottom. I have looked at various padding and insets values on both the label and the list view but none I have found are the culprit (most are zero).
Here is an example which demonstrates the problem.
import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.stage.Stage;
public class ListViewScrollExample extends Application {
private ListView<Node> listView;
#Override
public void start(Stage stage) throws Exception {
listView = new ListView<>();
addItem("Some quite long string to demonstrate the problem");
Scene scene = new Scene(listView);
stage.setScene(scene);
stage.show();
}
public void addItem(String item) {
Label label = new Label(item);
label.setWrapText(true);
label.maxWidthProperty().bind(listView.widthProperty());
listView.getItems().add(label);
}
public static void main(String[] args){
Application.launch(args);
}
}
The default CSS file adds padding to a ListCell (line 2316 in the current release):
.list-cell {
-fx-padding: 0.25em 0.583em 0.25em 0.583em; /* 3 7 3 7 */
}
It generally a bad idea to use Node instances as the data backing a ListView: you should use String in this example, and use the cell factory to create a label displaying the string that is configured as you need. The following seems to work for your example:
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.scene.Scene;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.stage.Stage;
public class ListViewScrollExample extends Application {
private ListView<String> listView;
#Override
public void start(Stage stage) throws Exception {
listView = new ListView<>();
listView.getItems().add("Some quite long string to demonstrate the problem");
listView.setCellFactory(lv -> {
ListCell<String> cell = new ListCell<String>() {
private Label label = new Label();
{
label.setWrapText(true);
label.maxWidthProperty().bind(Bindings.createDoubleBinding(
() -> getWidth() - getPadding().getLeft() - getPadding().getRight() - 1,
widthProperty(), paddingProperty()));
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
label.setText(item);
setGraphic(label);
}
}
};
return cell ;
});
Scene scene = new Scene(listView);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args){
Application.launch(args);
}
}
Here I created a list cell that displays a label as its graphic, with the text of the label set to the string to be displayed. The constructor for the cell binds the label's max width to the width of the cell, less any space required for padding. The call to setContentDisplay(ContentDisplay.GRAPHIC_ONLY) appears necessary, so the cell doesn't try to allocate any space for text.
It may be possible to do this by setting the text directly on the list cell and calling setWrapText(true) on the cell (which is, after all, also a subclass of Labeled), but I couldn't get it to work this way.
I couldn't replicate the problem but you can try the following instead of label.maxWidthProperty().bind(listView.widthProperty());
double i = Double.parseDouble(listView.widthProperty().toString());
label.setMaxWidth((i-2.0));
You can change the 2.0 to any pixel count you need to alter the screen by.
I have Scene which is set to the Scene of my primaryStage that - amongst other nodes - contains a VBox with a TableView and some buttons. When I take a snapshot on a row in the table using TableRow.snapshot(null, null), the size of the Scene is changed. The width is changed by about 10 pixels while the height is changed by about 40 - sometimes more than 600 (!) - pixels.
This happens because Node.snapshot(null, null) invokes Scene.doCSSLayoutSyncForSnapshot(Node node) which seems to get the preferred size of all nodes in the size and recalculate the size using that. This somehow returns the wrong values since my nodes only has preferred sizes specified and looks great before this method is invoked. Is there any way to prevent this?
The size change is a problem, but it is also a problem that the primary stage doesn't change size with the Scene that it contains.
I have tried to create an MCVE reproducing the issue, but after a few days of trying to do this, I am still unable to reproduce the problem. The original program contains around 2000 lines of code that I don't want to post here.
Why would Scene.doCSSLayoutSyncForSnapshot(Node node) compromise my layout when it is properly laid out in the first place? Can I somehow make sure that the layout is properly synced before this method is invoked to make sure that it doesn't change anything?
Solved the issue. Had to copy my whole project and then remove parts of the code until the issue disappeared.
Anyway. I basically had three components in my application. A navigation component, a table compontent, and a status bar compontent. It looked like this:
The problem I had was that the width of the status bar and the width and height of the table component was increased whenever I took a snapshot of a row in the table.
Apparently, this was due to the padding of the status bar compontent. It had a right and left padding of 5 pixels, and once I removed the padding, the problem disappeared.
The added 10 pixels in width made the BorderPane that contained all of this expand with the same amount of pixels, and since the table width was bound to the BorderPane width, it increased by the same amount. What I still don't understand though, is why the Stage that contains the BorderPane doesn't adjust to the new width.
The component was properly padded before Scene.doCSSLayoutSyncForSnapshot(Node node) was invoked, so I don't understand why the extra width of ten pixels is added.
Anyhow: Removing the padding from the status bar component and instead padding the components inside the status bar fixed the issue. If someone has a good explanation for this, I'm all ears.
Here's a MCVE where you can reproduce the issue by dragging a row in the table:
import java.io.File;
import java.sql.SQLException;
import java.util.ArrayList;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class MCVE extends Application {
private Stage primaryStage;
private BorderPane rootLayout;
private VBox detailsView;
private StatusBar statusBar;
public void start(Stage primaryStage) throws SQLException {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("MCVE");
initRootLayout();
showStatusBar();
showDetailsView();
detailsView.prefWidthProperty().bind(rootLayout.widthProperty());
detailsView.prefHeightProperty().bind(rootLayout.heightProperty());
}
#Override
public void init() throws Exception {
super.init();
}
public void initRootLayout() {
rootLayout = new BorderPane();
primaryStage.setWidth(1000);
primaryStage.setHeight(600);
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
}
public void showStatusBar() {
statusBar = new StatusBar();
rootLayout.setBottom(statusBar);
}
public void showDetailsView() {
detailsView = new VBox();
rootLayout.setCenter(detailsView);
setDetailsView(new Table(this));
detailsView.prefHeightProperty().bind(primaryStage.heightProperty());
detailsView.setMaxHeight(Region.USE_PREF_SIZE);
}
public static void main(String[] args) {
launch(args);
}
public VBox getDetailsView() {
return detailsView;
}
public void setDetailsView(Node content) {
detailsView.getChildren().add(0, content);
}
public StatusBar getStatusBar() {
return statusBar;
}
class StatusBar extends HBox {
public StatusBar() {
setPadding(new Insets(0, 5, 0, 5));
HBox leftBox = new HBox(10);
getChildren().addAll(leftBox);
/**
* CONTROL SIZES
*/
setPrefHeight(28);
setMinHeight(28);
setMaxHeight(28);
// Leftbox takes all the space not occupied by the helpbox.
leftBox.prefWidthProperty().bind(widthProperty());
setStyle("-fx-border-color: black;");
}
}
class Table extends TableView<ObservableList<String>> {
private ObservableList<ObservableList<String>> data;
public Table(MCVE app) {
prefWidthProperty().bind(app.getDetailsView().widthProperty());
prefHeightProperty()
.bind(app.getDetailsView().heightProperty());
widthProperty().addListener((obs, oldValue, newValue) -> {
System.out.println("Table width: " + newValue);
});
setRowFactory(r -> {
TableRow<ObservableList<String>> row = new TableRow<ObservableList<String>>();
row.setOnDragDetected(e -> {
Dragboard db = row.startDragAndDrop(TransferMode.ANY);
db.setDragView(row.snapshot(null, null));
ArrayList<File> files = new ArrayList<File>();
// We create a clipboard and put all of the files that
// was selected into the clipboard.
ClipboardContent filesToCopyClipboard = new ClipboardContent();
filesToCopyClipboard.putFiles(files);
db.setContent(filesToCopyClipboard);
});
row.setOnDragDone(e -> {
e.consume();
});
return row;
});
ObservableList<String> columnNames = FXCollections.observableArrayList("Col1", "col2", "Col3", "Col4");
data = FXCollections.observableArrayList();
for (int i = 0; i < columnNames.size(); i++) {
final int colIndex = i;
TableColumn<ObservableList<String>, String> column = new TableColumn<ObservableList<String>, String>(
columnNames.get(i));
column.setCellValueFactory((param) -> new SimpleStringProperty(param.getValue().get(colIndex).toString()));
getColumns().add(column);
}
// Adds all of the data from the rows the data list.
for (int i = 0; i < 100; i++) {
// Each column from the row is a String in the list.
ObservableList<String> row = FXCollections.observableArrayList();
row.add("Column 1");
row.add("Column 2");
row.add("Column 3");
row.add("Column 4");
// Adds the row to data.
data.add(row);
}
// Adds all of the rows in data to the table.
setItems(data);
}
}
}
This answer talks about it a little bit
Set scene width and height
but after diving into the source code I found that the resizing in snapshot is conditional on the scene never having a size set by one of its constructors.
You can only set a scene's size in its constructors and never again. That makes a little bit of sense, since its otherwise only used to size the window that contains it. It is unfortunate that the snapshot code is not smart enough to use the window's dimensions when set by the user in addition to the scene's possible user settings.
None of this prevents resizing later, so if you depend on taking snapshots, you may want to make a best practice out of using the Scene constructors which take a width and height and sending them something above 0
at the moment i'm working with a Progress-Indicator and a bunch of spinners.
I want to give them different styles in one CSS-File. My Problem is, that the Progress-Indicator always uses the style of I planned for the spinners.
I did an little application as example:
package application;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Pane root = new Pane();
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
ProgressIndicator value = new ProgressIndicator(-1.0);
value.getStyleClass().forEach(clazz -> System.out.println(clazz));
value.setPrefHeight(100);
value.setPrefWidth(100.0);
root.getChildren().add(value);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
I want to have my Progress-Indicator a red background and trying it todo like this:
.progress-indicator > .indicator {
-fx-background-color: red;
}
but without styling the spinner it won't work. so i append this:
.spinner {
-fx-background-color: red;
}
The problem is, that all my spinners now got red backgrounds. I could do it by using diffenrent CSS-Files. But It would be way better if I only need one CSS-File.
Thanks in advance for your time and help!
You faced this bug in modena.css which is fixed in 8u40. Now you can safely change the background color of progress indicator with:
.progress-indicator:indeterminate > .spinner {
/** Applying to undo styling from .spinner, reported in RT-37965 */
-fx-background-color: red;
/* originally was */
/*-fx-background-color: transparent;*/
-fx-background-insets: 0;
-fx-background-radius: 0;
}
I think you can create styles for each individual class?
Can't you add a custom style class for each spinner and apply that using spinner.getStyleClass().add("my-style")?
This will allow you to define may classes at a more specified level than just at the object level.
In JavaFX 2.2, is there any way to make TextArea (with setWrapText(true) and constant maxWidth) change its height depending on contents?
The desired behaviour: while user is typing something inside the TextArea it resizes when another line is needed and decreases when the line is needed no more.
Or is there a better JavaFX control that could be used in this situation?
You can bind the prefHeight of the text area to the height of the text it contains. This is a bit of a hack, because you need a lookup to get the text contained in the text area, but it seems to work. You need to ensure that you lookup the text node after CSS has been applied. (Typically this means after it has appeared on the screen...)
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ResizingTextArea extends Application {
#Override
public void start(Stage primaryStage) {
TextArea textArea = new TextArea();
textArea.setWrapText(true);
textArea.sceneProperty().addListener(new ChangeListener<Scene>() {
#Override
public void changed(ObservableValue<? extends Scene> obs, Scene oldScene, Scene newScene) {
if (newScene != null) {
textArea.applyCSS();
Node text = textArea.lookup(".text");
textArea.prefHeightProperty().bind(Bindings.createDoubleBinding(new Callable<Double>() {
#Override
public Double call() {
return 2+text.getBoundsInLocal().getHeight();
}
}), text.boundsInLocalProperty()));
}
}
});
VBox root = new VBox(textArea);
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Two things to add to James_D's answer (because I lack the rep to comment):
1) For big fonts like size 36+, the text area size was wrong at first but corrected itself when I clicked inside the text area. You can call textArea.layout() after applying CSS, but the text area still does not resize immediately after the window is maximized. To get around this, call textArea.requestLayout() asynchronously in a Change Listener after any change to the Text object's local bounds. See below.
2) The text area was still a few pixels short and the scroll bar still visible. If you replace the 2 with textArea.getFont().getSize() in the binding, the height fits perfectly to the text, no matter whether the font size is tiny or huge.
class CustomTextArea extends TextArea {
CustomTextArea() {
setWrapText(true);
setFont(Font.font("Arial Black", 72));
sceneProperty().addListener((observableNewScene, oldScene, newScene) -> {
if (newScene != null) {
applyCss();
Node text = lookup(".text");
// 2)
prefHeightProperty().bind(Bindings.createDoubleBinding(() -> {
return getFont().getSize() + text.getBoundsInLocal().getHeight();
}, text.boundsInLocalProperty()));
// 1)
text.boundsInLocalProperty().addListener((observableBoundsAfter, boundsBefore, boundsAfter) -> {
Platform.runLater(() -> requestLayout());
});
}
});
}
}
(The above compiles for Java 8. For Java 7, replace the listener lambdas with Change Listeners according to the JavaFX API, and replace the empty ()-> lambdas with Runnable.)