JavaFX-将另一个类的属性绑定到状态栏 [英] JavaFX - bind property from another class onto a status bar

查看:461
本文介绍了JavaFX-将另一个类的属性绑定到状态栏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我有一个非常简单的应用程序,应该可以下载某些文件并将其更新到某个目录.该应用程序具有一个带有状态栏的简单界面,该状态栏应告诉用户下载过程的进展情况.到目前为止,一切都很好.

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

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

问题是:我需要将 progressProperty 绑定到栏中,但是只有 UpdateTask 具有此属性,而我想在栏中显示的大部分工作在 FileDownloader 中完成.我无法从download方法中调用updateProgress,因为它不在 Task 类中.我无法将任务传递给方法并在那里调用update方法.我无法在progress属性上进行监听,也无法在downloader类内的字段上监听更改.看来我什么也做不了,唯一的解决方案是计算 call()方法中正在进行的工作.祸is是我.

是否有不涉及我编写较少可重用代码的解决方案?示例代码如下:

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方法内部获取信息,都会获得免费的Internet 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绑定到任务的progressProperty.

So, I have a very very simple application that is supposed to handle downloading certain files and updating them into a certain directory. The application has a simple interface with a Status Bar that should tell the user how the download process is going. So far, so good.

I have a few implementations of classes that extend the javafx.concurrent.Task class. Those classes handle the downloading and saving of files for each system, taking care of the particularities for each one. The download process itself (which actually comes from a remote database) is the same for everyone, so, it's implemented in another class which is called FileDownloader as it is, naturally, supposed to be reusable.

So, we have an UpdateTask class with a call() method that, in turn, calls some method in the FileDownloader class.

Trouble is: I would need to bind a progressProperty to the bar, but only UpdateTask has this property, while most of the work I want to show in the bar is done inside FileDownloader. I cannot call updateProgress from within the download method, as it isn't inside the Task class. I cannot pass the task into the method and call the update method there. I cannot make a listener on the progress property and listen for changes on the fields inside the downloader class. It seems I cannot do anything and the only real solution would be to count the work being done inside the call() method. Woe is me.

Is there a solution for this that doesn't involve me writing less reusable code? Example code as follows:

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
}

Whoever shows me how to get the information from inside the downloadSysVersion method gets a free internet cookie.

解决方案

Add a property in the FileDownloader class representing the progress. For example, if you wanted to expose the number of bytes downloaded, you could do

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(...);
        // ...
    }

}

Now you do

@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();

    // ...
}

If you want to make the FileDownloader class independent of the entire JavaFX API (including the property classes), you can use a LongConsumer instead:

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
        }
        // ...
    }
}

and in this case your task looks like

@Override
protected Void call() throws Exception {

    FileDownloader downloader = new FileDownloader();

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

    boolean isDownloaded = downloader.downloadSysVersion();

    // ...
}

With either of these setups, you can then just bind the progress bar's progressProperty to the task's progressProperty as usual.

这篇关于JavaFX-将另一个类的属性绑定到状态栏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