0

I'm using some TextFields in JavaFX, and I want to limit their area of shown text. I already limit their maximum number of characters, but in some cases, the maximum char number typed is larger than the Textfield's width. As you see, the text is overlapping a custom Erase-text button I added.

I want to know if I can move the text's right margin a little bit to the left (without changing the TextField's properties - size, coordinates), so the button and the text won't overlap anymore.

I already tried margins, padding, but they don't do what I need.

Example

How do I limit my TextField's maximum length (from stackoverflow):

public class LimitedJFXTextField extends JFXTextField {

    private final IntegerProperty maxLength;

    public LimitedJFXTextField() {
        super();
        this.maxLength = new SimpleIntegerProperty(-1);
    }

    public IntegerProperty maxLengthProperty() {
        return this.maxLength;
    }

    public final Integer getMaxLength() {
        return this.maxLength.getValue();
    }

    public final void setMaxLength(Integer maxLength) {
        Objects.requireNonNull(maxLength,
                "Max length cannot be null, -1 for no limit");
        this.maxLength.setValue(maxLength);
    }

    @Override
    public void replaceText(int start, int end, String insertedText) {
        if (this.getMaxLength() <= 0) {
            // Default behavior, in case of no max length
            super.replaceText(start, end, insertedText);
        } else {
            // Get the text in the textfield, before the user enters something
            String currentText = this.getText() == null ? "" : this.getText();

            // Compute the text that should normally be in the textfield now
            String finalText = currentText
                    .substring(0, start) + insertedText + currentText
                    .substring(end);

            // If the max length is not excedeed
            int numberOfexceedingCharacters = finalText.length() - this
                    .getMaxLength();
            if (numberOfexceedingCharacters <= 0) {
                // Normal behavior
                super.replaceText(start, end, insertedText);
            } else {
                // Otherwise, cut the the text that was going to be inserted
                String cutInsertedText = insertedText.substring(
                        0,
                        insertedText.length() - numberOfexceedingCharacters
                );

                // And replace this text
                super.replaceText(start, end, cutInsertedText);
            }
        }
    }
}
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Alex
  • 149
  • 1
  • 1
  • 7
  • the layout is the task of the skin: to add children, subclass TextFieldSkin, add what's needed and override computeXX and layoutChildren to accomodate for them. Unrelated: why this manual hack for limiting the # of chars? That's possible but belongs into stone age, the current way to implement it is using a TextFormatter – kleopatra Feb 22 '21 at 10:15
  • anyway, whenever asking for debug help a [mcve] is required - not just a snippet of (copied?) code. Actually, when having problems with layout there's no need at all for other specialities like char-limitation (repeating: in a very out-dated way!) – kleopatra Feb 22 '21 at 10:20
  • @DevilsHnd can't be really certain but: the question is about layout, not about limiting the the # of chars in the field (which is answered well in your referenced QA :) – kleopatra Feb 22 '21 at 15:18
  • @kleopatra yes, you're right, the question was about layout. Also, I was using that manual hack because, to be honest, I wasn't aware of the TextFormatter. I first tried using TextProperty, but at least in my way of implementing this, it was buggy. Then, I switched to that manual stone-aged hack. Thanks for your help! I didn't solve my problem yet, even though you gave me a solution, but I will keep trying. At least, I modified my way of limiting the # of chars :) – Alex Feb 24 '21 at 08:11
  • @kleopatra can you be more specific, again, please? I'm trying what you said, and I haven't got even a small progress, in the last few hours (plus google-ing this for 2 days; without finding something relevant, other than what you suggested). If I'm annoying, or breaking some rules with my reply, please delete my post. Thanks! – Alex Feb 24 '21 at 12:05
  • Can you provide your code of the textfield layout – Sai Dandem Mar 04 '21 at 22:25
  • It's just a material-layout TextField (jfoenix's JFXTextField), nothing special. Also, for the "clear text" button (that "X" circle), I'm using a clickable ImageView on top of the TextField. I don't want to make the TextField smaller, or move the button outside the TextField. – Alex Mar 05 '21 at 05:46
  • Have you tried using `ControlFX` `CustomTextField`? `CustomTextField textfield = new CustomTextField textfield.setRight(new Button());` – SedJ601 Mar 05 '21 at 07:24
  • I know about ControlFX CustomTextField, but I want to use JFXTextField's skin. – Alex Mar 05 '21 at 07:59
  • Could you use `CSS` to get a similar looking skin? – SedJ601 Mar 05 '21 at 17:01
  • Does this work? https://stackoverflow.com/questions/57614505/how-do-i-limit-the-number-of-characters-visible-in-a-text-field-at-a-time-to-les?noredirect=1&lq=1 – trilogy Mar 08 '21 at 19:50
  • Unfortunately not @trilogy, it makes my JFXTextField less wider (from the right side), if I use `-fx-padding: 4px 25px 4px 7px;`. It's not just limiting the text area, it's also decreasing the TextField area. – Alex Mar 08 '21 at 22:15
  • I'm not sure, @Sedrick, I'll look up to what you suggested. – Alex Mar 08 '21 at 22:16

