Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange control widths in JavaFX 2?

I am new to JavaFX 2 and confused about the default widths of ComboBox and ListView. I would expect the ComboBox to be wider, so that the text "the prompt text" would be completely visible, for the ListView I would expect it to be smaller, only as wide as necessary. Code and screenshot following below.

1) How can I achieve that ComboBox and Listview are both sized to the width they need?

2) How to make both controls the same width (therefore the maximum out of both widths), is it possible to create some kind of link between the widths of both? I am especially looking for an elegant solution for FXML.

Thanks for any hint!

@Override
public void start(Stage primaryStage) {
    ComboBox<String> comboBox = new ComboBox<String>();
    comboBox.setPromptText("the prompt text");
    ObservableList<String> items = FXCollections.observableArrayList();
    items.addAll("item 1", "item 2");
    comboBox.setItems(items);

    ListView<String> list = new ListView<String>();
    ObservableList<String> items2 =FXCollections.observableArrayList (
        "blue", "red");
    list.setItems(items2);

    VBox vBox = new VBox();
    vBox.getChildren().addAll(comboBox, list);

    primaryStage.setScene(new Scene(vBox, 200, 300));
    primaryStage.show();
}

enter image description here

like image 335
stefan.at.wpf Avatar asked May 07 '12 19:05

stefan.at.wpf


1 Answers

2) How to make both controls the same width (therefore the maximum out of both widths), is it possible to create some kind of link between the widths of both? I am especially looking for an elegant solution for FXML.

It looks like, by default, ListView has it's maxWidth unbounded, but ComboBox has it's maxWidth clamped to the width of it's initial item list. To make these controls have the same width, the easiest way to do it is place them in a layout manager (as you have done - the VBox) and then unclamp the maxWidth of the comboBox.

In code you can do this:

comboBox.setMaxWidth(Double.MAX_VALUE);

In FXML add the following attibute definition to your ComboBox element:

maxWidth="Infinity"

You can use the John Gray's binding solution, but I find the above more elegant.

1) How can I achieve that ComboBox and Listview are both sized to the width they need?

I think what you are asking here is how to make the combobox and listview only take up as much space as they need and no more. This is, I believe a bit tricky, and the JavaFX platform does not provide a lot of support for this.

Here is some sample code for fixing the size of the listbox to the minimum required.

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.scene.*;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListView;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;

public class GridControlWidths extends Application {
  public static void main(String[] args) throws Exception { launch(args); }
  @Override public void start(Stage stage) {
    ComboBox<String> comboBox = new ComboBox<String>(FXCollections.observableArrayList("item 1", "item 2"));
    comboBox.setPromptText("the prompt text");

    ListView<String> list = new ListView<String>(FXCollections.observableArrayList ("blue", "red"));

    // layout the controls in a grid with appropriate constraints.
    GridPane grid = new GridPane();
    grid.add(comboBox, 0, 0);
    grid.add(list, 0, 1);
    grid.setVgrow(list, Priority.ALWAYS);  // make the list grow vertically as much as possible

    // unclamp the max width of the combo box.
    comboBox.setMaxWidth(Double.MAX_VALUE);

    // display the scene.
    stage.setScene(new Scene(grid, 200, 300));
    stage.show();

    // set the prefWidth of the listview based on the list cells (allowing 8 pixels for padding of the cells).
    double maxWidth = 0;
    for (Node n: list.lookupAll(".text")) {
      maxWidth = Math.max(maxWidth, n.getBoundsInParent().getWidth() + 8);
    }
    list.setPrefWidth(maxWidth);
  }
}

FWIW, I believe a recommended approach when you just have a few items is to to put your items in a VBox rather than using a ListView or a ChoiceBox rather than a ComboBox, that way you don't need to do the cell introspection and update the preferred width all of the time as the layout manager and controls will take care of it for you. The ListView is optimized to handle the case of a virtualized list which can contain thousands of arbitrarily sized items for which you may not be able to easily calculate the layout width, which is why I think it comes with the default control sizing behaviour which does not size it to the minimum size it could possibly have. Usually when using a ListView you will just pick a reasonable prefWidth for the listView and set that on the listView rather than introspecting the items as the example above shows.

Additionally, the image you have where some of the prompt text is clipped, would seem (to me) to be a bug in JavaFX where it does not correctly calculate the preferred width for the ComboBox control when the ComboBox prompt text is wider than the ComboBox item text. As ComboBox is currently a brand new control and I have seen these kind of issues in earlier builds of JavaFX controls and they got fixed, I would expect that the preferred width calculation for the ComboBox will get fixed reasonably soon.

like image 159
jewelsea Avatar answered Oct 02 '22 16:10

jewelsea