【问题标题】:JavaFX TextField: How to "auto-scroll" to right when text overflowsJavaFX TextField:文本溢出时如何“自动滚动”到右侧
【发布时间】:2017-02-10 10:48:25
【问题描述】:

我使用TextField 来显示用户在我的应用程序中打开的目录的路径。

目前,如果路径无法容纳在 TextField 内,则在远离此控件/单击远离此控件时,看起来好像路径已被截断:

我希望设置TextField 的行为,这样当我将注意力从它移开时,里面显示的路径会自动滚动到右侧,并且用户能够看到他们打开的目录。 IE。像这样:

我怎样才能做到这一点?我已经尝试调整here 给出的答案

如下在我的 FXML Controller 类中的 initialize() 方法中:

// Controller class fields
@FXML TextField txtMoisParentDirectory;
private String moisParentDirectory;

// ...

txtMoisParentDirectory.textProperty().addListener(new ChangeListener<String>() {

                @Override
                public void changed(ObservableValue<? extends String> observable, String oldStr, String newStr) {
                    moisParentDirectory = newStr;
                    txtMoisParentDirectory.selectPositionCaret(moisParentDirectory.length());
                    txtMoisParentDirectory.deselect();

                }
            });

但它不起作用。

【问题讨论】:

    标签: string javafx textfield


    【解决方案1】:

    您的问题是基于两个事件,输入文本的长度和失去焦点,所以为了解决它,我使用了属性textProperty()focusedProperty(),结果如下:

    import javafx.application.Application;
    import javafx.application.Platform;
    import javafx.beans.value.ChangeListener;
    import javafx.beans.value.ObservableValue;
    import javafx.scene.Scene;
    import javafx.scene.control.TextField;
    import javafx.scene.layout.Pane;
    import javafx.stage.Stage;
    
    public class Launcher extends Application{
    
    private Pane root = new Pane();
    private Scene scene;
    private TextField tf = new TextField();
    private TextField tft = new TextField();
    
    private int location = 0;
    
    @Override
    public void start(Stage stage) throws Exception {
    
    
        scrollChange(); 
        tft.setLayoutX(300);
        root.getChildren().addAll(tft,tf);
        scene = new Scene(root,400,400);
        stage.setScene(scene);
        stage.show();
    
    }
    
    private void scrollChange(){
    
    
        tf.textProperty().addListener(new ChangeListener<String>() {
    
            @Override
            public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
    
                location = tf.getText().length();
    
            }
        });
    
    
        tf.focusedProperty().addListener(new ChangeListener<Boolean>() {
    
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
    
                if(!newValue){
    
                    Platform.runLater( new Runnable() {
                        @Override
                        public void run() {
    
                            tf.positionCaret(location);
    
                        }
                    });
    
    
                }
    
    
            }
        });
    
    
    
    }
    
    
    public static void main(String[] args) {
    
        launch(args); 
    
    }
    
    
    }
    

    关于Platform.runLater,我在这个答案Here之后添加了它,我不知道为什么没有它它就无法工作,祝你好运!

    【讨论】:

    • 感谢您的帮助 - 您使用 Label 的具体原因有哪些?在我的ChangeListener(见问题)中,我添加了location = newStr.length();,其中location 是在您的代码中声明的字段。我还像您一样添加了focusedPropertyChangeListener,但是在运行时它似乎不起作用。您是否有机会使用TextField 而不是Label 来尝试?我知道这不应该有所作为,但只是为了清楚起见。
    • 我删除了Label,没必要看看我更新了我的代码,它在你的代码中不起作用,这就是我添加Platform.runLater()的原因!
    【解决方案2】:
    tf.textProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                int location = tf.getText().length();
                Platform.runLater(() -> {
                    tf.positionCaret(location);
                });
            }
        });
    

    这也是可行的

    【讨论】:

      【解决方案3】:

      由于其他答案对我不起作用,这里有一个解决方案应该可以解决问题:

      private TextField txtField;
      
      // Both ChangeListeners just call moveCaretToEnd(), we need them both because of differing data types we are listening to
      private final ChangeListener<Number> caretChangeListener = (observable, oldValue, newValue) -> moveCaretToEnd();
      private final ChangeListener<String> textChangeListener = (observable, oldValue, newValue) -> moveCaretToEnd();
      
      // This method moves the caret to the end of the text
      private void moveCaretToEnd() {
           Platform.runLater(() -> {
               txtField.deselect();
               txtField.end();
           });
      }
      
      public void initialize() {
          // Immediatly add the listeners on initialization (or once you created the TextField if you are not using FXML)
          txtField.caretPositionProperty().addListener(caretChangeListener);
          txtField.textProperty().addListener(textChangeListener);
      
          txtField.focusedProperty().addListener((observable, oldValue, isFocused) -> {
              if (isFocused) {
                  // once the TextField has been focused remove the listeners to enable normal editing of the text
                  txtField.caretPositionProperty().removeListener(caretChangeListener);
                  txtField.textProperty().removeListener(textChangeListener);
              } else {
                  // when the focus is lost apply the listeners again
                  moveCaretToEnd();
                  txtField.caretPositionProperty().addListener(caretChangeListener);
                  txtField.textProperty().addListener(textChangeListener);
              }
          });
      }
      

      【讨论】:

      • 是的,似乎正在工作..您知道现在鼠标在 focusGained 上的行为不正确(插入符号应该在鼠标位置)?查看 TextFieldBehavior 以了解如何改进 :) 次要:代码 sn-p 中的字段名称不匹配 ..
      • 感谢您的反馈 kleopatra。我修复了 txtField 的命名,并在获得焦点时删除了对 moveCaretToEnd() 的调用。 focusGained 上的行为现在应该是正确的。
      • hmm .. 现在它滚动到通过从另一个控件切换获得的焦点上的文本开头。这可能是可以接受的,具体取决于要求和操作系统标准行为:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-01
      • 2021-11-25
      • 1970-01-01
      • 2017-05-09
      • 2020-12-22
      • 1970-01-01
      相关资源
      最近更新 更多