How to align a ListView BASELINE in a GridPane - java

I'm currently writing a Java-FX program that contains a ListView in a GridPane. I want to align the listview by the baseline of its first item with the label to the left of the listview, but the listview is initially empty. It appears not aligned correctly, but jumps to the right position when it is populated and an item is selected.
I asume, in order to calculate the correct baseline offset, the listview needs to know its items before it is shown. So, how can I create an empty listview and fill it dynamically (by user actions), when it should be aligned BASELINE?
You can reproduce the effect with the following mcve (Java 8 u221):
import javafx.application.Application;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.RowConstraints;
import javafx.stage.Stage;
public class ListViewAlignmentTest extends Application
{
public static void main(String[] args)
{
Application.launch(args);
}
#Override
public void start(Stage stage)
{
ListView<String> listview = new ListView<String>();
listview.setPrefSize(100.0, 100.0);
RowConstraints rc0 = new RowConstraints();
rc0.setValignment(VPos.BASELINE);
RowConstraints rc1 = new RowConstraints();
rc1.setValignment(VPos.BASELINE);
GridPane root = new GridPane();
root.getRowConstraints().add(0, rc0);
root.getRowConstraints().add(1, rc1);
root.setHgap(10);
root.setVgap(10);
root.add(new Label("Some text"), 0, 0);
root.add(new TextField(), 1, 0);
root.add(new Label("Other text"), 0, 1);
root.add(listview, 1, 1);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
listview.getItems().addAll("String1", "String2");
}
}
This is how the GUI looks initially: https://i.imgur.com/nUXqyDm.png
After selecting the first listview item it looks correct: https://i.imgur.com/i73kbKw.png
I expect the listview to be aligned BASELINE to the label next to it, but it first appears under the label.

Edit: updated complete code.
When replicated it so that it looks like as shown in image, https://i.imgur.com/i73kbKw.png
Code below makes it immovable.
import javafx.application.Application;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.RowConstraints;
import javafx.stage.Stage;
public class ListViewAlignmentTest extends Application
{
public static void main(String[] args)
{
Application.launch(args);
}
#Override
public void start(Stage stage)
{
ListView<String> listview = new ListView<String>();
listview.setPrefSize(100.0, 100.0);
RowConstraints rc0 = new RowConstraints();
rc0.setFillHeight(true);
RowConstraints rc1 = new RowConstraints();
rc1.setFillHeight(true);
GridPane root = new GridPane();
root.getRowConstraints().add(0, rc0);
root.getRowConstraints().add(1, rc1);
root.setHgap(10);
root.setVgap(10);
root.add(new Label("Some text"), 0, 0);
root.add(new TextField(), 1, 0);
root.add(new Label("Other text"), 0, 1);
root.add(listview, 1, 1);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
listview.getItems().addAll("String1", "String2");
}
}
As a result, it does not move now. That should help.

Related

JavaFx : VBox still occupies space when invisible [duplicate]

Is it possible to shrink a GridPane row if the content of that row is both disabled and invisible?
When I set a Node to disable=true and visible=false, the cell still takes up space.
If I have 8 rows and only the first and last is visible I don't want the empty rows to take up much space. As if there was only two rows.
The only "solution" I could find was to set the size to zero. However I do not consider that a good solution. I would have to store the min/max size to set it back when/if the node becomes enabled/visible again.
Could perhaps CSS help with a better solution?
package com.company;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;
public class App 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 {
Label label1 = new Label("Text");
Label label2 = new Label("Text");
Label label3 = new Label("Text");
label2.setDisable(true);
label2.setVisible(false);
GridPane root = new GridPane();
root.setGridLinesVisible(true);
root.add(label1, 0, 0);
GridPane.setVgrow(label1, Priority.NEVER);
root.add(label2, 0, 1);
GridPane.setVgrow(label2, Priority.NEVER);
root.add(label3, 0, 2);
GridPane.setVgrow(label3, Priority.NEVER);
stage.setScene(new Scene(root));
stage.setWidth(300);
stage.setHeight(300);
stage.setTitle("JavaFX 8 app");
stage.show();
}
}
If you do not want the parent to layout a node, you can set the managed property of the node to false.
Here is an image showing the difference in layout when I used the following line in your code:
label2.setManaged(false);

GridPane doesn't align in center

