In messages apps, as you type a counter label on the corner gets updated showing the number of characters being entered. How do I create the same thing in Java?
Retrieve a IntegerBinding from the TextField's text property containing it's length and convert this to a StringBinding in a way that suits your needs. Bind the text property of the output Label to the result:
#Override
public void start(Stage primaryStage) {
TextField textField = new TextField();
Label label = new Label();
label.textProperty().bind(textField.textProperty()
.length()
.asString("Character Count: %d"));
VBox root = new VBox(label, textField);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
Related
I want to make a form with three sections, two with fields and one with buttons.
public class Form extends Application{
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
StackPane root = new StackPane();
GridPane fp = new GridPane();
fp.setAlignment(Pos.TOP_CENTER);
fp.setHgap(6);
fp.setVgap(6);
fp.add(new Label("Name: "), 0, 0);
TextField name = new TextField();
name.setPrefWidth(450);
fp.add(name, 1, 0);
GridPane sp = new GridPane();
sp.setAlignment(Pos.CENTER);
sp.setHgap(6);
sp.setVgap(6);
sp.add(new Label("Another Name: "), 1, 0);
TextField anothername = new TextField();
anothername.setPrefWidth(120);
sp.add(anothername, 2, 0);
HBox hbox = new HBox();
hbox.setAlignment(Pos.BOTTOM_CENTER);
Button btn1 = new Button("Button 1");
hbox.getChildren().add(btn1);
Scene scene = new Scene(root, 500, 500);
root.getChildren().addAll(fp, sp, hbox);
stage.setScene(scene);
stage.show();
}
}
formatting and some text might be off but that is my general solution. I made a root stack pane to hold all the parts of my form. I then made two grid panes to hold text fields and an hbox to hold my buttons along the bottom.
example of how it looks
My problem is that only the name field can be clicked. If I try to click another name field it wont work. I can press tab to cycle through the fields and button but I want to be able to click on each field individually. Is there a better way to create one scene with multiple panes or hboxes? I am also open to only having one grid pane, but I thought having two would be easier for formatting since I want to separate different fields. Thank you!
The issue you're facing is caused by your using a StackPane as the root element of your scene.
A StackPane, as the name suggests, stacks its children one on top of the other. Any children placed on top will be the ones receiving events (such as clicking on the anothername field).
You have added 3 nodes as children of your StackPane:
GridPane #1 fp
GridPane #2 sp
HBox hbox
Since the HBox was added last, it is the only node that can receive click events.
Using your example, I've added borders to each of the 3 items above to illustrate how JavaFX is laying them out:
As you can see, each child of the StackPane get resized to fill the entire area (I used different widths for the borders so you can see them all).
You can try this yourself by adding the following code before you show your stage:
fp.setStyle("-fx-border-color: green; -fx-border-width: 15px");
sp.setStyle("-fx-border-color: blue; -fx-border-width: 10px");
hbox.setStyle("-fx-border-color: red; -fx-border-width: 5px");
To solve this, you will need to rethink your layout entirely; a StackPane is certainly not the correct layout pane to use in your case.
I highly recommend working through the examples in Oracle's Working With Layouts in JavaFX tutorial to get a better grasp on how to best layout your scene.
As the titles suggests. I'm quite new to JavaFX so it's a bit confusing but I'm trying to set the max width of a TextField. I tried the maxWidth() method but it does not seem to work. This is the relevant code.
TextField field = new TextField("Enter");
field.maxWidth(300);
StackPane root = new StackPane();
root.getChildren().add(field);
Scene scene = new Scene(root, 500, 250);
primaryStage.setScene(scene);
primaryStage.show();
Try
field.setMaxWidth(300);
For more info refer this.
public void start(Stage stage) throws Exception {
FlowPane flowPane = new FlowPane();
flowPane.setOrientation(Orientation.VERTICAL);
for(int i = 0; i < 101;i++) {
Label aLabel = new Label("Label number: " + i);
flowPane.getChildren().add(aLabel);
}
Scene applicationScene = new Scene(flowPane);
stage.setHeight(400.0);
stage.setWidth(400.0);
stage.setScene(applicationScene);
stage.show();
}
I am trying to write the code so that all of the labels end up in the same column even though the labels will not be within the window (I plan on adding a scrollPane to make the labels still viewable issue). However, I have no clue as to why, since the labels automatically begin filling up the next column when the first one is filled (example here). How should I go about this?
I have no clue as to why since the labels automatically begin filling
up the next column when the first one is filled
That's the functionality of a FlowPane. From the documentation:
FlowPane lays out its children in a flow that wraps at the flowpane's
boundary. ... A vertical flowpane lays out nodes in columns, wrapping at the flowpane's height.
You should use a VBox instead:
public void start(Stage stage) throws Exception {
VBox vbox = new VBox();
for(int i = 0; i < 101;i++) {
Label aLabel = new Label("Label number: " + i);
vbox.getChildren().add(aLabel);
}
Scene applicationScene = new Scene(vbox);
stage.setHeight(400.0);
stage.setWidth(400.0);
stage.setScene(applicationScene);
stage.show();
}
If you have a lot of data to display, you might also consider using a ListView. The ListView has a more complex API (it manages selection, and can be editable if you choose), and provides its own scrollbars when needed, but it can be more efficient for large amounts of data (basically it only creates UI controls for the visible data, and reuses them as the user scrolls).
I am trying to print the numbers in the horizontal and then show in reverse order, now, in the following code below, the logic is correct and show the number on the console, imrpimi okay, as shown in the second link and show these same values in a label in JavaFX, shows the opposite of the desired solution
public class GridPane extends Application {
#Override
public void start(Stage primaryStage) {
GridPane root = new GridPane();
root.setPadding(new Insets(5));
root.setAlignment(Pos.CENTER);
for (int number = 8; number > 0; number--) {
StringBuilder str = new StringBuilder();
str.append(number);
Label label = new Label(str.toString());
System.out.println(str.toString());
label.setFont(Font.font("Arial", FontWeight.BOLD, 13));
label.setPrefSize(20, 20);
root.add(label,0, number + 3);
}
Scene scene = new Scene(root, 900, 900);
primaryStage.setTitle("Grid Pane Example");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
to test the program, I got is output http://i.imgur.com/Jeh0zWp.jpg
the goal is to follow this logic in which the console displays the result correctly like this http://i.imgur.com/jH9jAs1.jpg
Any suggestions, I appreciate and thanks.
The parameters to root.add(...) are the node you are adding, the column index, and the row index. So you are always adding the label displaying number in row number + 3: i.e. 8 goes in row 11, 7 goes in row 10, etc.
The order of iteration makes no difference.
If you want 1 in row 11, 2 in row 10, 3 in row 9, etc, then you would have to notice that rowIndex = 12 - number and call
root.add(label, 0, 12 - number);
When this class runs, the Text that is generated on the bottom (After the button is pressed) is pushing the other controls away from each other and compressing them. Is there any way that I can keep the Text but not have the controls above it compressed? NOTE: This class can be run by calling Application.launch(CSSTrial1.class); from outside the class.
public class CSSTrial1 extends Application {
#Override
public void start(Stage stage) throws Exception {
stage.setTitle("CSS Trial");
stage.setResizable(false);
final GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(25));
grid.add(new Label("Character Name:"), 0, 0);
final TextField nameField = new TextField("");
nameField.setPromptText("Randel James");
grid.add(nameField, 1, 0);
grid.add(new Label("Weapon:"), 0, 1);
final ComboBox<String> weapons = new ComboBox<>();
weapons.getItems().addAll("Katsuragi x2", "Assault Rifle",
"Pistol", "RPG-7", "Barret 50. Cal");
grid.add(weapons, 1, 1);
HBox box = new HBox(10);
box.setAlignment(Pos.BOTTOM_RIGHT);
Button submit = new Button("Submit Character");
submit.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
grid.add(new Text("Signed In As: " + nameField.getText()
+ ", Weapon: " + weapons.getValue()), 0, 6);
}
});
box.getChildren().add(submit);
grid.add(box, 1, 3);
Scene scene = new Scene(grid, 300, 275);
stage.setScene(scene);
stage.show();
}
}
Define a ColumnConstraints object, and use it in the grid pane:
ColumnConstraints firstColumn = new ColumnConstraints();
grid.getColumnConstraints().addAll(firstColumn);
You can set the min, pref, and max width on the column constraints to control how much that column is allowed to be resized (for example, setting all three to the same fixed value will force the column to be that size).
You might also want to set the wrapping width of your text, so that it takes up less space.
According to the Javadocs:
By default, rows and columns will be sized to fit their content; a column will be wide enough to accommodate the widest child, a row tall enough to fit the tallest child.
Since you are adding the nameField to the first column, when the length of that text expands, the whole columns expands in length, causing the "pushing of the controls away from each other." I would suggest either creating a new Pane, have the nameField span two columns, or using a different layout. You may even want to consider using FXML with the JavaFX Scene Builder.
Maybe try to insert the text with another column span such as in this altered code:
submit.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
grid.add(new Text("Signed In As: " + nameField.getText()
+ ", Weapon: " + weapons.getValue()), 0, 6,2,1);//colum span=2, but row span is1
}
});