从 TextArea 拖动选定文本时出现 Javafx 问题

Posted

技术标签:

【中文标题】从 TextArea 拖动选定文本时出现 Javafx 问题【英文标题】:Javafx Issue in dragging selected text from TextArea 【发布时间】:2019-10-21 12:00:10 【问题描述】:

从 TextArea 拖动选定的文本时遇到奇怪的问题。文本被正确选择,但是当我拖动到目标位置时,文本的选择发生了变化,它随机减少了2-3个字符的选择。

这是完整的课程:

public class DnDMainController extends Application 


    ClipboardContent cb = new ClipboardContent();
    ObservableList<String> list = FXCollections.observableArrayList();
    @FXML
    private TextArea sourceText;
    @FXML
    private ListView<String> listView;
    @Override
    public void start(Stage stage) throws Exception 

        Parent root = FXMLLoader.load(getClass().getResource("/main/DnD.fxml"));
          Scene scene = new Scene(root);
          stage.setScene(scene);
          stage.setTitle("Simple Drag and Drop ExampleGame");
          stage.show();

    

    public static void main(String[] args) 
        launch(args);
    
    @FXML
    void _detectDrag(MouseEvent event) 
        Dragboard db = sourceText.startDragAndDrop(TransferMode.COPY);
        cb.putString(sourceText.getSelectedText());
        db.setContent(cb);
        event.consume();
    

    @FXML
    void _dragExited(DragEvent event) 
        String st = event.getDragboard().getString();
        if (!(list.contains(st.trim()))) 
        list.add(st);
        listView.getItems().addAll(list);
    



[![gif for DnD Issue][1]][1]

我在 TextField 上尝试过同样的方法,它在 TextField 上运行良好。但不幸的是,由于文本字符串很大,我无法使用 TextField。我不知道我做错了什么......

FXML 代码:


<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="549.0" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="main.DnDMainController">
   <children>
      <TextArea fx:id="sourceText" layoutY="273.0" onDragDetected="#_detectDrag" prefHeight="127.0" prefWidth="550.0" text="There was once a velveteen rabbit, and in the beginning he was really splendid. He was fat and bunchy, as a rabbit should be; his coat was spotted brown and white, he had real thread whiskers, and his ears were lined with pink sateen. On Christmas morning, when he sat wedged in the top of the Boy’s stocking, with a sprig of holly between his paws, the effect was charming." wrapText="true">
         <font>
            <Font size="19.0" />
         </font></TextArea>
      <ListView fx:id="listView" layoutY="40.0" onDragExited="#_dragExited" onMouseClicked="#_callContext" prefHeight="200.0" prefWidth="516.0" />
      <Label alignment="CENTER" contentDisplay="CENTER" layoutX="-2.0" layoutY="2.0" prefHeight="38.0" prefWidth="550.0" text="List of Words" textAlignment="CENTER" />
      <Label alignment="CENTER" contentDisplay="CENTER" layoutX="7.0" layoutY="240.0" prefHeight="32.0" prefWidth="542.0" text="Story" textAlignment="CENTER" />
   </children>
