How to bind TextField and ProgressBar in JavaFx - javafx

I'm trying to Use reactive bindings to bind the value of alcoholPercentageField to the progress property of alcoholBar.
The progress bar will "full" when alcoholic content is set to 20 % and empty when the alcoholic content is 0
My Code-
public void start(Stage stage) throws Exception {
stage.setTitle("Mead calculator");
// Creating the fields and components
TextField waterAmountField = new TextField();
TextField alcoholPercentageField = new TextField();
TextField sugarAmountField = new TextField();
Label meadTotalAmount = new Label();
Label assessmentLabel = new Label("");
//assessmentLabel.textProperty().bind(alcoholPercentageField.textProperty());
//Conditional Binding Error
assessmentLabel.textProperty().bind(Bindings.when((alcoholPercentageField.textProperty().lessThan(5))).then("Smart").otherwise("Bad"));
ProgressBar alcoholBar = new ProgressBar();
//Error is here
alcoholBar.progressProperty().bind(alcoholPercentageField.textProperty() * 5);
Rest of the Code: some visual things
GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(25, 25, 25, 25));
var columnOneConstraints = new ColumnConstraints(150, 150, Double.MAX_VALUE);
columnOneConstraints.setHalignment(HPos.RIGHT);
var columnTwoConstrains = new ColumnConstraints(200,200, Double.MAX_VALUE);
columnTwoConstrains.setHgrow(Priority.SOMETIMES);
grid.getColumnConstraints().addAll(columnOneConstraints, columnTwoConstrains);
alcoholBar.setMaxWidth(Double.MAX_VALUE);
GridPane.setColumnSpan(alcoholBar, 2);
GridPane.setHalignment(assessmentLabel, HPos.RIGHT);
sugarAmountField.setDisable(true);
grid.add(new Label("Water (l):"), 0, 0);
grid.add(waterAmountField, 1, 0);
grid.add(new Label("Vol-%:"), 0, 1);
grid.add(alcoholPercentageField, 1, 1);
grid.add(new Label("Sugar (kg):"), 0, 2);
grid.add(sugarAmountField, 1, 2);
grid.add(new Label("Lemons: "), 0, 3);
grid.add(new Label("To taste"), 1, 3);
grid.add(new Label("Mead total (kg):"), 0, 4);
grid.add(meadTotalAmount, 1, 4);
grid.add(alcoholBar, 0, 5);
grid.add(assessmentLabel, 1, 6);
// Okay, layout creation stops here
// And of course set the scene and show the stage as always
stage.setScene(new Scene(grid, 500, 400));
stage.show();
}
}

You need to create some additional Property and Binding objects.
First, create properties for your TextField alcoholPercentageField. Then, you'll bind them using a StringConverter to convert the text entered into doubles.
Finally, use bindBidirectional to propagate and lastly bind it with progressBar by dividing 20 ( The progress bar will be "full" when alcoholic content is set to 20 %)
Code Will be like this-
// Properties used for bindings
DoubleProperty alcoholPercent = new SimpleDoubleProperty();
//Setup the converters to get the input from the textfields
StringConverter<? extends Number> converter = new DoubleStringConverter();
Bindings.bindBidirectional(alcoholPercentageField.textProperty(), alcoholPercent, (StringConverter<Number>) converter);
alcoholBar.progressProperty().bind(alcoholPercent.divide(20));
For Conditional Binding, check this Conditional Binding
Code would be like this-
assessmentLabel.textProperty().bind(Bindings.when(alcoholPercent.lessThan(5)).then("Smart").otherwise("Bad"));
assessmentLabel.textFillProperty().bind(Bindings.when(alcoholPercent.lessThan(5)).then(Color.GREEN).otherwise(Color.RED));

Use the Bindings API.
Note that the progress is supposed to be between 0 and 1, so if you are entering percentages, instead of proportions, into your text field you need to divide by 100:
alcoholBar.progressProperty().bind(Bindings.createDoubleBinding(
() -> 0.05 * Double.parseDouble(alcoholPercentageField.getText()),
alcoholPercentageField.textProperty()
));
You might want to implement more complex logic to, e.g. check for a valid number, or at least non-empty text field.

