【问题标题】:JavaFX-8 Make text caret visible in readonly textareaJavaFX-8 使文本插入符号在只读文本区域中可见
【发布时间】:2014-12-04 10:23:34
【问题描述】:

如果您将 JavaFX 文本字段设置为只读模式,则它们不会显示文本插入符号。这是一个例子:

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);
    }
}

虽然仍然可以使用 Shift+光标键选择文本,但不会显示插入符号。有人知道解决方法吗?

【问题讨论】:

  • 为什么在ReadOnly 文本控件上需要TextCaret?当鼠标指针悬停在文本上时,您想设置鼠标指针的样式吗?
  • 我不想改变鼠标指针。我希望 textarea 显示 TextInputControl.getCaretPosition() 的位置。我猜 TextArea 没有显示插入符号的原因是你不需要它,因为当它是只读的时你无论如何都不能插入任何文本。但这是错误的(IMO),因为您仍然可以使用光标键选择文本,为此您绝对需要插入符号。
  • 也许允许编辑和覆盖编辑事件以模拟只读!?

标签: javafx javafx-8


【解决方案1】:

Neil's answer 触发,我尝试快速测试我的建议,以扩展 TextAreaSkin 并将 caretVisible 属性替换为不检查可编辑性的属性。似乎可以工作(虽然没有经过彻底测试)-但需要对 super 的 private blink 属性进行反射访问。显然很脏,在安全受限的情况下是不可能的......

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);
    }

};

【讨论】:

    【解决方案2】:

    我想要同样的东西 - 一个只读字段,但对导航可见插入符号。我试过了:

    .text-input:readonly { -fx-display-caret: true; }
    

    但无济于事。深入FX source code (for 2.2),我发现了这个:

    caretVisible = new BooleanBinding() {
            { bind(textInput.focusedProperty(), textInput.anchorProperty(), textInput.caretPositionProperty(),
                    textInput.disabledProperty(), textInput.editableProperty(), displayCaret, blink);}
            @Override protected boolean computeValue() {
                // RT-10682: On Windows, we show the caret during selection, but on others we hide it
                return !blink.get() && displayCaret.get() && textInput.isFocused() &&
                        (isWindows() || (textInput.getCaretPosition() == textInput.getAnchor())) &&
                        !textInput.isDisabled() &&
                        textInput.isEditable();
            }
        };
    

    看起来没有办法覆盖条件末尾的 isEditable() 要求。我可能会在虚拟插入符号上绘画作为一种变通方法,这很丑陋,但我不确定是否有另一种方法——看起来你可以伪造插入符号或伪造只读方面(拒绝对控件的所有编辑)。

    【讨论】:

    • 加一个用于挖掘 :-) 您可能会考虑实现自定义皮肤并覆盖绑定 - caretVisible 受保护(尽管 blink 不是)并且仅在受保护的 caretPath 中使用,因此您可以摆脱扩展..
    • 如果您不在安全受限的环境中(并且公司规则允许):自定义 TextAreaSkin 似乎可以解决问题。不过,没有测试过副作用
    猜你喜欢
    • 1970-01-01
    • 2013-07-05
    • 1970-01-01
    • 2011-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多