2017-10-27 1 views
0

私は自分自身にJavaFXを教えています。 Swingの世界には2つのイベント処理の間に多くの類似点があります。私のプロセスの一部は、既存のアプリケーションを可能な限り厳密に模倣しようとすることです。私がやっていることの1つは、ユーザが使用するフォントを選択できるダイアログを作成することです。フォント名を入力するためのテキストフィールドと、スクロールして選択できるリストがあります。入力を開始すると、リストが自動的にスクロールして、ユーザーが入力した内容とのマッチングを開始します。また、テキストフィールドに現在一致するフォント名を入力し、ユーザーがまだ入力していない部分を強調表示して、正しい一致が見つかるまで入力を続けます。JavaFXでプログラム的に選択しようとしていません

たとえば、ユーザーがWindowsで文字 't'を入力した場合、最初に見つかったフォントはTahomaです。テキストフィールドはTahomaに設定され、カラットは 'T'の直後に配置され、 'ahoma'が強調表示されます。代わりに、フィールドにはタホマが埋められ、カラットは最後に配置され、何も強調表示されません。つまり、位置決めとハイライトのために2行のコードを無視している、またはイベントプロセッサがJavaFXライブラリへの呼び出しに順不同で実行されているようです。

これはJavaFXのバグかもしれませんが、私のイベントシステムの誤解かもしれません。どんな理由があるのか​​教えてください。

ここに、問題を示す完全なサンプルコードがあります。テキストフィールドに入力を開始して試してみてください。

package test; 

import javafx.application.Application; 
import javafx.beans.value.ChangeListener; 
import javafx.scene.Scene; 
import javafx.scene.control.TextField; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.text.Font; 
import javafx.stage.Stage; 

public class TestTyping extends Application { 
    ChangeListener<String> textChange; 
    @Override 
    public void start(Stage primaryStage) throws Exception { 
     BorderPane root = new BorderPane(); 
     TextField text = new TextField(); 
     root.setTop(text); 
     Scene scene = new Scene(root); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 

     textChange = (observable, oldValue, newValue) -> { 
      text.textProperty().removeListener(textChange); 
      for (String family : Font.getFamilies()) { 
       if (family.equalsIgnoreCase(newValue) || family.toLowerCase().startsWith(newValue.toLowerCase())) { 
        text.setText(family); 
        text.positionCaret(newValue.length()); 
        text.selectEnd(); 
        break; 
       } 
      } 
      text.textProperty().addListener(textChange); 
     }; 
     text.textProperty().addListener(textChange); 
    } 

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

答えて

1

末尾をPlatform.runLaterにラップします。問題はイベントの順序です。私はこの問題の正確な詳細を知らないので、詳細な解答は提供しません。ここで

Platform.runLater(()-> { 
    text.positionCaret(newValue.length()); 
    text.selectEnd(); 
}); 
+0

私はそれを試みますが、私はイベントスレッドに既に入っているので、必要ではないはずです。 – markbernard

+0

私はそれを試みましたが、問題を修正しませんでした。ありがとう。 – markbernard

+0

私の修正プログラムであなたのコードを試してみて、それが動作しています。キャレットは入力された位置にあり、テキストは強調表示されて終了します。 – MBec

1

は、テキストへの変更を修正するためにTextFormatterを使用した、全く別のアプローチです。ここでの利点は、イベントハンドリングに関するさまざまなプロパティ変更の「タイミング」に依存しないことです。これは文書化されておらず、したがってJavaFXの後のバージョンで変更される可能性があります。それはまた、少し醜い "聴取者を削除し、それを戻す"イディオムを避ける。

import java.util.function.UnaryOperator; 

import javafx.application.Application; 
import javafx.beans.value.ChangeListener; 
import javafx.scene.Scene; 
import javafx.scene.control.TextField; 
import javafx.scene.control.TextFormatter; 
import javafx.scene.control.TextFormatter.Change; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.text.Font; 
import javafx.stage.Stage; 

public class TestTyping extends Application { 
    ChangeListener<String> textChange; 
    @Override 
    public void start(Stage primaryStage) throws Exception { 
     BorderPane root = new BorderPane(); 
     TextField text = new TextField(); 
     root.setTop(text); 
     Scene scene = new Scene(root); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 


     UnaryOperator<Change> filter = c -> { 

      // for delete, move the caret, or change selection, don't modify anything... 
      if (c.getText().isEmpty()) { 
       return c ; 
      } 


      for (String family : Font.getFamilies()) { 
       if (family.toLowerCase().startsWith(c.getControlNewText().toLowerCase())) { 
        c.setText(family.substring(c.getRangeStart(), family.length())); 
        c.setAnchor(c.getControlNewText().length()); 
        break ; 
       } 
      } 

      return c ; 

     }; 

     text.setTextFormatter(new TextFormatter<String>(filter)); 
    } 

    public static void main(String... args) { 
     launch(args); 
    } 
} 
+0

他のありがとうございます。私は間違いなくそれを考慮する。 – markbernard

関連する問題