JavaFX TextArea从坐标获取插入位置

时间:2015-06-11 03:41:10

标签: java javafx textarea javafx-8

是否可以在JavaFX int的屏幕坐标(2 double)处获取插入位置(TextArea)?

3 个答案:

答案 0 :(得分:8)

您可以在拖动处理程序中使用TextAreaSkin的getInsertionPoint方法:

TextAreaSkin skin = (TextAreaSkin) target.getSkin();
int insertionPoint = skin.getInsertionPoint(event.getX(),  event.getY());
target.positionCaret( insertionPoint);

但是,skin类在com.sun.javafx。*中,所以Java 9出来后你可能不得不采用不同的方式。没有人知道他们会破坏什么或他们提供什么作为替代品。但是,使用Java 8它(现在)可以工作。

您可以将Label的文本拖动到TextArea中的任何位置的完整示例:

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

import com.sun.javafx.scene.control.skin.TextAreaSkin;

// Parts of this drag/drop example are from https://docs.oracle.com/javafx/2/drag_drop/HelloDragAndDrop.java.html
public class TextAreaDemo extends Application {

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

    @Override
    public void start(Stage primaryStage) {

        Label source = new Label( "Draggable Text");

        TextArea target = new TextArea();
        target.setPrefRowCount(10);
        target.setPrefColumnCount(100);
        target.setWrapText(true);
        target.setPrefWidth(150);

        String cssDefault = "Lorem ipsum dolor sit amet, et bonorum pertinacia est, verear temporibus definitionem nam an, ius cu justo legimus philosophia. Adversarium complectitur at sit, his ex sumo nibh consequuntur. Et vim adhuc mnesarchum, eum in ignota integre tincidunt. Erant oblique alterum no eos.";

        target.setText(cssDefault);

        HBox root = new HBox();
        root.setSpacing(10);
        HBox.setMargin(source, new Insets(10,10,10,10));
        HBox.setMargin(target, new Insets(10,10,10,10));
        root.getChildren().addAll( source, target);

        Scene scene = new Scene(root, 600, 330, Color.WHITE);
        primaryStage.setScene(scene);
        primaryStage.show();

        source.setOnDragDetected(new EventHandler <MouseEvent>() {
            public void handle(MouseEvent event) {

                /* allow any transfer mode */
                Dragboard db = source.startDragAndDrop(TransferMode.ANY);

                /* put a string on dragboard */
                ClipboardContent content = new ClipboardContent();
                content.putString(source.getText());
                db.setContent(content);

                event.consume();
            }
        });

        target.setOnDragOver(new EventHandler <DragEvent>() {
            public void handle(DragEvent event) {

                /* accept it only if it is  not dragged from the same node 
                 * and if it has a string data */
                if (event.getGestureSource() != target &&
                        event.getDragboard().hasString()) {
                    /* allow for both copying and moving, whatever user chooses */
                    event.acceptTransferModes(TransferMode.COPY_OR_MOVE);

                    // position caret at drag coordinates 
                    TextAreaSkin skin = (TextAreaSkin) target.getSkin();
                    int insertionPoint = skin.getInsertionPoint(event.getX(),  event.getY());
                    target.positionCaret( insertionPoint);

                }

                event.consume();
            }
        });

        target.setOnDragDropped(new EventHandler <DragEvent>() {
            public void handle(DragEvent event) {

                /* if there is a string data on dragboard, read it and use it */
                Dragboard db = event.getDragboard();
                boolean success = false;
                if (db.hasString()) {
                    target.insertText( target.getCaretPosition(), db.getString());
                    success = true;
                }
                /* let the source know whether the string was successfully 
                 * transferred and used */
                event.setDropCompleted(success);
                event.consume();
            }
        });
    }
}

答案 1 :(得分:2)

import com.sun.javafx.scene.control.skin.TextAreaSkin;
import com.sun.javafx.scene.text.HitInfo;
/****************************************************/

TextAreaSkin skin = (TextAreaSkin) target.getSkin();
HitInfo mouseHit = skin.getIndex(e.getX(), e.getY());
// Now you can position caret
skin.positionCaret(mouseHit, false, false);
// And/or get insertion index
int insertionPoint = mouseHit.getInsertionIndex();

对于TextArea,这种方法相当于罗兰的答案。这种方法的实际区别在于它对TextFieldTextInputControl的另一个子类)的适用性:

TextFieldSkin skin = (TextFieldSkin) target.getSkin();
HitInfo mouseHit = skin.getIndex(e.getX(), e.getY());
skin.positionCaret(mouseHit, false);
int insertionPoint = mouseHit.getInsertionIndex();

不幸的是,TextFieldSkin没有覆盖getInsertionPoint(...),而父实体的实现返回0,因此替代解决方案在这里不起作用。

关于Java 9,Roland和我的答案仍然有用。 包com.sun.javafx.scene.control.skincom.sun.javafx.scene.textHitInfo类所在的位置)正在转移到Java 9中的公共API。它们的位置将是javafx.scene.control.skinjavafx.scene.text,分别。请参阅Javadocs for JavaFX 9:http://download.java.net/java/jdk9/jfxdocs/index.html

答案 2 :(得分:0)

要始终看到光标,请将其放在setOnDragOver - Methode

target.requestFocus();