Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFX-8 Make text caret visible in readonly textarea

JavaFX textfields do not show a text caret if you set them to readonly mode. Here is an example:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.stage.Stage;

public class TextAreaReadOnly extends Application {

    public TextAreaReadOnly() {
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        TextArea textarea = new TextArea();
        textarea.setText("This is all\nreadonly text\nin here.");
        textarea.setEditable(false);
        Scene scene = new Scene(textarea, 600, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }    

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

While it is still possible to select text with Shift+Cursor keys, no caret is displayed. Does anyone know a workaround for this?

like image 293
rli Avatar asked Jan 17 '26 14:01

rli


1 Answers

Triggered by Neil's answer, I tried a quick test of my suggestion to extend TextAreaSkin and replace the caretVisible property by one that doesn't check for editability. Seems to work (not thoroughly tested, though) - but requires reflective access of super's private blink property. Obviously dirty and not possible in security restricted contexts ...

public static class MyTextAreaSkin extends TextAreaSkin {

    public MyTextAreaSkin(TextArea textInput) {
        super(textInput);
        caretVisible = new BooleanBinding() {
            { bind(textInput.focusedProperty(), textInput.anchorProperty(), 
                    textInput.caretPositionProperty(),
                    textInput.disabledProperty(), displayCaret , blinkProperty() );}
            @Override protected boolean computeValue() {
                return !blinkProperty().get() &&  displayCaret.get() && textInput.isFocused() &&
                        (isWindows() || (textInput.getCaretPosition() == textInput.getAnchor())) 
                        && !textInput.isDisabled(); 
            }
        };
        // rebind opacity to replaced caretVisible property
        caretPath.opacityProperty().bind(new DoubleBinding() {
            { bind(caretVisible); }
            @Override protected double computeValue() {
                return caretVisible.get() ? 1.0 : 0.0;
            }
        });

    }

    BooleanProperty blinkAlias;

    BooleanProperty blinkProperty() {
        if (blinkAlias == null) {
            Class<?> clazz = TextInputControlSkin.class;
            try {
                Field field = clazz.getDeclaredField("blink");
                field.setAccessible(true);
                blinkAlias = (BooleanProperty) field.get(this);
            } catch (NoSuchFieldException | SecurityException 
                   | IllegalArgumentException | IllegalAccessException e) {
                // TBD: errorhandling
                e.printStackTrace();
            }

        }
        return blinkAlias;
    }

}

// usage in a custom TextArea
TextArea textarea = new TextArea() {

    @Override
    protected Skin<?> createDefaultSkin() {
        return new MyTextAreaSkin(this);
    }

};
like image 178
kleopatra Avatar answered Jan 20 '26 12:01

kleopatra