1

It looks like TableView has some default width, independent from columns content (not to mention height and position on screen, which also are affected by using it as a root of Scene instead of for example StackPane).

I understand that every JavaFX element has it's preferred size, and that scene is adjusting to it, but I wonder where this comes from? I tried to find it in TableView documentation and get it's width using getters, but with no success.

I know I can set stage width and height explicitly, but it's not what I am interested in.

On this example you can observe how the size (and position) of the window change, depending of it's content.

@Override
public void start(Stage stage) throws IOException, URISyntaxException {
    TableView table = createTable();
    StackPane pane = new StackPane();

    Scene scene = new Scene(table);
//  Scene scene = new Scene(pane);
    stage.setScene(scene);
    stage.show();
}
Line
  • 1,529
  • 3
  • 18
  • 42
  • 2
    It's retrieved using the `prefWidth` property. In this there's probably some logic in the `TableViewSkin` class involved... – fabian Jun 08 '19 at 16:40
  • @fabian but then do you know why *getPrefWidth()* on this `TableView` returns -1? – Line Jun 08 '19 at 17:34
  • 3
    A pref width/height of `-1` is the value of `Region.USE_COMPUTED_SIZE`. This means the preferred size is computed during layout, using methods like `computePrefWidth`. As `TableView` is a `Control`, the implementation of this computation is likely in the skin class instead of the control class. If you're wondering how to _get_ this computed value, I'm not sure you can—at least not reliably. There's `Node#prefWidth(double)` but you need to know what the parent passes as the height value if the node uses it for computations. – Slaw Jun 08 '19 at 17:50
  • @Slaw yay, I really get it now, thanks to you. actually, with those informations and a little digging, it was not so hard to find it. if anyone is wondering about the same thing, take a look at `computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset)` in `TableViewSkinBase` - the implementation is really funny ;) (I'm using JavaFX 12). @Slaw, please add your comment as answer, so I can accept it. – Line Jun 08 '19 at 18:39

1 Answers1

2

When it comes to minimum, preferred, and maximum dimensions of a Region, there are three different modes1:

  1. The developer sets them explicitly (e.g. setPrefWidth(400)).
  2. They are set to Region.USE_COMPUTED_SIZE (i.e. -1.0)2.
  3. They are set to Region.USE_PREF_SIZE (i.e. negative infinity)1.

1. The preferred dimensions only have two modes as USE_PREF_SIZE only has meaning for the minimum and maximum dimensions.
2. This is the default for Region and most (all?) of its subclasses.


When the dimensions are set to USE_COMPUTED_SIZE this means the values are computed during layout, using protected methods such as:

And similar methods for the minimum and maximum dimensions.

When it comes to Controls, however, these computations are typically delegated to the skin class. Most skin implementations inherit from SkinBase which provides similar methods for computing min/pref/max dimensions; they have the same names but accept more parameters to make the computations a little easier. You note in a comment that, in the case of TableView, the computations for preferred width and height take place in TableViewSkinBase.

You may be wondering how you can get this computed value; I don't believe you can in a reliable fashion. You could try using the public methods of Node, such as Node.prefWidth(double), but the problem is knowing what value to pass as an argument. In the case the value shouldn't be -1 then it's really only the parent that knows for certain how much space is available.

Note: These methods of Node (e.g. prefWidth(double)) are the "entry point" for getting the minimum, preferred, and maximum dimensions of a Node. However, the min, pref, and max properties are not universal (available for Regions and, to an extent, WebView) and the computeXXX methods are unique to Parent (and its subclasses). Other kinds of Nodes, such as Shapes, provide their own internal mechanisms.

Also, the preferred dimensions are just a guideline. The parent is free to size its children as it sees fit within the constraints of the min and max values. If you want to know what the dimensions of a node ultimately end up being you can use the Region.width and Region.height properties (when using a Region) or the Node.boundsInLocal property (for an arbitrary Node). WebView and some Shape implementations also provide properties for knowing their dimensions.


Note:

This answer focuses on Nodes (i.e. the scene graph). As pointed out by kleopatra, other objects (e.g. TableColumnBase) that have properties like prefWidth don't have the same specified behavior as Region. For instance, setting the value to -1 is not defined to behave the same way. This also applies to WebView which, while having min/pref/max dimension properties, is not a Region.

The TableView's default skin implementation takes into account the prefWidth of each visible TableColumn when computing its preferred width.

Slaw
  • 37,820
  • 8
  • 53
  • 80
  • *cough (nothing new to you, obviously, just to nitpick ) ... TableColumn is _not_ a Node - or in other words: the effect of -1 for pref is unspecified ;) – kleopatra Jun 09 '19 at 08:55
  • True, though the question (as I interpreted it) was about `TableView` and my answer focuses on `Node`s only. I added a note about `TableColumnBase`. – Slaw Jun 09 '19 at 10:14
  • oops ... looks like I misread the question, thanks for the heads-up :) – kleopatra Jun 09 '19 at 10:19
  • @Slaw "The TableView's default skin implementation takes into account the prefWidth of each visible TableColumn when computing its preferred width." - I see that. is there a way to affect those columns widths so they take into account table content? the problem which I have is preferred size is 80 (default), but during displaying they are wider (*width* property is much bigger). – Line Jun 10 '19 at 19:29
  • @Line If you're asking if each `TableColumn` can automatically size itself to fit the largest of its content, the answer is probably "no". The problem is that only a small portion of the items are rendered and the table has no idea how much space the non-rendered items require. However, something in this question may provide an answer: https://stackoverflow.com/questions/14650787/javafx-column-in-tableview-auto-fit-size – Slaw Jun 10 '19 at 21:36
  • @Slaw the problem is they are resizing, but somehow after columns (and therefore table) size is calculated - that, connected with the fact that my scene is fitting to the table, results in clipped table - it's width is fixed to 400, and I can scroll the table inside. – Line Jun 11 '19 at 19:43
  • 1
    @Line I'm not sure I understand the problem. Perhaps you should ask a new question where you can provide a [mre] and a more detailed explanation. – Slaw Jun 11 '19 at 21:24