I am making a Login Screen with a number pad, and I can't seem to center align a GridPane of buttons in a Pane. What am I doing wrong?
Main.java
import javafx.application.Application;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.input.KeyCombination;
import javafx.stage.Screen;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args){
launch(args);
}
public void start(Stage primaryStage) throws Exception{
Rectangle2D bounds = Screen.getPrimary().getBounds();
LoginScreen loginScreen = new LoginScreen(bounds.getWidth(), bounds.getHeight());
Scene scene = new Scene(loginScreen.get());
primaryStage.setScene(scene);
primaryStage.setFullScreenExitKeyCombination(KeyCombination.NO_MATCH);
primaryStage.show();
primaryStage.setFullScreen(true);
}
}
LoginScreen.java
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
public class LoginScreen {
private Pane root;
private GridPane numberPad;
public LoginScreen(double screenWidth, double screenHeight){
root = new Pane();
root.setPrefSize(screenWidth, screenHeight);
root.setBackground(new Background(new BackgroundFill(Color.AQUA, CornerRadii.EMPTY, Insets.EMPTY)));
numberPad = new GridPane();
Button button01 = new Button("1");
Button button02 = new Button("2");
Button button03 = new Button("3");
Button button04 = new Button("4");
Button button05 = new Button("5");
Button button06 = new Button("6");
Button button07 = new Button("7");
Button button08 = new Button("8");
Button button09 = new Button("9");
numberPad.setAlignment(Pos.CENTER);
numberPad.add(button01, 0, 0);
numberPad.add(button02, 1, 0);
numberPad.add(button03, 2, 0);
numberPad.add(button04, 0, 1);
numberPad.add(button05, 1, 1);
numberPad.add(button06, 2, 1);
numberPad.add(button07, 0, 2);
numberPad.add(button08, 1, 2);
numberPad.add(button09, 2, 2);
root.getChildren().addAll(numberPad);
}
public Pane get(){
return root;
}
}
GUI code is verbose, and this post editor isn't letting me post my question as is, so I need these extra lines to get it to accept my question. If I thought I could cut down my code to just the numberPad.setAlignment(Pos.Center) and still make it clear how I am attempting to center my GridPane I most certainly would. I do humbly thank those who might lend me their time to help me solve this issue I have.
Edit 01:
My issue is that the GridPane itself is drawn in the top left corner of the screen rather than in the center of the screen.
You need to actually set the alignment for the parent container. A Pane is not a valid container for doing this, however.
If you were to use a VBox instead, you could simply set its alignment as so:
VBox root = new VBox(10);
root.setAlignment(Pos.CENTER);
That will cause all of the children of the VBox to be placed in the center.
The Pos enum also provides other methods of positioning, including TOP_CENTER, TOP_LEFT, and BOTTOM_RIGHT, for example.

GridPane not visible unless i resize window javaFx

