0

I want to create a JavaFX fxml based dialog, where the user can enter a bunch of integer and double values. I created the dialog in SceneBuilder using for each of the values a dedicated TextField.

Intentionally I am not using Binding between the TextFields and the model. In order to NOT add a ChangeListener or set a TextFormatter to each of these TextFields in the controller again and again, I created a dedicated IntegerTextField and DoubleTextField class, e.g.

public class IntegerTextField extends TextField {

    protected static Pattern decimalPattern = Pattern.compile("^-?\\d+$");      // Double ("-?\\d*(\\.\\d{0,1})?");

    public IntegerTextField() {
        super();
        setTextFormatter(new TextFormatter<>(c -> (decimalPattern.matcher(c.getControlNewText()).matches()) ? c : null ));
    }

    public int getInt() {
        try {
            return Integer.parseInt(getText());
        }
        catch (NumberFormatException e) {
            return 0;
        }
    }
}

and in the Controller class I replaced the previous

@FXML private TextField setsTextField;

with

@FXML private IntegerTextField setsTextField;

When I got the

javafx.fxml.LoadException:...Can not set util.IntegerTextField field ctrl.ExerciseEditorCtrl.setsTextField to javafx.scene.control.TextField

I realized that this implicit downcasting doesn't work.

Is there a way to do this properly with fxml or is it neccessary to have the dialog setup in a java class when using IntegerTextField?

jewelsea
  • 150,031
  • 14
  • 366
  • 406
Alex
  • 1,387
  • 2
  • 9
  • 14
  • 2
    Changing the type of the field in the controller class does not alter the FXML file. You would need to modify the FXML file to change the `TextField` elements to your classes. Given your classes are part of your project, which means they are not a compiled library that you can add to Scene Builder, I'm not sure that Scene Builder can help you here. You might have to go into the FXML file and manually edit it. – Slaw Aug 04 '22 at 07:47
  • 2
    Provide the fxml, perhaps a [mcve]. It would appear you don’t reference a `IntegerTextField` in your fxml, though I don’t know why you don’t do that. – jewelsea Aug 04 '22 at 07:56
  • 1
    don't extend a class for mere configuration, don't do manual pattern matching for numbers – kleopatra Aug 04 '22 at 09:14
  • As Slow suggested, I changed the fxml file manually, and it works. But now I lost the ability to edit the dialog in SceneBuilder. For anybody having the same issue: The way to do that is described here https://stackoverflow.com/questions/30063792/adding-a-custom-component-to-scenebuilder-2-0 – Alex Aug 04 '22 at 10:09
  • @kleopatra There's no other way to get a configured element into an FXML file except to extend a class. The only other alternative is to violate DRY and have endless repeated configuration code in the FXML Controller. – DaveB Aug 04 '22 at 15:41
  • @DaveB textFormatter is a property on the textField that's __meant__ to be configured, so use it in that way ;) you wouldnt extend the class just to vary its colors would you? – kleopatra Aug 04 '22 at 16:51
  • @DaveB Another option is to create a factory method that simply creates a `TextField` and then adds an appropriate `TextFormatter` to it. Then you can use `fx:factory` in the FXML file (not sure if that's possible from Scene Builder). This approach still adheres to DRY. – Slaw Aug 04 '22 at 23:09
  • @kleopatra It may be borderline, but I think the addition of the `getInt()` convenience method by the OP could justify creating a subclass (though the implementation could be better). – Slaw Aug 04 '22 at 23:13
  • @Alex Your `getInt()` method does not need to parse the text. Save your formatter in a field, and then change the implementation to `return theFormatter.getValue()`. You might want to define a default value. Also, note your regex for `Double` does not take localization into account (e.g., some countries use `,` as the decimal separator), though that may not matter for this application. – Slaw Aug 04 '22 at 23:14
  • 1
    @Slaw _but I think the addition of the getInt() convenience method by the OP could justify creating a subclass_ I disagree because it's too specific (you really want a subclass for every type of numbers? or custom types?) A valid (IMO) extension would be to a) require a formatter, generify the textField with the formatter's type and add a getValue(). – kleopatra Aug 04 '22 at 23:35
  • @kleopatra Hmm, good point. Agreed. – Slaw Aug 04 '22 at 23:52
  • @Slaw - At that point I'm just happy that I'm not using FXML/SceneBuilder and I can just call a builder method to do it all. – DaveB Aug 05 '22 at 01:29

0 Answers0