JavaFX - 将另一个类的属性绑定(bind)到状态栏

标签 java multithreading user-interface javafx progress-bar

所以,我有一个非常非常简单的应用程序,应该处理下载某些文件并将它们更新到某个目录中。该应用程序有一个带有状态栏的简单界面,可以告诉用户下载过程的进展情况。到目前为止,一切顺利。

我有一些扩展javafx.concurrent.Task类的类的实现。这些类处理每个系统的文件下载和保存,并考虑每个系统的特殊性。下载过程本身(实际上来自远程数据库)对于每个人来说都是相同的,因此,它是在另一个名为 FileDownloader 的类中实现的,因为它自然应该是可重用的。

因此,我们有一个带有 call() 方法的 UpdateTask 类,该方法又调用 FileDownloader 类中的某些方法。

问题是:我需要将一个 progressProperty 绑定(bind)到该栏,但只有 UpdateTask 有此属性,而我想在栏中显示大部分工作是在FileDownloader内部完成的。我无法从下载方法中调用 updateProgress,因为它不在 Task 类中。我无法将任务传递到方法中并在那里调用更新方法。我无法在进度属性上创建监听器并监听下载器类内字段的更改。看来我无能为力,唯一真正的解决方案是计算 call() 方法内完成的工作。祸哉是我。

是否有解决方案,不需要我编写可重用性较低的代码?示例代码如下:

public class UpdateTask extends Task<Void> {

@Override
protected Void call() throws Exception {

//some other operations are performed before this part

FileDownloader downloader = new FileDownloader();

//The stuff I wanna count is in there :(
boolean isDownloaded = downloader.downloadSysVersion();

//some other stuff happens that depends on the completion of the download
}

无论谁向我展示如何从 downloadSysVersion 方法内部获取信息,都将获得免费的互联网 cookie。

最佳答案

FileDownloader 类中添加一个表示进度的属性。例如,如果您想公开下载的字节数,您可以这样做

public class FileDownloader {

    private final ReadOnlyLongWrapper bytesDownloaded = new ReadOnlyLongWrapper();

    public final long getBytesDownloaded() {
        return bytesDownloaded.get();
    }

    public final ReadOnlyLongProperty bytesDownloadedProperty() {
        return bytesDownloaded.getReadOnlyProperty();
    }

    private long totalBytes ;

    public long getTotalBytes() {
        return totalBytes ;
    }

    // other code as before...

    public boolean downloadSysVersion() {
        // code as before, but periodically call
        bytesDownloaded.set(...);
        // ...
    }

}

现在你做到了

@Override
protected Void call() throws Exception {

    FileDownloader downloader = new FileDownloader();

    downloader.bytesDownloadedProperty().addListener((obs, oldValue, newValue) -> 
        updateProgress(newValue.longValue(), downloader.getTotalBytes()));

    boolean isDownloaded = downloader.downloadSysVersion();

    // ...
}

如果您想让 FileDownloader 类独立于整个 JavaFX API(包括属性类),您可以使用 LongConsumer 来代替:

public class FileDownloader {

    private LongConsumer progressUpdate ;

    public void setProgressUpdate(LongConsumer progressUpdate) {
        this.progressUpdate = progressUpdate ;
    }

    private long totalBytes ;

    public long getTotalBytes() {
        return totalBytes ;
    }

    public boolean downloadSysVersion() {
        // periodically do
        if (progressUpdate != null) {
            progressUpdate.accept(...); // pass in number of bytes downloaded
        }
        // ...
    }
}

在本例中,您的任务如下所示

@Override
protected Void call() throws Exception {

    FileDownloader downloader = new FileDownloader();

    downloader.setProgressUpdate(bytesDownloaded -> 
        updateProgress(bytesDownloaded, downloader.getTotalBytes()));

    boolean isDownloaded = downloader.downloadSysVersion();

    // ...
}

使用这两种设置中的任何一种,您都可以照常将进度条的 progressProperty 绑定(bind)到任务的 progressProperty

关于JavaFX - 将另一个类的属性绑定(bind)到状态栏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31734527/

相关文章:

java - Java StringBuilder.substring() 方法的时间复杂度是多少?如果是线性的,有没有固定时间复杂度的方法得到一个子串?

java - 使用 Room 库获取最近插入的行 ID

java - 如何在 Firebase 图像标签中使用输入和输出数据类型为 uint8 的 TFLite 模型

java - java中的多个return语句

java - JTextPane 的轻量级替代品?

java - 通过 Netbeans 创建 GUI

c# - 多线程丛林中的全局异常处理 - 故障安全/重启

java - 我必须在哪里使用同步?

python-3.x - 如何在 Python 3 中导入线程包?

Java图像不会随着鼠标点击而移动?