Related

JAVAFX - How to make a textfield active on event action

GridPane layout = new GridPane();
Label wordInstruction = new Label("Word");
TextField wordField = new TextField();
Label translationInstruction = new Label("Translation");
TextField translationField = new TextField();
Label error = new Label();
layout.setVgap(10);
layout.setHgap(10);
layout.setPadding(new Insets(10, 10, 10, 10));
layout.setAlignment(Pos.CENTER);
Button addButton = new Button("Add");
// Stops the button from consuming mouse events and allows it to become the default button.
addButton.setSkin(new ButtonSkin(addButton) {
{
this.consumeMouseEvents(false);
}
});
// The button can now be pressed with the enter key.
addButton.setDefaultButton(true);
layout.add(wordInstruction, 0, 0);
layout.add(wordField, 0, 1);
layout.add(translationInstruction, 0, 2);
layout.add(translationField, 0, 3);
layout.add(addButton, 0, 4);
layout.add(error, 0, 6);
addButton.setOnAction((event) -> {
String word = wordField.getText();
String translation = translationField.getText();
if (!translationField.getText().isEmpty()) {
this.dictionary.add(word.toLowerCase(), translation.toLowerCase());
error.setText("");
wordField.clear();
} else {
error.setText("Please input a translation.");
}
translationField.clear();
});
return layout;
}
Hello, I've just started using JavaFX and I've not been able to find anything in the documentation related to my problem. When I press the addButton, I want the user to be able to write into the wordField textField straight away instead of having to click it or tab all the way to it. Is there any way to make the textField active in my addButton.setOnAction function?
Thank you in advance.
How about running the TextField.requestFocus() method?

Adding label into border, JavaFX

