Is there any way to get the current size of a TableView column? I've haven't even been able to find the question online which makes me think I've missed something since I can't be the first one to need this functionality.
If that isn't possible, is there any way to set the size of a TableView column? That would also solve my issue although I'd prefer getting the size. setFixedCellSize(double) looked promising, but I couldn't get it to work.
I want to have a TextField above each column in my TableView with the same size as the column it's above. If there's a better way to accomplish that, I'm open to suggestions.
You can use Property-Bindings. But the width-Property of a TableColumn or TextField is read-only. This is correct, since the width and height is part of the layout process in rendering the whole window.
So you need to set the three sizes, min - pref - max width, for the TextField with the currently width from the TableColumn. It seems to me the prefered way to take the TableColumns width as the master for the TextFields width.
Now, even on manually resizing, your TextField stays the same width as the "bound" TableColumns width.
A little Minimal, Complete, and Verifiable example is below:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TableTest extends Application {
#Override
public void start(Stage primaryStage) {
TextField field = new TextField();
TableView<String> table = new TableView<>();
TableColumn<String, String> column = new TableColumn("Header Text");
table.getColumns().add(column);
field.prefWidthProperty().bind(column.widthProperty());
field.minWidthProperty().bind(column.widthProperty());
field.maxWidthProperty().bind(column.widthProperty());
VBox root = new VBox();
root.getChildren().addAll(field, table);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Related
I have this view designed via Scene Builder for JavaFX. There are 4 ComboBox in it. I would like to have the possibility to have something to let the user choose how many and which ComboBox use.
For example, my aim is having 3 modes:
allow the user to use all the 4 ComboBox;
allow the user to use only one ComboBox and let him choose it;
allow the user to use only two ComboBox and let them choose the preferred combination of the four Controls
Any design or idea (and its implementation) are well welcomed since I am not having a very good solution at this moment. I was thinking something like using the CheckBox element near to every ComboBox to enable or disable them, but anyway it is not very good. Also I was thinking about putting 3 Buttons to select the 3 modes and dynamically populate my Container, but I do not know where to start with the implementation.
If you want to let the user select a specific ComboBox, you can enable it using the JavaFX function setDisable() that is on all classes that inherit from the Node class.
(See difference between: setDisabled() vs setDisable())
In the case below, I bind the disabledProperty() to the inverse selectedProperty() on each CheckBox. This way you can select specific ComboBoxes to choose from. Hopefully this will get you started on seeing how JavaFX bindings work.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Test extends Application
{
public static void main(String[] args){
launch(args);
}
#Override
public void start (Stage primaryStage) throws Exception {
VBox vBox = new VBox();
HBox hBox1 = generateComboBoxHBox();
HBox hBox2 = generateComboBoxHBox();
HBox hBox3 = generateComboBoxHBox();
HBox hBox4 = generateComboBoxHBox();
vBox.getChildren().addAll(hBox1, hBox2, hBox3, hBox4);
primaryStage.setScene(new Scene(vBox));
primaryStage.show();
}
// Create 4 of the same HBoxes for an example. Each HBox has a checkbox and combobox
private HBox generateComboBoxHBox(){
HBox hBox = new HBox();
CheckBox checkBox = new CheckBox();
ComboBox<String> comboBox = new ComboBox<>(FXCollections.observableArrayList("Option1", "Option2", "Option3", "Option4"));
comboBox.disableProperty().bind(checkBox.selectedProperty().not());
hBox.getChildren().addAll(checkBox, comboBox);
return hBox;
}
}
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);
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);
}
}
In my application I have a BorderPane which contains a ScrollPane in the center. The ScrollPane has two logical sections top and bottom.
When I create a stage to show the BorderPane I want the stage to be sized so that only the top section of ScrollPane is shown and the user can scroll down to see the bottom section if they need it.
So I try to bind the prefHeight property of the ScrollPane to the prefHeight property of the top section. Hoping that the ScrollPane will get the right height and the stage will look "Just Rightâ„¢". For some reason this fails miserably. But when I attach a listener to the prefHeight property it does indeed return the correct height. So I'm flabbergasted as to what is going on.
Interestingly, if I remove the BorderPane it works in the SSCCE but this is not an option in the real case.
EDIT: SSCCE updated
Here is a SSCCE:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class SSCCE extends Application {
#Override
public void start(Stage aStage) throws Exception {
VBox top = new VBox(new ComboBox<>(), new ComboBox<>(), new ComboBox<>());
top.setStyle("-fx-background-color: pink");
top.heightProperty().addListener((aObs, aOld, aNew)->{
System.out.println(aNew.doubleValue());
});
Region regionBottom = new Region();
regionBottom.setPrefHeight(100);
regionBottom.setPrefWidth(200);
regionBottom.setStyle("-fx-background-color: red");
VBox content = new VBox(top, regionBottom);
ScrollPane scrollPane = new ScrollPane(content);
scrollPane.setFitToWidth(true);
scrollPane.prefHeightProperty().bind(top.prefHeightProperty());
BorderPane root = new BorderPane(scrollPane);
root.setTop(new MenuBar(new Menu("Foo")));
Scene scene = new Scene(root);
aStage.setScene(scene);
aStage.sizeToScene();
aStage.show();
aStage.toFront();
}
public static void main(String[] args) {
launch();
}
}
Actual result:
Expected result:
The prefHeightProperty defaults to a sentinel value, indicating that the pref height should be computed. (Region.USE_COMPUTED_SIZE). Thus when you bind the prefHeight of the scroll pane, you effectively instruct it to do the same, which basically means it will get its default size.
Persuading the layout to be performed and measured in order to get the correct size for the scroll pane's preferred height is a bit of a hack. The correct layout sizes depend on CSS, so you must first force the CSS to be applied, and then you can ask for the computed pref height of the top area. You can do the latter with a call to
top.prefHeight(-1);
So the following works:
ScrollPane scrollPane = new ScrollPane(content);
scrollPane.setFitToWidth(true);
// scrollPane.prefHeightProperty().bind(top.heightProperty());
BorderPane root = new BorderPane(scrollPane);
root.setTop(new MenuBar(new Menu("Foo")));
Scene scene = new Scene(root);
aStage.setScene(scene);
root.applyCss();
scrollPane.setPrefHeight(top.prefHeight(-1));
root.requestLayout();
aStage.sizeToScene();
aStage.show();
aStage.toFront();
(Note the call to aStage.sizeToScene(); is not needed: this is the default behavior anyway.)
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.