when i start the application, TitledPane does not show the GridPane I have added. Surprisingly it's visible the moment i increase/decrease the window width. where am i missing?
Here is the Complete Code:
package com.ct.bic.comparator;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Accordion;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.control.TitledPane;
import javafx.scene.layout.GridPane;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.stage.Stage;
public class Comparator extends Application {
#Override
public void start(Stage stage) {
GridPane dbGrid = new GridPane();
dbGrid.setId("dbGrid");
dbGrid.setAlignment(Pos.TOP_LEFT);
dbGrid.setHgap(10);
dbGrid.setVgap(10);
dbGrid.setPadding(new Insets(25, 25, 25, 25));
Label dbConnection = new Label("Database Configuration");
dbConnection.setId("dbConnection");
dbConnection.setFont(Font.font("Tahoma", FontWeight.NORMAL, 20));
dbGrid.add(dbConnection, 0, 0, 2, 1);
Label server = new Label("Server");
server.setId("server");
dbGrid.add(server, 0, 1);
TextField serverText = new TextField();
serverText.setId("serverText");
dbGrid.add(serverText, 1, 1);
Label database = new Label("Database");
database.setId("database");
dbGrid.add(database, 0, 2);
TextField databaseText = new TextField();
databaseText.setId("databaseText");
dbGrid.add(databaseText, 1, 2);
Label user = new Label("User");
user.setId("user");
dbGrid.add(user, 0, 3);
TextField userText = new TextField();
userText.setId("userText");
dbGrid.add(userText, 1, 3);
Label password = new Label("Password");
password.setId("password");
dbGrid.add(password, 0, 4);
PasswordField passwordText = new PasswordField();
passwordText.setId("passwordText");
dbGrid.add(passwordText, 1, 4);
dbGrid.setId("passwordText");
/*GridPane dbGrid = DatabaseInputGrid.getDatabaseGrid();*/
TitledPane tp = new TitledPane("Database Configuration", dbGrid);
Scene scene = new Scene(tp, 500,500);
stage.setScene(scene);
stage.setTitle("Bic-Java Output Comparator Pro");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I don't know the exact reason why, but it seems TitledPane is not resized if used as root for the Scene.
I tried something like this:
VBox vbox = new VBox();
vbox.getChildren().add(tp);
Scene scene = new Scene(vbox, 500,500);
Then everything works as expected.
Edit:
I have found this here:
Do not explicitly set the minimal, maximum, or preferred height of a
titled pane, as this may lead to unexpected behavior when the titled
pane is opened or closed.
So my guess is, when you set your TitledPane as root for the scene, it will try to set the preferred height, that leads to the mentioned "unexpected behaviour".

How do i properly move multiple items in a single listView control to another listveiw control in javaFx?

I have made it possible to have multiple items in a list move to another list but when i move it to the other list [] these pop up around the just moved item and the multiple choices that are chosen are all on a single line in the list view control rather then it being individually listed items going vertically down the list.I need this for an assignment. Here is what i have.
package com.company.javaFxPractice;
import javafx.collections.*;
import javafx.geometry.*;
import javafx.scene.*;
import javafx.scene.text.Text;
import javafx.stage.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.application.*;
public class ListProblem extends Application
{
ObservableList<String> girlNames;
ObservableList<String> boyNames;
Button moveLeftButton;
Button moveRightButton;
Scene scene1;
public void start(Stage primaryStage) throws Exception
{
primaryStage.setTitle("List Problem");
primaryStage.setResizable(false);
primaryStage.sizeToScene();
GridPane gridPane = new GridPane();
scene1 = new Scene(gridPane,350,200);
ListView<String> data = new ListView<String>();
data.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
girlNames = FXCollections.observableArrayList(
"Meagan Good", "Jessica Alba", "Erykah Badu", "Beyonce", "Janet"
);
data.setItems(girlNames);
ListView<String> data2 = new ListView<String>();
boyNames = FXCollections.observableArrayList(
"Eddie Murphy", "Richord Pryor", "Eddie Griffin", "Kevin Heart", "Mike"
);
data2.setItems(boyNames);
gridPane.setConstraints(data, 0, 0);
gridPane.setConstraints(data2, 1, 0);
moveLeftButton = new Button("Move Left");
moveLeftButton.setPrefSize(200, 30);
moveLeftButton.setAlignment(Pos.CENTER);
moveLeftButton.setOnAction(event -> {
String selection = "";
//turns selected item on left list control to a string
selection = String.valueOf(data.getSelectionModel().getSelectedItems());
//adds selected Item to the list on the right
boyNames.add(selection);
// removes whatever was selected from the left list
girlNames.remove(data.getSelectionModel().getSelectedItem());
});
gridPane.setConstraints(moveLeftButton, 0, 1);
moveRightButton = new Button("Move Right");
moveRightButton.setPrefSize(200, 30);
moveRightButton.setAlignment(Pos.CENTER);
moveRightButton.setOnAction(event -> {
String selection = "";
//turns selected item on the right list control to a string
selection =
String.valueOf(data2.getSelectionModel().getSelectedItems());
//adds the string to the list on the left
girlNames.add(selection);
// removes whatever was just selected from right list
boyNames.remove(data2.getSelectionModel().getSelectedItem());
});
gridPane.setConstraints(moveRightButton,1,1);
gridPane.getChildren().
addAll(data,data2,moveLeftButton,moveRightButton);
primaryStage.setScene(scene1);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
You don't need to convert the selected items into a String. You can (and should) directly add them to the other List.
Try using:
moveLeftButton.setOnAction(event -> {
boyNames.addAll(data.getSelectionModel().getSelectedItems());
girlNames.removeAll(data.getSelectionModel().getSelectedItems());
});
Please take a note that I am using getSelectedItems(), because this ListView has MULTIPLE selection enabled.
and similarly,
moveRightButton.setOnAction(event -> {
girlNames.addAll(data2.getSelectionModel().getSelectedItem());
boyNames.remove(data2.getSelectionModel().getSelectedItem());
});
Complete Working Example
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class ListProblem extends Application {
ObservableList<String> girlNames;
ObservableList<String> boyNames;
Button moveLeftButton;
Button moveRightButton;
Scene scene1;
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("List Problem");
primaryStage.setResizable(false);
primaryStage.sizeToScene();
GridPane gridPane = new GridPane();
scene1 = new Scene(gridPane, 350, 200);
ListView<String> data = new ListView<String>();
data.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
girlNames = FXCollections.observableArrayList("Meagan Good",
"Jessica Alba", "Erykah Badu", "Beyonce", "Janet");
data.setItems(girlNames);
ListView<String> data2 = new ListView<String>();
boyNames = FXCollections.observableArrayList("Eddie Murphy",
"Richord Pryor", "Eddie Griffin", "Kevin Heart", "Mike");
data2.setItems(boyNames);
GridPane.setConstraints(data, 0, 0);
GridPane.setConstraints(data2, 1, 0);
moveLeftButton = new Button("Move Left");
moveLeftButton.setPrefSize(200, 30);
moveLeftButton.setAlignment(Pos.CENTER);
moveLeftButton.setOnAction(event -> {
boyNames.addAll(data.getSelectionModel().getSelectedItems());
girlNames.removeAll(data.getSelectionModel().getSelectedItems());
});
GridPane.setConstraints(moveLeftButton, 0, 1);
moveRightButton = new Button("Move Right");
moveRightButton.setPrefSize(200, 30);
moveRightButton.setAlignment(Pos.CENTER);
moveRightButton.setOnAction(event -> {
girlNames.addAll(data2.getSelectionModel().getSelectedItem());
boyNames.remove(data2.getSelectionModel().getSelectedItem());
});
GridPane.setConstraints(moveRightButton, 1, 1);
gridPane.getChildren().addAll(data, data2, moveLeftButton,
moveRightButton);
primaryStage.setScene(scene1);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

JavaFx :Default Message for Empty ListView

When there is no record in any table it shows a message 'No content in table', which is by default functionality of TableView in JavaFx.
So here my question is, does the same can be possible with ListView in JavaFx ? Like, if there is no item in any ListView then it will show a message same as TableView, instead of a blank/empty fields.
You have to try this:-
listView.setPlaceholder(new Label("No Content In List"));
its 100% working....
JavaFX8 has a setPlaceholder(...) method for ListView.
In earlier versions, you need to roll your own somehow. This is a bit of a hack: it wraps the ListView in a stack pane, with a white rectangle and the placeholder displayed over the top of the list view. The placeholder and rectangle have their visible property bound, so they are only visible if the list is empty.
There may be easier ways that I'm not seeing right away...
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class ListViewPlaceholderTest extends Application {
#Override
public void start(Stage primaryStage) {
final ListView<String> listView = new ListView<>();
final IntegerProperty counter = new SimpleIntegerProperty();
final Button addButton = new Button("Add item");
addButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
counter.set(counter.get()+1);
listView.getItems().add("Item "+counter.get());
}
});
final Button removeButton = new Button("Remove");
removeButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
listView.getItems().remove(listView.getSelectionModel().getSelectedIndex());
}
});
removeButton.disableProperty().bind(Bindings.equal(listView.getSelectionModel().selectedIndexProperty(), -1));
final HBox buttons = new HBox(5);
buttons.setPadding(new Insets(10));
buttons.getChildren().addAll(addButton, removeButton);
final BorderPane root = new BorderPane();
root.setCenter(createPlaceholderForListView(listView, new Label("No content in List")));
root.setBottom(buttons);
final Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
private Node createPlaceholderForListView(ListView<?> listView, Node placeholder) {
final StackPane pane = new StackPane();
final Rectangle rect = new Rectangle(0, 0, Color.WHITE);
rect.widthProperty().bind(listView.widthProperty());
rect.heightProperty().bind(listView.heightProperty());
pane.getChildren().addAll(listView, rect, placeholder);
placeholder.visibleProperty().bind(Bindings.isEmpty(listView.getItems()));
rect.visibleProperty().bind(placeholder.visibleProperty());
rect.setMouseTransparent(true);
return pane ;
}
}
With fxml:
<ListView fx:id="foundContentList">
<placeholder>
<Label text="Nothing found" />
</placeholder>
</ListView>
Not entirely sure but I don't think there is a setPlaceholder method(to set the default message when no content in table) for ListView.
The workaround that I use is to create an Object in the list that indicate "No content" and show that on the listview and also disable it.
For example:
ObservableList noContent= FXCollections.observableArrayList("No content found");
ListView listView = new ListView(noContent);
listView.setDisable(true);

Categories