2 Answers2

0

Here is a solution using ControlsFX.

import java.io.IOException;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import org.controlsfx.control.textfield.CustomTextField;

/**
 * JavaFX App
 */
public class App extends Application
{

    private static Scene scene;

    @Override
    public void start(Stage stage) throws IOException
    {
        CustomTextField customTextField = new CustomTextField();
        customTextField.setText("Hello World!");

        Label labelX = new Label("x");
        labelX.setTextFill(Color.RED);
        customTextField.setRight(labelX);
        customTextField.setMaxWidth(200);

        scene = new Scene(new StackPane(customTextField), 500, 500);//loadFXML("primary"), 640, 480);
        stage.setScene(scene);
        stage.show();
    }
}

enter image description here

SedJ601
  • 12,173
  • 3
  • 41
  • 59
0

I have never used JFXTextField, so take this answer with a grain of salt.

However, since JFXTextField extends TextField, you should be able to change properties of TextField. One of these is called padding:

So using just the "normal" TextField, you can use this:

public class ExampleApp extends Application {

    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage stage) {
        var textField = new TextField();
        textField.setPadding(new Insets(0, 50, 0, 0)); // This adds 50px right padding
        textField.setText("Hello World!");

        var label = new Label("x");

        var pane = new StackPane(textField, label);
        StackPane.setAlignment(label, Pos.CENTER_RIGHT);

        var scene = new Scene(pane, 500, 500);
        stage.setScene(scene);
        stage.show();
    }
}

Or if you prefer FXML, use this:

<TextField>
    <padding>
        <Insets right="50"/>
    </padding>
</TextField>

The StackPane as well as the Label are just for the sake of demonstrating some overlaying item, same as in Sedricks answer. The important part which actually restricts the text inside of the textfield is the padding.

Sebastian S
  • 4,420
  • 4
  • 34
  • 63
  • It doesn't work. It modifies my TextField skin (makes it smaller). This is how the TextField looks originally, without padding (the Phone TextField), and how the TextField looks with padding (the Mail TextField): [photo demo](https://i.imgur.com/tAWjJoz.png) – Alex Mar 12 '21 at 13:02
  • That is a matter of styling, though. You need to distinguish between behaviour (that is what your question is about) and appearance (your screenshot). Please add the CSS of your text field to your question, if you need help fixing the length of the bottom border. – Sebastian S Mar 13 '21 at 14:18
  • It's the default skin of JFXTextField: [css-file](https://github.com/sshahine/JFoenix/blob/master/jfoenix/src/main/resources/com/jfoenix/assets/css/controls/jfx-text-field.css) – Alex Mar 14 '21 at 23:18