ComboBox item height bug

John Hendrikx john.hendrikx at gmail.com
Mon Nov 10 01:10:37 UTC 2025


Hi Nir,

I got this mainly from non-public API Region#boundedSize

Node#minWidth and Node#maxWidth do document their respective behaviors,
but Node#prefWidth doesn't very explicitly state that it is clamped to
min/max.

--John

On 10/11/2025 00:34, Nir Lisker wrote:
>
>     When it comes to size priorities (min, pref and max), minimum
>     always wins, then comes maximum, then comes preferred.
>
>     - min/pref/max height are 20/20/20
>     - you set minimum to 6
>     - end result: pref height wins with 20 as it is within the range
>     [min, max]
>     - you also set maximum to 1
>     - end result: pref height is now outside the min/max range, so it
>     is ignored; max is smaller than min, so it is ignored; min wins with 6
>
>
> Is this documented somewhere? I'd think it would answer a lot of
> confusing questions. 
>
> On Sun, Nov 9, 2025 at 8:50 PM John Hendrikx <john.hendrikx at gmail.com>
> wrote:
>
>     Hi,
>
>     Normally a cell will have computed values for each of the
>     min/pref/max.  In your example, you were resetting the cells to
>     USE_PREF_SIZE, but it makes little difference in the reasoning. 
>     All the size of a cell control (which is a label) will be the
>     label's size to display its text.  Its preferred height will be
>     say 20.  Its minimum will also be 20 to avoid cuts off.  Its
>     maximum will be 20 because there is no reason for it to take up
>     more space. Those are the computes sizes.  If you change all to
>     USE_PREF_SIZE, nothing changes (since pref is 20, min and max will
>     copy that).  So:
>
>     - min/pref/max height are 20/20/20
>     - you set minimum to 6
>     - end result: pref height wins with 20 as it is within the range
>     [min, max]
>     - you also set maximum to 1
>     - end result: pref height is now outside the min/max range, so it
>     is ignored; max is smaller than min, so it is ignored; min wins with 6
>
>     If you however set minimum to USE_PREF_SIZE (as was done in your
>     original code) or set it to 1, then you can use the pref size to
>     change it.  Either because 1 is smaller than the pref size, and so
>     changing pref size to a smaller value won't make it go out of
>     range; or in the USE_PREF_SIZE case, because min will simply track
>     the pref size value and always change with it.
>
>     --John
>
>     On 09/11/2025 03:44, Cormac Redmond wrote:
>>     Hi John,
>>
>>     Thanks for the reply & details. One remaining question in my
>>     previous mail however, was why a max *needs* to be set for min to
>>     "win"...this still didn't make sense.
>>
>>     Similarly, I had already tried prefHeight on its own, but it has
>>     no effect (unless it's set to number higher than the computed
>>     size of the cell, in which case it would increase the size).
>>     Setting prefHeight and minHeight together though, can achieve
>>     setting a "max height" though, just like setting a maxHeight and
>>     minHeight as per my previous mail.
>>
>>     But I've noticed that values prefHeight, minHeight, maxHeight are
>>     all defaulted to USE_COMPUTED_SIZE (-1)..., *not
>>     USE_PREF_SIZE* as you mentioned, and I assumed.
>>
>>     So this explains the above behaviour and why several need to be
>>     set: otherwise computed size wins one way or another.
>>
>>     Although confusing initially, I assume there's no bug here and
>>     that the developer needs to always check the underlying nature of
>>     how pref/min/max default values are set for any node, in order to
>>     know what and how to override their settings...?
>>
>>
>>     If you want some validation, you can see these -1 defaults, via a
>>     simpler example:
>>
>>     public class ComboBoxHeightBug2 extends Application {
>>         public static void main(String[] args) {
>>             launch(args);
>>         }
>>
>>         public void start(Stage stage) {
>>             ComboBox<Object> cb = new ComboBox<>();
>>             cb.getItems().addAll("Apple", "Banana", "Carrot", "Lettuce");
>>             cb.setCellFactory(_ -> new ListCell<>() {
>>                 protected void updateItem(Object item, boolean empty) {
>>                     super.updateItem(item, empty);
>>                     if (empty || item == null) {
>>                         setText(null);
>>                         setGraphic(null);
>>                     } else if (item instanceof Separator) {
>>                         setText(null);
>>                         setGraphic((Separator) item);
>>                         setDisable(true);
>>                     } else {
>>                         System.out.println("minHeight: " +
>>     getMinHeight()); // -1
>>                         System.out.println("maxHeight: " +
>>     getMaxHeight()); // -1
>>                         System.out.println("prefHeight: " +
>>     getPrefHeight()); // -1
>>                         setText(item.toString());
>>                         setGraphic(null);
>>                         setStyle("");
>>                     }
>>                 }
>>             });
>>
>>             cb.getSelectionModel().selectFirst();
>>             stage.setScene(new Scene(cb, 200, 100));
>>             stage.show();
>>         }
>>     }
>>
>>
>>
>>
>>     Kind Regards,
>>     Cormac
>>
>>
>>
>>     On Sun, 9 Nov 2025 at 00:06, John Hendrikx
>>     <john.hendrikx at gmail.com> wrote:
>>
>>         What you are likely seeing is that the minimum always wins
>>         over the other values.
>>
>>         The minimum height is set to the constant USE_PREF_SIZE,
>>         which means that it will take the preferred size for the
>>         minimum height.
>>
>>         When it comes to size priorities (min, pref and max), minimum
>>         always wins, then comes maximum, then comes preferred.
>>
>>         So in this case, the preferred size is say 20.  The minimum
>>         follows the preferred, also 20.  You set maximum to 1. 
>>         Minimum > Maximum, so Maximum is ignored.
>>
>>         What you could try is set preferred size smaller instead;
>>         there should be no need to change minimum or maximum then.
>>
>>         --John
>>
>>         On 08/11/2025 21:30, Cormac Redmond wrote:
>>>         Hi,
>>>
>>>         I have found a height bug when I am trying to reduce the
>>>         height of one ComboBox item (a Separator) in a simple ComboBox.
>>>
>>>         One would expect that to achieve this, you'd set the maximum
>>>         height for that particular ListCell; but this has no effect.
>>>
>>>         Instead what I need to do is set the /minimum/ height (but
>>>         to the value I wish to be the maximum height), and I must
>>>         *also *set the /maximum /height to any value (if I do not,
>>>         my minimum height (i.e., my desired maximum) gets ignored)...
>>>
>>>         For example, if I want the maximum height of this Separator
>>>         to be 6, I must set the minimum height to 6 and I must set
>>>         the maximum height to anything, even 1.
>>>
>>>         Obviously this is counter-intuitive and doesn't
>>>         make any logical sense.
>>>
>>>         Example to reproduce (running from JFX master branch):
>>>
>>>         public class ComboBoxHeightBug extends Application {
>>>             public static void main(String[] args) {
>>>                 launch(args);
>>>             }
>>>
>>>             public void start(Stage stage) {
>>>                 ComboBox<Object> cb = new ComboBox<>();
>>>                 cb.getItems().addAll("Apple", "Banana",  new
>>>         Separator() , "Carrot", "Lettuce");
>>>                 cb.setCellFactory(_ -> new ListCell<>() {
>>>                     protected void updateItem(Object item, boolean
>>>         empty) {
>>>                         super.updateItem(item, empty);
>>>                         if (empty || item == null) {
>>>                             setText(null);
>>>                             setGraphic(null);
>>>                             setStyle("");
>>>                             // Set back to default
>>>                             setMinHeight(USE_PREF_SIZE);
>>>                             setMaxHeight(Double.MAX_VALUE);
>>>                         } else if (item instanceof Separator) {
>>>                             setText(null);
>>>                             setGraphic((Separator) item);
>>>                             setDisable(true);
>>>                             setMinHeight(6); // This is required for
>>>         any "max height" to apply, and appears to be the value that
>>>         is used to determine height
>>>                             setMaxHeight(1); // Setting this (to 6)
>>>         should work on its own, it doesn't, the value appears
>>>         irrelevant -- but it MUST be set to get the separator height
>>>         to be 6
>>>                         } else {
>>>                             setText(item.toString());
>>>                             setGraphic(null);
>>>                             setStyle("");
>>>                             // Set back to default
>>>                             setMinHeight(USE_PREF_SIZE);
>>>                             setMaxHeight(Double.MAX_VALUE);
>>>                         }
>>>                     }
>>>                 });
>>>
>>>                 cb.getSelectionModel().selectFirst();
>>>                 stage.setScene(new Scene(cb, 200, 100));
>>>                 stage.show();
>>>             }
>>>         }
>>>
>>>         Note: I have noticed a few issues like this in general,
>>>         whereby it requires trial and error to get /some/ desired
>>>         height to apply; without any apparent logic as to how these
>>>         values are being arrived at or how they're triggered to be
>>>         used (I have logged bugs before on this)...
>>>
>>>
>>>         Kind Regards,
>>>         Cormac
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/openjfx-dev/attachments/20251110/cb046cc3/attachment-0001.htm>


More information about the openjfx-dev mailing list