</AnchorPane>```

【问题讨论】:

请提供minimal, complete and verifiable example,以便我们尝试找出问题所在。对我来说,提供的信息太板了,无法找到问题。 我已经用完整的代码编辑了我的问题 发布您的FXML 使用 FXML 代码编辑 首先,您的代码结构让我知道您对基本 JavaFX 的了解并不好。您在Controller 中扩展Application。其次,基本的Java 实践要求您在创建方法名称时遵循某些规则。使用_ 引导变量名是不好的做法。最后,搜索JavaFXDrag and Drop 将为您提供大量有关如何正确执行此操作的基本教程。 【参考方案1】:

我在尝试以一种直接的方式实现这一点时遇到了一些问题。我必须创建一个允许我选择文本然后拖动文本的切换。在拖动过程中,我注意到它不会抓取所有选定的文本,除非在选定文本的末尾开始拖动。我通过在选择文本后抓住所选文本并将切换模式更改为拖动模式来解决此问题。 MCVE 下面。

主要

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.Parent;

public class Main extends Application     
    @Override
    public void start(Stage stage) throws Exception 

        Parent root = FXMLLoader.load(getClass().getResource("Test.fxml"));
          Scene scene = new Scene(root);
          stage.setScene(scene);
          stage.setTitle("Simple Drag and Drop ExampleGame");
          stage.show();
    

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

FXML

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.ToggleButton?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane id="AnchorPane" prefHeight="583.0" prefWidth="851.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javaapplication12.TestController">
   <children>
      <ListView fx:id="listView" layoutX="326.0" layoutY="14.0" onDragDropped="#dragDropped" onDragEntered="#dragEntered" onDragOver="#dragOver" prefHeight="200.0" prefWidth="200.0" />
      <TextArea fx:id="textArea" layoutX="224.0" layoutY="274.0" onDragDetected="#dragDetected" prefHeight="247.0" prefWidth="426.0" text="There was once a velveteen rabbit, and in the beginning he was really splendid. He was fat and bunchy, as a rabbit should be; his coat was spotted brown and white, he had real thread whiskers, and his ears were lined with pink sateen. On Christmas morning, when he sat wedged in the top of the Boy’s stocking, with a sprig of holly between his paws, the effect was charming." wrapText="true" />
      <ToggleButton fx:id="tbtnDragMode" layoutX="44.0" layoutY="26.0" mnemonicParsing="false" onAction="#handleTbtnDragMode" text="Select Text Mode" />
   </children>
</AnchorPane>

控制器

import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ListView;
import javafx.scene.control.TextArea;
import javafx.scene.control.ToggleButton;
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;

public class TestController implements Initializable 

    @FXML TextArea textArea;
    @FXML ListView listView;
    @FXML ToggleButton tbtnDragMode;


    ObservableList<String> list = FXCollections.observableArrayList();
    String selectedText = "";

    @Override
    public void initialize(URL url, ResourceBundle rb) 
       listView.setItems(list);

       list.add("test");
    

    @FXML private void handleTbtnDragMode(ActionEvent actionEvent)
    
        if(tbtnDragMode.isSelected())
        
            System.out.println("Drag Mode On");
            tbtnDragMode.setText("Drag Mode");
            selectedText = textArea.getSelectedText().isBlank() ? "" : textArea.getSelectedText();
        
        else 
            System.out.println("Drag Mode Off");
            tbtnDragMode.setText("Select Text Mode");
        
    

    @FXML
    private void dragDetected(MouseEvent event) 
        System.out.println("drag detected 1");
        System.out.println(tbtnDragMode.isSelected());
        if(tbtnDragMode.isSelected())
        
            System.out.println("drag detected 2");
            /* drag was detected, start a drag-and-drop gesture*/
            /* allow any transfer mode */
            Dragboard db = textArea.startDragAndDrop(TransferMode.ANY);

            /* Put a string on a dragboard */
            ClipboardContent content = new ClipboardContent();
            content.putString(selectedText);
            db.setContent(content);

            event.consume();
        

    

    @FXML
    private void dragEntered(DragEvent event) 
        System.out.println("dragEntered");
         event.consume();
    

    @FXML
    private void dragDropped(DragEvent event)
    
        System.out.println("Drag dropped");
        /* data dropped */
        /* if there is a string data on dragboard, read it and use it */
        Dragboard db = event.getDragboard();
        boolean success = false;
        if (db.hasString()) 
           list.add(db.getString());
           success = true;
        
        /* let the source know whether the string was successfully 
         * transferred and used */
        event.setDropCompleted(success);

        event.consume();
    

    @FXML
    private void dragDone(DragEvent event) 
        /* the drag and drop gesture ended */
        /* if the data was successfully moved, clear it */
        System.out.println("drag done");
        if (event.getTransferMode() == TransferMode.MOVE) 
            //clear textarea selection
            System.out.println("drag done");
        
        event.consume();
    

    @FXML
    private void dragExited(DragEvent event) 
        System.out.println("dragExited");
         event.consume();
    

    @FXML
    private void dragOver(DragEvent event) 
        /* data is dragged over the target */
        /* accept it only if it is not dragged from the same node 
         * and if it has a string data */
        System.out.println(event.getGestureSource() + " - "  + event.getTarget());
        if (event.getGestureSource() != event.getTarget() &&
                event.getDragboard().hasString()) 
            /* allow for both copying and moving, whatever user chooses */
            event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
        

        event.consume();
    

【讨论】:

非常感谢!但我不想限制用户切换选择和拖动模式。顺便说一句,非常感谢您的努力。

以上是关于从 TextArea 拖动选定文本时出现 Javafx 问题的主要内容,如果未能解决你的问题,请参考以下文章

从 TabControl 拖动时出现表单 ShowDialog 问题

如何在textarea中获取选定的文本? [复制]

chromesafari中的input或textarea

如何在 JavaScript 中获取 textarea 的选定文本范围

如何在 Internet Explorer 7 中使用 jQuery 获取 textarea 中的选定文本?

如何在textarea中的选定文本下方显示一个div?