I have the following example code:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class Test extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("JavaFX Test");
GridPane grid = new GridPane();
grid.add(new Text("Enter the value in the text box below:"), 0, 0, 3, 1);
grid.add(new Text("Label: "), 0, 1);
grid.add(new TextField(), 1, 1);
grid.add(new Text("units"), 2, 1);
Scene scene = new Scene(grid);
primaryStage.setScene(scene);
primaryStage.sizeToScene();
primaryStage.show();
}
}
Which results in the following window:
If I resize the window to the width I would expect it to be, the TextField is also resized:
My question is, where is that white space on the right of the window coming from? Why is the window size so much wider than the space taken up by the components? Why is the TextField resized when I make my window smaller, even though the window has plenty of room for it?
If I remove the top Text, the window size is more sane:
I've tried using VBox and HBox to achieve the effect I'm looking for, but the window always seems to look like the first image above. What's going on?
This looks like a known bug: RT24636. It is fixed in the latest release (Java 1.8.0_05).
No workaround is posted on the JIRA and none comes to mind immediately.
Related
I'm new to JavaFX, trying to build a GUI program that displays a bill for a table at a restaurant when you click on that table. The spacing is off between the table buttons and I'm not sure why.
The GUI class for my program:
package restaurantBillingProgram;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.scene.control.Label;
import javafx.scene.control.Button;
import javafx.geometry.Pos;
public class BillingGUI extends Application {
#Override
public void start(Stage primaryStage) {
// Create grid pane
GridPane pane = new GridPane();
pane.setAlignment(Pos.CENTER);
pane.setHgap(5);
pane.setVgap(5);
// Label
pane.add(new Label("Generate bill"), 1, 0);
// Buttons
Button btT1 = new Button("Table 1");
pane.add(btT1, 0, 1);
btT1.setOnAction(e - > Billing.generateT1());
Button btT2 = new Button("Table 2");
pane.add(btT2, 1, 1);
btT2.setOnAction(e - > Billing.generateT2());
Button btT3 = new Button("Table 3");
pane.add(btT3, 2, 1);
btT3.setOnAction(e - > Billing.generateT3());
// Create scene and place in stage
Scene scene = new Scene(pane, 250, 250);
primaryStage.setTitle("Restaurant Billing Program");
primaryStage.setScene(scene);
primaryStage.show();
}
// Main method
public static void main(String[] args) {
launch(args);
}
}
From the Javadoc:
Row/Column Sizing
By default, rows and columns will be sized to fit their content; a column will be wide enough to accommodate the widest child, ...
The label in row 0 column 1 forces that column to be wider.
You probably want the label to be centered and span all 3 columns.
While doing you layout, use pane.setGridLinesVisible(true). This should only be used during debugging. It can be very useful for situations like your current situation. As #Jim Garrison pointed out, your Label is causing the issue:
Issue:
One way to fix this is to let the Label span all columns and center the Label's text.
Fix:
Key Code:
label.setMaxWidth(Double.MAX_VALUE);
label.setAlignment(Pos.CENTER);
pane.add(label, 0, 0, 3, 1);// Look at the following link to see how this add method works. https://openjfx.io/javadoc/11/javafx.graphics/javafx/scene/layout/GridPane.html#add(javafx.scene.Node,int,int,int,int)
Full Code:
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.scene.control.Label;
import javafx.scene.control.Button;
import javafx.geometry.Pos;
public class BillingGUI extends Application {
#Override
public void start(Stage primaryStage) {
// Create grid pane
GridPane pane = new GridPane();
pane.setAlignment(Pos.CENTER);
pane.setHgap(5);
pane.setVgap(5);
pane.setGridLinesVisible(true);//Use for debugging only!!!!
// Label
Label label = new Label("Generate bill");
label.setMaxWidth(Double.MAX_VALUE);
label.setAlignment(Pos.CENTER);
pane.add(label, 0, 0, 3, 1);
// Buttons
Button btT1 = new Button("Table 1");
pane.add(btT1, 0, 1);
Button btT2 = new Button("Table 2");
pane.add(btT2, 1, 1);
Button btT3 = new Button("Table 3");
pane.add(btT3, 2, 1);
// Create scene and place in stage
Scene scene = new Scene(pane, 250, 250);
primaryStage.setTitle("Restaurant Billing Program");
primaryStage.setScene(scene);
primaryStage.show();
}
// Main method
public static void main(String[] args) {
launch(args);
}
}
EDIT: SOLVED, ACCIDENTALLY FLIPPED X AND Y VALUES FOR LABEL'S 1 & 2
I'm creating an overlay using JavaFX, but for some reason two of my labels are missing while one is perfectly fine. It's weird because they all have the same y-value (setLayoutY) and only one label is successfully shown. When changing label 1's y-value from 536 to 500, it then gets show, but cut out.
When label 1's setLayoutY(536): http://i.imgur.com/M5NxQoa.png
When label 2's setLayoutY(500): http://i.imgur.com/heJDopx.png
It's weird because it's well within both the pane and stages size (by the way, which one takes precedence). On the other hand, label 2 has the same y-value of 536 and is displayed, but the rest aren't.
I really hope this isn't a simple mistake as I'm not seeing what I'm doing wrong. Why is this happening and how can I fix it? Thank you!
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.scene.paint.Color;
public class Overlay extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
Pane root = new Pane();
root.setPrefSize(765,596);
Label label1 = new Label("why does");
label1.setLayoutX(97);
label1.setLayoutY(536);
label1.setPrefWidth(57);
label1.setPrefHeight(184);
label1.setTextFill(Color.BLACK);
Label label2 = new Label("this happen");
label2.setLayoutX(481);
label2.setLayoutY(536);
label2.setPrefWidth(184);
label2.setPrefHeight(57);
label2.setTextFill(Color.BLACK);
Label label3 = new Label("-1");
label3.setLayoutX(289);
label3.setLayoutY(536);
label3.setPrefWidth(57);
label3.setPrefHeight(184);
label3.setTextFill(Color.BLACK);
root.getChildren().addAll(label1, label2, label3);
Scene scene = new Scene(root, 765, 596, Color.TRANSPARENT);
scene.setFill(Color.TRANSPARENT);
primaryStage.setScene(scene);
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.setAlwaysOnTop(true);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Set same PrefHeight in all label
label1.setPrefHeight(57);
label2.setPrefHeight(57);
label3.setPrefHeight(57);
This above picture is result of my code.But I want like the following.
How can I fix it? The following is my code.I read too many sources but they was too complicated. For example,a source that I read, I think this way is very complicated.Maybe there is a easy way to solve this problem.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class Test extends Application {
public BorderPane border = new BorderPane();
public Label name = new Label("Name");
public Label surname = new Label("Surname");
public TextField name1 = new TextField();
public TextField surname1 = new TextField();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage arg0) throws Exception {
Scene scene = new Scene(new VBox(), 300, 200);
arg0.setTitle("Header");
arg0.setResizable(false);
scene.setFill(Color.OLDLACE);
StackPane grid = addStackPane();
border.setMargin(grid, new Insets(12,12,12,12));
border.setCenter(grid);
((VBox) scene.getRoot()).getChildren().add(border);
arg0.setScene(scene);
arg0.show();
}
#SuppressWarnings("static-access")
public StackPane addStackPane() {
StackPane pane = new StackPane();
GridPane grid = new GridPane();
Label title = new Label("Border Title");
title.setStyle("-fx-translate-y: -7");
pane.setAlignment(title, Pos.TOP_LEFT);
grid.setStyle("-fx-content-display: top");
grid.setStyle("-fx-border-insets: 20 15 15 15");
grid.setStyle("-fx-background-color: white");
grid.setStyle("-fx-border-color: black");
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(25, 10, 25, 10));
grid.add(name, 1, 0);
grid.add(name1, 2, 0);
grid.add(surname, 1, 1);
grid.add(surname1, 2, 1);
pane.getChildren().addAll(grid, title);
return pane;
}
}
Thank you all that reads this topic.
Try to set -fx-background-color of your title label to the same color as the borderPane's background. And make sure you set in a css file, because it's not possible to set multiple styles via setStyle() unless you concatenate them:
myComponent.setStyle("-fx-text-fill: white;"+
"-fx-background-color: black;");
Furthermore it is bad practice to use an InlineStyleSheets as it always has a higher priority than a rule specified in a CSS StyleSheet.
(If you change pane.setAlignment(title, Pos.TOP_LEFT) to StackPane.setAlignment(title, Pos.TOP_LEFT) you can remove the "static-acces" warning.)
User jewelsea has made a control to perform this.
The related stackoverflow question is: How to add border to panel of javafx?
And on gitHub: https://gist.github.com/jewelsea/2838292
I have used it with minimal modification and it works like a charm.
So, I've been working on a dynamical UI, which consists of TextAreas, but the thing is that the inputs to TextAreas come from the database and therefore are with different lengths. And I must also make the TextAreas dynamic depending on the length of the strings from database. And this is a difficult task because the length of the strings doesn't automatically tell its length in pixels.
So, for example strings:
a)"iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"
b)"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM"
Those two strings consist of 70 letters but their length in pixels is completely different.
And I need to make sure that the TextArea gets its width based on the string's length in pixels.
I have tried to use something like this:
int textwidth = (int) font.getStringBounds(ta.getText(), frc).getWidth();
But it gives me errors, because the font is the following:
textLabel.getFont()
-> Font[name=System Regular, family=System, style=Regular, size=12.0]
But using this font in the previous getStringBounds method it gives me errors:
Cannot resolve method 'getStringBounds(java.lang.String, java.awt.font.FontRenderContext)'
Any help would be highly appriciated. I can provide more information if required.
Thanks in advance!
You can measure the size of some text by creating a Text object, placing it in a pane (e.g. a StackPane) and calling layout() on the pane, then get the layout bounds of the text. Set the font to the same font as you want to use in the text area.
The only remaining issue is that the text area needs some padding for its border, etc, the following code example just uses a fixed padding (established via trial-and-error) but works well enough. You can probably improve on this if needed.
Type something in the text field and press enter; it will update the text and size of the text area:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class SizeTextAreaToString extends Application {
#Override
public void start(Stage primaryStage) {
TextField enterField = new TextField();
TextArea textArea = new TextArea();
textArea.setPrefRowCount(1);
enterField.setOnAction(e -> sizeTextAreaToText(textArea, enterField.getText()));
VBox root = new VBox(5, enterField, textArea);
VBox.setVgrow(textArea, Priority.NEVER);
root.setPadding(new Insets(5));
primaryStage.setScene(new Scene(root, 400, 400));
primaryStage.show();
}
private void sizeTextAreaToText(TextArea textArea, String text) {
Text t = new Text(text);
t.setFont(textArea.getFont());
StackPane pane = new StackPane(t);
pane.layout();
double width = t.getLayoutBounds().getWidth();
double padding = 20 ;
textArea.setMaxWidth(width+padding);
textArea.setText(text);
}
public static void main(String[] args) {
launch(args);
}
}
I hava 3 tabs in a TabPane that each one has a text area with different texts and different length.
I want to autosize text area according to it's length in each tab.
I don't understand what should I do ? using scene builder ? css ?javaFX methods ?
Thank's in Advance ...
I think you are asking that the text areas grow or shrink according to the text that is displayed in them?
If so, see if this code helps:
import java.util.concurrent.Callable;
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 AutosizingTextArea extends Application {
#Override
public void start(Stage primaryStage) {
TextArea textArea = new TextArea();
textArea.setMinHeight(24);
textArea.setWrapText(true);
VBox root = new VBox(textArea);
Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
// This code can only be executed after the window is shown:
// Perform a lookup for an element with a css class of "text"
// This will give the Node that actually renders the text inside the
// TextArea
Node text = textArea.lookup(".text");
// Bind the preferred height of the text area to the actual height of the text
// This will make the text area the height of the text, plus some padding
// of 20 pixels, as long as that height is between the text area's minHeight
// and maxHeight. The minHeight we set to 24 pixels, the max height will be
// the height of its parent (usually).
textArea.prefHeightProperty().bind(Bindings.createDoubleBinding(new Callable<Double>(){
#Override
public Double call() throws Exception {
return text.getBoundsInLocal().getHeight();
}
}, text.boundsInLocalProperty()).add(20));
}
public static void main(String[] args) {
launch(args);
}
}
If you want to make this reusable, then you could consider subclassing TextArea. (In general, I dislike subclassing control classes.) The tricky part here would be to execute the code that makes the TextArea expand once it has been added to a live scene graph (this is necessary for the lookup to work). One way to do this (which is a bit of a hack, imho) is to use an AnimationTimer to do the lookup, which you can stop once the lookup is successful. I mocked this up here.