When I'm trying to add label into the gridpane as the second picture shows, it's not working. I have tried many things like adding CSS and it's still not working. Why are lines 113 and 114 not working?
(opcje.setStyle("-fx-background-color: #f4f4f4");)
Here is what I have:
Here is what I need:
My code:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
public class KCK_lab1_zad2 extends Application {
#SuppressWarnings("static-access")
public void start (Stage primaryStage) {
try {
primaryStage.setTitle("Narzedzie przetwarzania plikow");
BorderPane glownyBorderPane = new BorderPane();
Scene scene = new Scene(glownyBorderPane, 600, 200);
GridPane lewyGridPane = new GridPane();
GridPane prawyGridPane = new GridPane();
glownyBorderPane.setLeft(lewyGridPane);
glownyBorderPane.setRight(prawyGridPane);
glownyBorderPane.setMargin(lewyGridPane, new Insets(0, 15, 0, 0));
Label zrodlo = new Label("Źrodlo");
Label wynik = new Label("Wynik");
TextField text1 = new TextField();
TextField text2 = new TextField();
Button przegladaj1 = new Button("Przegladaj...");
Button przegladaj2 = new Button("Przegladaj...");
lewyGridPane.setVgap(15);
lewyGridPane.setHgap(0);
lewyGridPane.setPadding(new Insets(15));
lewyGridPane.setLayoutX(100);
lewyGridPane.setLayoutY(100);
lewyGridPane.setMinSize(100, 150);
text1.setPrefSize(100, 20);
text2.setPrefSize(100, 20);
przegladaj1.setPrefSize(100, 20);
przegladaj2.setPrefSize(100, 20);
glownyBorderPane.setPadding(new Insets(20, 10, 10, 10));
Label panelPlikow = new Label("Panel plików");
panelPlikow.getStyleClass().add("title");
panelPlikow.setPadding(new Insets(-60, -20, 0, 0));
panelPlikow.setPrefWidth(150);
lewyGridPane.add(panelPlikow, 0, 0);
lewyGridPane.add(zrodlo, 0, 0);
lewyGridPane.add(text1, 1, 0);
lewyGridPane.add(przegladaj1, 2, 0);
lewyGridPane.add(wynik, 0, 1);
lewyGridPane.add(text2, 1, 1);
lewyGridPane.add(przegladaj2, 2, 1);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//grd.prefHeightProperty().bind(root.heightProperty());
//glownyBorderPane.borderProperty();
lewyGridPane .setStyle("-fx-border-style: solid inside;");
lewyGridPane .setStyle("-fx-border-width: 1;");
lewyGridPane .setStyle("-fx-border-insets: 1;");
lewyGridPane .setStyle("-fx-border-radius: 1;");
lewyGridPane .setStyle("-fx-border-color: black;");
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Label opcje = new Label ("Opcje uruchomienia");
Button uruchom = new Button ("Uruchom przetwarza...");
Button pomoc = new Button ("Pomoc");
Button o_programie = new Button ("O programie");
Button zakoncz = new Button ("Zapisz i zakończ");
prawyGridPane.setVgap(0);
prawyGridPane.setHgap(0);
prawyGridPane.setPrefSize(150, 200);
prawyGridPane.setMaxWidth(150);
prawyGridPane.setPadding(new Insets(15));
prawyGridPane.setPrefSize(400, 300);
opcje.setPrefSize(150, 20);
uruchom.setPrefSize(150, 20);
o_programie.setPrefSize(150, 20);
zakoncz.setPrefSize(150, 20);
opcje.getStyleClass().add("title");
opcje.setPadding(new Insets(-34, -20, 0, 0));
VBox vbox = new VBox();
prawyGridPane.add(vbox, 0, 0);
opcje.setPrefWidth(150);
opcje.setStyle("-fx-background-color: #f4f4f4");
panelPlikow.setStyle("-fx-background-color: #f4f4f4");
vbox.getChildren().add(opcje);
vbox.getChildren().add(uruchom);
vbox.getChildren().add(pomoc);
vbox.getChildren().add(o_programie);
vbox.getChildren().add(zakoncz);
vbox.toBack();
//opcje.toFront();
uruchom.prefWidthProperty().bind(glownyBorderPane.widthProperty());
pomoc.prefWidthProperty().bind(glownyBorderPane.widthProperty());
o_programie.prefWidthProperty().bind(glownyBorderPane.widthProperty());
zakoncz.prefWidthProperty().bind(glownyBorderPane.widthProperty());
uruchom.prefHeightProperty().bind(glownyBorderPane.heightProperty());
pomoc.prefHeightProperty().bind(glownyBorderPane.heightProperty());
o_programie.prefHeightProperty().bind(glownyBorderPane.heightProperty());
zakoncz.prefHeightProperty().bind(glownyBorderPane.heightProperty());
/*
opcje .setStyle("-fx-font: 28px Vivaldi;");
opcje .setStyle("-fx-font-color: red;");
opcje .setStyle("-fx-background-color: white;");
opcje .setStyle("-fx-translate-y: -16;");
opcje .setStyle("-fx-content-display: top;");
opcje .setStyle("-fx-background-color: black;");
opcje.setTextFill(Color.RED);
opcje.setStyle("-fx-background-color: white");
*/
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//grd.prefHeightProperty().bind(root.heightProperty());
//glownyBorderPane.borderProperty();
prawyGridPane .setStyle("-fx-border-style: solid inside;");
prawyGridPane .setStyle("-fx-border-width: 1;");
prawyGridPane .setStyle("-fx-border-insets: 1;");
prawyGridPane .setStyle("-fx-border-radius: 1;");
prawyGridPane .setStyle("-fx-border-color: black;");
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
primaryStage.setScene(scene);
primaryStage.setMinHeight(250);
primaryStage.setMinWidth(580);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]){
launch(args);
}
}
The problem is the padding of the title-labels. To recognize this, set the background-colors of the title-labels, e.g. to green, set the padding to 0 and increase it step by step towards your value. If you do that, the text shifts up (what is desired), but the content (and thus the background) becomes smaller and finally disappears (what you did not intend). Overall, it does not work right with padding:
If you really want to keep your solution you can compensate for the problem by using the graphic-property of the label usually applied to add an icon to the label.
Replace
Label panelPlikow = new Label("Panel plików");
with
Label panelPlikow = new Label();
panelPlikow.setGraphic(new Label(" Panel plików "));
panelPlikow.getGraphic().setStyle("-fx-background-color: #f4f4f4;");
and analogously for the other button. That results in:
However, I don't know if it works in combination with your title-styleclass since you haven't post it. You have to try that.
I would like to point out that there are conceptually better ways to achieve what you want!
One possibility that comes close to your solution is, not to add the GridPane directly to the BorderPane, but a Pane, with the Pane containing the GridPane and the label. Here, the label can be positioned freely without a padding.
Another possibility is to use the Borders-control from ControlsFX (http://fxexperience.com/controlsfx/features/). It does exactly what you want, i.e. it surrounds an arbitrary control with a border and you can optionally define a title.
GridPane lewyGridPane = new GridPane();
Node leftWithBorder = Borders.wrap(lewyGridPane).lineBorder().title("Panel plików").color(Color.BLACK).buildAll();
GridPane prawyGridPane = new GridPane();
Node rightWithBorder = Borders.wrap(prawyGridPane).lineBorder().title("Opcje uruchomienia").color(Color.BLACK).buildAll();
glownyBorderPane.setLeft(leftWithBorder);
glownyBorderPane.setRight(rightWithBorder);
Of course, you have to remove the currently existing GridPane-borders and title-labels and you have to adapt margins, paddings, preferred sizes etc. Moreover you have to download and add the controlsfx-jar to the build path.
With the ControlsFX-Borders-control the GUI looks almost identical:

Unequal sized buttons JavaFX

When i create 2 buttons in gridpane using the following code, it gives me 2 unequal sized buttons. How can i fix this issue ?
/**
* Set the appearance of buttons in the grid
*/
private void setButtonAppearance(Button button)
{
button.setAlignment(Pos.CENTER);
//button.setFont(font);
button.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
button.setMinSize(Double.MIN_VALUE, Double.MIN_VALUE);
// doesn't start with focus or stay focused
button.setFocusTraversable(false);
}
/**
* Create buttons to perform allocation and deallocation of events to venues
*/
private void addButtons()
{
allocateButton = new Button("Allocate Event");
deallocateButton = new Button("Deallocate Event");
//Set appearance of buttons
setButtonAppearance(allocateButton);
setButtonAppearance(deallocateButton);
gridPane.add(allocateButton, 5, 30, 10, 1);
gridPane.add(deallocateButton, columns-15, 30, 10, 1);
}
OUTPUT:
Regards !
There are two possible solutions, either set a preferred width for the button
private void setButtonAppearance(Button button) {
button.setPrefWidth(60);
}
or set the columns which the buttons occur in to both have the same constraints. Something like this. Note, by default there aren't any ColumnConstraint objects in the the getColumnConstraints() array.
gridPane.getColumnConstraints()
.add(new ColumnConstraints(10, 100, Double.MAX_VALUE, Priority.ALWAYS, HPos.CENTER, true));
gridPane.getColumnConstraints()
.add(new ColumnConstraints(10, 100, Double.MAX_VALUE, Priority.ALWAYS, HPos.CENTER, true));
Self contained example
#Override
public void start(Stage primaryStage) throws Exception {
Button allocateButton = new Button("Allocate Event");
Button deallocateButton = new Button("Deallocate Event");
setButtonAppearance(allocateButton);
setButtonAppearance(deallocateButton);
GridPane gridPane = new GridPane();
gridPane.add(allocateButton, 0, 0, 1, 1);
gridPane.add(deallocateButton, 2, 0, 1, 1);
gridPane.getColumnConstraints()
.add(new ColumnConstraints(10, 100, Double.MAX_VALUE, Priority.ALWAYS, HPos.CENTER, true));
gridPane.getColumnConstraints()
.add(new ColumnConstraints(10, 100, Double.MAX_VALUE, Priority.ALWAYS, HPos.CENTER, true));
gridPane.getColumnConstraints()
.add(new ColumnConstraints(10, 100, Double.MAX_VALUE, Priority.ALWAYS, HPos.CENTER, true));
primaryStage.setScene(new Scene(gridPane));
primaryStage.show();
}
private void setButtonAppearance(Button button) {
button.setAlignment(Pos.CENTER);
// button.setFont(font);
button.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
button.setMinSize(Double.MIN_VALUE, Double.MIN_VALUE);
// doesn't start with focus or stay focused
button.setFocusTraversable(false);
}
Either way, I'd recommend against coding JavaFX layouts by hand, instead take advantage of Scene Builder and FXML...

Maximize JavaFX pane (HBox, for example)

I have to rewrite existing app, with SWT.
I'm adding FXCanvas class with JavaFX components on it.
I noticed that somehow my panes (usually, HBox'es) do not change size when I maximize window, for example.
My code is:
final Display display = parent.getDisplay();
shell = new Shell(display);
Group group = new Group();
scene = new Scene(group, Color.rgb(shell.getBackground().getRed(), shell.getBackground().getGreen(),
shell.getBackground().getBlue()));
fxCanvas = new FXCanvas(shell, SWT.NONE) {
#Override
public Point computeSize(int wHint, int hHint, boolean changed) {
getScene().getWindow().sizeToScene();
int width = (int) getScene().getWidth();
int height = (int) getScene().getHeight();
return new Point(width, height);
}
};
fxCanvas.setScene(scene);
HBox hbox = new HBox();
hbox.setPadding(new Insets(15, 12, 15, 12));
hbox.setSpacing(20); // Gap between nodes
group.getChildren().add(hbox);
Please advise.

JavaFX label contents not showing in gridpane

Why is myLabel content not showing in my gridpane, it is strange, everything else is showing..
I have tried everything I can. any help please
here are snippets of my code and attached photo of the result
#Override public void start(Stage stage) {
Group root = new Group();
Scene scene = new Scene(root, 1180, 650);
stage.setScene(scene);
stage.setTitle("Prayer Time Display");
scene.getStylesheets().addAll(this.getClass().getResource("style.css").toExternalForm());
GridPane Mainpane = new GridPane();
scene.setRoot(Mainpane);
Mainpane.setGridLinesVisible(true);
Mainpane.setId("Mainpane");
GridPane prayertime_pane = new GridPane();
prayertime_pane.setId("prayertime_pane");
prayertime_pane.setPadding(new Insets(20, 20, 20, 20));
prayertime_pane.setAlignment(Pos.BASELINE_CENTER);
prayertime_pane.setVgap(7);
prayertime_pane.setHgap(35);
GridPane moon_pane = new GridPane();
moon_pane.setGridLinesVisible(true);
moon_pane.setPadding(new Insets(10, 10, 10, 10));
moon_pane.setAlignment(Pos.BASELINE_CENTER);
moon_pane.setVgap(10);
moon_pane.setHgap(10);
myLabel.setText("hello");
moon_pane.setConstraints(myLabel, 0, 0);
moon_pane.getChildren().add(myLabel);
ImageView Moon_img = new ImageView(new Image(getClass().getResourceAsStream("/Images/Full_Moon.png")));
Moon_img.setFitWidth(100);
Moon_img.setFitHeight(100);
moon_pane.add(Moon_img, 1, 0);
Text next_moon_text = new Text("13/02");
next_moon_text.setId("prayer-text-english");
moon_pane.setHalignment(next_moon_text,HPos.LEFT);
moon_pane.setValignment(next_moon_text,VPos.CENTER);
moon_pane.setConstraints(next_moon_text, 2, 0);
moon_pane.getChildren().add(next_moon_text);
Mainpane.add(moon_pane, 8, 1,3,2);
Your label does appear on the scene but it has been shrinked to the extent that only the text overflow characters are rendered - "..."
To ensure that the label is always rendered with a fixed width that will fit all the text you can force the minumum and maximum widths to be the same as the preferred width:
myLabel.setMinWidth(Region.USE_PREF_SIZE);
myLabel.setMaxWidth(Region.USE_PREF_SIZE);
If you want to retain the dynamic sizing you can always use Scenic View (http://fxexperience.com/scenic-view/) to analyse your scene graph and determine which nodes or containers take up all the space or have size limits

Resources