0

I am seeing some odd behavior, where the preferred width of a javafx.scene.control.TextField isn't being computed correctly after calling setPrefColumnCount. My specific use case is for a javafx.scene.control.Spinner control. My code is as follows:

@FXML
private Spinner<Integer> mySpinner;

@Override
public void initialize(URL location, ResourceBundle resources) {
    mySpinner.getEditor().setPrefColumnCount(3);
}

After executing the above, I get a spinner that is barely large enough for a single character (the spinner value is pictured at 999):

Incorrectly Sized Spinner

Does anyone know the correct way to set the width of a TextField based on the number of digits I want to be able to display? I am using JRE 8u77 on Windows 7 Enterprise SP1 x64, in case it matters.

EDIT

I have realized that part of the problem is that even if I measure the text via the instructions here, I still don't know what to set Spinner.prefWidth to. In addition, it appears that setting the prefWidth on the underlying TextField editor is no different than setting it on the Spinner object. Is there some way to get the TextField.padding property (returns 0 within the initialize method, even though it is eventually set to 7 on each side)? How about a way to query the width of the up/down arrows? If I could somehow compute/query these values, then I could use the measure text technique. Without that information, however, I can't figure out how to go about it.

Community
  • 1
  • 1
Jeff G
  • 4,470
  • 2
  • 41
  • 76
  • That property has never worked for me, either. I got around it by using a different method to determine relative display scaling. I created a variable that is sort of like an em value in css. `final static double em = Math.rint(new Text("").getLayoutBounds().getHeight());` and then I use it as my basis for relative width and height by using a multiplier. `navButtons.setButtonMinWidth(5*em);` – RonSiven May 12 '16 at 17:59
  • I tried to do something like that based on [measuring text](http://stackoverflow.com/a/13020490/960115) containing the desired number of zero characters. However, in the specific case of the `Spinner` object, I am struggling with how to apply that measurement. It appears that setting the `prefWidth` of the underlying `TextField` must also account for the `padding` property (returns 0 within the `initialize` method, even though it will end up being 7) and the up/down buttons (whose width I can't seem to get). – Jeff G May 12 '16 at 18:44

1 Answers1

1

The padding property returns 0 because the TextField not being layed out at that time doesn't have any CSS style applied to it. Try to get the padding after the TextField is added to the SceneGraph.

At that time you're also able to use the Nodes lookup method to get the StackPane which contains the arrow button:

 StackPane upArrow = (StackPane) spnr.lookup(".increment-arrow-button");
 StackPane downArrow = (StackPane) spnr.lookup(".decrement-arrow-button");

Then it should be possible to calculate the width for the spinner:

 double spinnerWidth = calculateWidth("123", spnr.getEditor()) + upArrow.getWidth();

 private double calculateWidth(String value, TextField textField) {
        Text text = new Text(value);
        text.setFont(textField.getFont());
        Insets insets = textField.getInsets();
        return insets.getLeft() + text.prefWidth(-1) + insets.getRight();
    }
jns
  • 6,017
  • 2
  • 23
  • 28
  • Is there some event I can subscribe to that is fired "after the `TextField` is added to the `SceneGraph`"? If not, what is the standard practice to achieve this functionality? – Jeff G May 13 '16 at 13:55
  • You can use any of the mentioned methods after the node in question is attached to a `Scene` in a `Stage`that is showing. So after showing a `Stage` by `stage.show()` you can call the method you need. – jns May 13 '16 at 14:34
  • All of my JavaFX controllers were already implementing an interface that includes a `setStage` method (so I could set the owner for pop-up dialogs). For those components that include a `Spinner` control, I registered for the `Stage.onShown` event, and perform this width calculation within that handler. – Jeff G May 13 '16 at 19:01
  • One final note: I had to add `prefWidth="0"` to the FXML on the `Spinner` element for this to work. Otherwise, the layout was not performed when setting the `prefWidth` property value after the `Stage` was shown. – Jeff G May 13 '16 at 20:18