【问题标题】:How do I properly bind a .Text property to the Overridden .asString() method of a SimpleObjectProperty?如何正确地将 .Text 属性绑定到 SimpleObjectProperty 的 Overridden .asString() 方法?
【发布时间】:2014-12-25 15:14:37
【问题描述】:

我正在创建一个简单的控件来浏览和采样音频文件。我想使用ObjectProperty<File>,这样我就可以绑定负责播放文件的按钮的一些属性:

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

那么我将需要覆盖三件事,其中两件事我已经成功完成,因此不会进入

第三个是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按钮文本保持为 [NONE]。

这是浏览文件的代码:

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。我知道这样做是因为切换按钮变为活动状态并按下它会播放声音文件。

那么我在这里错过了什么/做错了什么?

编辑:

我想我可能有一个想法: 我覆盖的方法之一是 set 方法:

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

会不会是重写set方法导致它不触发重写的asString方法?

【问题讨论】:

    标签: java file binding javafx object-property


    【解决方案1】:

    问题是每次调用asString() 方法时都会创建一个新的绑定。由于您在文件为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() 方法中。该方法不会因为属性改变而被调用。

    因此,当调用 get() 方法时,您需要创建一个处理所有逻辑的 StringBinding(检查文件是否为空,如果不存在,则检查文件是否存在,如果存在则获取名称等)。您可以通过子类化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);

    【讨论】:

    • 那里有一些非常漂亮的代码。成功了。不是 100% 确定原因,但我会接受。
    • 弄清楚发生了什么,并相应地更新了答案。
    • 非常酷,这比你的澄清更有意义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-25
    • 2012-09-20
    • 1970-01-01
    • 2013-05-04
    • 1970-01-01
    • 1970-01-01
    • 2014-01-28
    相关资源
    最近更新 更多