0

オーディオ ファイルを参照してサンプリングするための単純なコントロールを作成しています。ObjectProperty<File>ファイルの再生を担当するボタンのいくつかのプロパティをバインドできるように、を使用したいと思います。

PlayButton.disableProperty.bind(this.BGMFile.isNull());
PlayButton.textProperty.bind(this.BGMFile.asString());

そのため、オーバーライドする必要があることが 3 つあり、そのうちの 2 つが正常に完了したため、ここには入りません。

3 つ目は asString メソッドです。

new SimpleObjectProperty<File>(this, "BGM File", null){
    /*yadda yadda overrides*/
    @Override public StringBinding asString(){
        if (super.get() != null && super.get().exists())
            return (StringBinding) Bindings.format(
                super.get().getName(), this
            );
        else return (StringBinding) Bindings.format("[NONE]", this);
    }
}

これは私には正しいと感じており、grepCode hereからコードをリッピングしましたが、FileChooser を使用してファイルを参照すると、使用するファイルをセットアップして選択し、SimpleProperty に設定して、ボタンのテキストはそのままです[なし]。

これは、ファイルを参照するためのコードです。

this.btnBrowseBGM.setOnAction((ActionEvent E) -> {
    FileChooser FC = new FileChooser();
    FC.getExtensionFilters().add(Filters.AudioExtensions());
    FC.setTitle("Browse for Background Audio File");
    File F = FC.showOpenDialog(this.getScene().getWindow());
    if (F != null && F.exists()) try {
        this.BGMFile.set(Files.copy(
            F.toPath(),
            Paths.get("Settings/Sound/", F.getName()),
            StandardCopyOption.REPLACE_EXISTING
        ).toFile());
    } catch(IOException ex) {
        Methods.Exception(
            "Unable to copy file to Settings Sound Directory.",
            "Failed to copy Sound File", ex);
        this.BGMFile.set(F);
    } else this.BGMFile.set(null);
    E.consume();
});

パスが存在しないため、私に怒鳴られますが(私は予想していました)、それでもBGMFileプロパティをに設定する必要がありますF。トグルボタンがアクティブになり、それを押すとサウンドファイルが再生されるため、そうであることがわかります。

では、ここで何が欠けている/間違っているのでしょうか?

編集:

私はアイデアを持っていると思います:私がオーバーライドするメソッドの1つはsetメソッドです:

@Override public void set(File newValue){
    if (newValue != null && newValue.exists())
        super.set(newValue);
    else super.set(null);
}

set メソッドをオーバーライドすると、オーバーライドされたメソッドがトリガーされない可能性がありasStringますか?

4

1 に答える 1

1

asString()問題は、メソッドが呼び出されるたびに新しい Binding を作成することです。ファイルが のときに最初に呼び出すので、nullによって作成されたバインディングを取得しますBindings.format("[NONE]", this)。したがって、ボタンのバインディングは次と同等です。

playButton.textProperty().bind(Bindings.format("[NONE]", bgmFile));

そのため、ファイル プロパティが変更されたときに文字列値が再評価されても、まだフォーマットされています"[NONE]"

そうすれば、反対の問題を見ることができます

ObjectProperty<File> fileProperty = new SimpleObjectProperty<File>() { 
    /* your previous implementation */
};
fileProperty.set(new File("/path/to/some/valid/file"));
// now bind when you get the filename:
playButton.textProperty().bind(fileProperty.asString());
// setting the fileProperty to null will now invoke the binding that was provided when it wasn't null
// and you'll see a nice bunch of null pointer exceptions:
fileProperty.set(null);

別の言い方をすれば、必要な名前の有効なファイルがバインディングに存在しないかどうかをチェックするロジックがasString()メソッドにあるということです。プロパティが変更されたからといって、そのメソッドが呼び出されるわけではありません。

そのため、メソッドが呼び出されたときにすべてのロジックを処理する単一のものを作成する必要がありますStringBinding(ファイルが null かどうかを確認し、そうでない場合は存在するかどうかを確認し、存在する場合は名前を取得するなど) get()。これを行うには、サブクラスStringBinding化してロジックをcomputeValue()メソッドに入れるか、次のようにユーティリティBindings.createStringBinding(...)メソッドを使用します。

new SimpleObjectProperty<File>(this, "BGM File", null){

    final StringBinding string = Bindings.createStringBinding(() -> {
        File file = this.get();
        if (file != null && file.exists()) {
            return file.getName();
        } else {
            return "[NONE]";
        }
    }, this);

    @Override public StringBinding asString(){
        return string ;
    }
}

それだけの価値があるため、必要な場合を除き、サブクラス化を避けるスタイルを好む傾向があります。この場合、StringBindingファイル プロパティにバインドするだけの別のオブジェクトを作成します。ここでの選択はユースケースによって異なりますが、これはほとんどのユースケースで機能し、「オーバーライドされたメソッドが機能しない方法で相互作用していますか」と尋ねることは決してありません。一般的に、あなたが持っていたようなバグはもっとこのスタイルでは明らかです:

ObjectProperty<File> bgmFile = new SimpleObjectProperty(this, "bgmFile", null);
StringBinding fileName = Bindings.createStringBinding( () -> {
    File file = bgmFile.get();
    if (file != null && file.exists()) {
        return file.getName();
    } else return "[NONE]";
}, bgmFile);

そしてもちろん、ただ行うだけですplayButton.textProperty().bind(fileName);

于 2014-10-29T19:21:34.517 に答える