后台和线程中的 JavaFX 图像加载

2024-03-10

我认为这是一个简单的问题,但我很难找到答案。我有一个与 JavaFX Scene 对象关联的 ImageView 对象,我想从磁盘加载大图像并使用 ImageView 依次显示它们。我一直在尝试找到一种好方法来重复检查 Image 对象,当它在后台加载完成时,将其设置为 ImageView,然后开始加载新的 Image 对象。我提出的代码(如下)有时有效,有时无效。我很确定我遇到了 JavaFX 和线程的问题。它有时会加载第一张图像并停止。变量“processing”是类中的布尔实例变量。

在后台加载 JavaFX 中的图像并在加载完成后将其设置到 ImageView 的正确方法是什么?

public void start(Stage primaryStage) {

       ... 

       ImageView view = new ImageView();
       ((Group)scene.getRoot()).getChildren().add(view);

       ... 

        Thread th = new Thread(new Thread() {
            public void run() {

                while(true) {
                    if (!processing) {

                        processing = true;         
                        String filename = files[count].toURI().toString();
                        Image image = new Image(filename,true);

                        image.progressProperty().addListener(new ChangeListener<Number>() {
                            @Override public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number progress) {
                                if ((Double) progress == 1.0) {
                                    if (! image.isError()) {
                                        view.setImage(image);
                                    }
                                    count++;
                                    if (count == files.length) {
                                        count = 0;
                                    }
                                    processing = false;
                                }
                            }
                        });
                    }
                }
            }
        });
    }

实际上,我认为可能有一种比您尝试使用的方法更好的通用方法来满足您的应用程序的要求,但这是我实现您描述的方法的最佳答案。

创建一个有界的BlockingQueue在加载图像时保存它们。队列的大小可能需要一些调整:太小,您将没有任何“缓冲区”(因此您将无法利用任何比平均加载速度更快的缓冲区),太大,您可能会消耗太多内存。这BlockingQueue允许您从多个线程安全地访问它。

创建一个简单循环并加载每个图像的线程同步地,即该线程在每个图像加载时阻塞,并将它们存储在BlockingQueue.

由于您想要尝试在每个 FX 帧(即 60fps)中最多显示一次图像,因此请使用AnimationTimer http://docs.oracle.com/javase/8/javafx/api/javafx/animation/AnimationTimer.html。这有一个handle在 FX 应用程序线程上的每个帧渲染上调用的方法,因此您可以实现它poll() the BlockingQueue,如果图像可用,请将其设置在ImageView.

这是一个 SSCCE。我还指出了如何在固定的时间内显示每个图像,因为我认为这是一个更常见的用例,并且可能会帮助其他人寻找类似的功能。

import java.io.File;
import java.net.MalformedURLException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javafx.animation.AnimationTimer;
import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;


public class ScreenSaver extends Application {

    @Override
    public void start(Stage primaryStage) {

        BorderPane root = new BorderPane();

        Button startButton = new Button("Choose image directory...");
        startButton.setOnAction(e -> {
            DirectoryChooser chooser= new DirectoryChooser();
            File dir = chooser.showDialog(primaryStage);
            if (dir != null) {
                File[] files = Stream.of(dir.listFiles()).filter(file -> {
                    String fName = file.getAbsolutePath().toLowerCase();
                    return fName.endsWith(".jpeg") | fName.endsWith(".jpg") | fName.endsWith(".png");
                }).collect(Collectors.toList()).toArray(new File[0]);
                root.setCenter(createScreenSaver(files));
            }
        });

        root.setCenter(new StackPane(startButton));

        primaryStage.setScene(new Scene(root, 800, 800));
        primaryStage.show();
    }

    private Parent createScreenSaver(File[] files) {
        ImageView imageView = new ImageView();
        Pane pane = new Pane(imageView);
        imageView.fitWidthProperty().bind(pane.widthProperty());
        imageView.fitHeightProperty().bind(pane.heightProperty());
        imageView.setPreserveRatio(true);

        Executor exec = Executors.newCachedThreadPool(runnable -> {
            Thread t = new Thread(runnable);
            t.setDaemon(true);
            return t ;
        });

        final int imageBufferSize = 5 ;
        BlockingQueue<Image> imageQueue = new ArrayBlockingQueue<Image>(imageBufferSize);

        exec.execute(() -> {
            int index = 0 ;
            try {
                while (true) {
                    Image image = new Image(files[index].toURI().toURL().toExternalForm(), false);
                    imageQueue.put(image);
                    index = (index + 1) % files.length ;
                }
            } catch (MalformedURLException e) {
                throw new RuntimeException(e);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // This will show a new image every single rendering frame, if one is available: 
        AnimationTimer timer = new AnimationTimer() {

            @Override
            public void handle(long now) {
                Image image = imageQueue.poll();
                if (image != null) {
                    imageView.setImage(image);
                }
            }
        };
        timer.start();

        // This wait for an image to become available, then show it for a fixed amount of time,
        // before attempting to load the next one:

//        Duration displayTime = Duration.seconds(1);
//        PauseTransition pause = new PauseTransition(displayTime);
//        pause.setOnFinished(e -> exec.execute(createImageDisplayTask(pause, imageQueue, imageView)));
//        exec.execute(createImageDisplayTask(pause, imageQueue, imageView));

        return pane ;
    }

    private Task<Image> createImageDisplayTask(PauseTransition pause, BlockingQueue<Image> imageQueue, ImageView imageView) {
        Task<Image> imageDisplayTask = new Task<Image>() {
            @Override
            public Image call() throws InterruptedException {
                return imageQueue.take();
            }
        };
        imageDisplayTask.setOnSucceeded(e -> {
            imageView.setImage(imageDisplayTask.getValue());
            pause.playFromStart();
        });
        return imageDisplayTask ;
    }

    public static void main(String[] args) {
        launch(args);
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

后台和线程中的 JavaFX 图像加载 的相关文章

  • 文章中的内联图像和标题 - 使标题的宽度与图像的宽度一致

    这是我的代码 div class image img src image jpg alt Image description p class caption This is the image caption p div 这是我的 CSS
  • 在单个显示器中绘制多个 jpeg 图像

    我需要在单个组合显示器 或画布 中绘制和显示多个 jpeg 图像 例如 假设我有图像 a b c d jpg 每个图像的大小不同 我想将它们绘制在 2x2 网格的一页上 能够为每个子图设置标题也很好 我一直在彻底寻找解决方案 但不知道如何去
  • 使用无图像按钮有哪些优点?

    讨论关于这个答案 https stackoverflow com questions 520640 how can i use googles new imageless button how could i reverse enginee
  • 在不支持 CAS 操作的处理器上进行 CompareAndSet

    今天 我在一次采访中被问到下一个问题 如果您在具有不支持 CAS 操作的处理器的机器上调用 AtomicLong 的compareAndSet 方法 会发生什么情况 您能否帮我解决这个问题 并在可能的情况下提供一些全面描述的链接 From
  • minAreaRect OpenCV 返回的裁剪矩形 [Python]

    minAreaRectOpenCV 中返回一个旋转的矩形 如何裁剪矩形内图像的这部分 boxPoints返回旋转矩形的角点的坐标 以便可以通过循环框内的点来访问像素 但是在 Python 中是否有更快的裁剪方法 EDIT See code在
  • 单线程程序中可以有竞争条件吗?

    您可以在here https en wikipedia org wiki Race condition Software关于什么是竞争条件的一个很好的解释 我最近看到很多人对竞争条件和线程做出了令人困惑的陈述 我了解到竞争条件只能发生在线程
  • 了解应用程序在后台时何时收到 Firebase 消息

    我知道这个标题有同样的问题 但不幸的是它没有得到正确的回答 它被接受了 here https stackoverflow com questions 37711082 how to handle notification when app
  • 在 Three.js 中从 Web Worker 加载纹理

    当将大纹理图像应用到网格上一段明显的时间时 Three js 会锁定浏览器的主线程 让我们考虑以下示例 var texLoader new THREE TextureLoader texLoader load someLargeTextur
  • 如何使网页中出现的图标闪烁/闪烁

    几天前我开始研究高级java 我知道太晚了 我被困在使图标 出现在任务栏上 闪烁的特定任务上 这种闪烁应该根据特定条件发生 这意味着可以使用以下方法来实现javascript 我已经搜索了一段时间了 但是有没有办法让图标每隔 1 秒左右出现
  • 理解 JavaScript 的单线程本质

    我一直在阅读 John Resig 的 JavaScript Ninja 的秘密 它解释了 JavaScript 是单线程的 但是 我尝试对此进行测试 但我不确定要从这里删除什么 executing this in browser func
  • 使用 boost::thread 特定的 ptr<>::get() 是否会很慢?有什么解决方法吗?

    我目前正在使用 Valgrind 的 Callgrind 分析一个存在性能问题的应用程序 在查看分析数据时 似乎有 25 的处理时间花费在boost detail get tss data在主要目的是物理模拟和可视化的应用程序中 get t
  • 如何在 JavaFX 中连接可观察列表?

    我所说的串联是指获得一个新列表 该列表侦听所有串联部分的更改 方法的目的是什么FXCollections concat ObservableList
  • Android 为什么这不会抛出错误的线程异常?

    我的印象是视图只能从主线程操作 但是 为什么这不会崩溃 public class MainActivity extends Activity TextView tv Override protected void onCreate Bund
  • 在 Python 中打印守护线程异常

    Python 不会打印守护线程中引发的异常的回溯消息 例如 以下代码创建一个守护线程并在新线程中引发异常 def error raiser raise Exception import threading thread threading
  • Erlang 如何睡觉(晚上?)

    我想在 Erlang 服务器上每隔几个小时运行一次小型清理过程 我知道计时器模块 我在教程中看到一个示例 使用链式计时器 睡眠命令来等待几天后发生的事件 我觉得这很奇怪 我知道 Erlang 进程与其他语言中的进程相比是独一无二的 但是进程
  • JavaFX使节点覆盖父节点边框颜色

    我有一个如下所示的节点 仅使用 css 我希望标签覆盖其父边框颜色 因此标签下方的边框颜色部分变得不可见 我用来制作这个边框的CSS代码 fx border color black fx border width 3 fx border r
  • 如何使用 Perl CGI 脚本提供图像?

    我的 Google fu 让我失望了 如何使用 Perl 提供已生成的图像 Example img src getimage pl getimage pl 里有什么 干得好 usr bin perl w my file inner nav
  • 使用 Glide 库设置图像加载完成后进度条的可见性

    您好 我想要一个图像进度条 该进度条将在图像加载时显示 但当图像加载完成时 我想将其设置为消失 早些时候我为此使用了毕加索库 但我不知道如何将它与 Glide 库一起使用 我知道有一些资源就绪功能 但我不知道如何使用它 谁能帮我 毕加索图书
  • WinForms - 加载表单时如何使用 PaintEventArgs 运行函数?

    我试图理解图形 在 Graphics FromImage 文档中 它有这样的示例 private void FromImageImage PaintEventArgs e Create image Image imageFile Image
  • 如何从 JavaFX 中的另一个控制器类访问 UI 元素?

    我有一个使用 NetBeans 8 编写的 JavaFX Java 8 应用程序 没有SceneBuilder 我的应用程序有一个主窗口 该窗口有自己的 FXML 文件 primary fxml 和自己的控制器类 FXMLPrimaryCo

随机推荐

  • 使用 pandas 将 JSON 输出为 CSV

    我正在尝试转换以下内容 json文件至 csv使用熊猫 输入 json 文件名 my json file json profile set doc type PROFILE key 123 mem list mem num 10001 cu
  • 正确生成带有特殊字符的站点地图 XML

    我有一个程序可以为 Google 网站管理员工具 除其他外 生成 XML 站点地图 GWT 给我提供了某些站点地图的错误 因为 URL 包含字符序列 如 等 站点地图规范说 https www sitemaps org protocol h
  • “interface”关键字是否从 Dart 中删除了?

    只是为了确定 Dart 是否删除了显式定义interface现在赞成通过隐式定义它abstract 我看到它提到Dart 和接口隔离原则 https stackoverflow com questions 20791286 dart and
  • 对列表中的每个 Id 进行多个 RestTemplate 调用

    我需要制作多个RestTemplate要求每个Id in a List
  • 编写指向其实现者的通用接口的便捷方法

    java中是否有一种编写通用接口的方法 以更方便的方式向此类接口的实现者指出 例如我写的接口 public interface Updatable
  • Mysql2::错误(用户'root'@'localhost'访问被拒绝(使用密码:NO)):

    只需在 CentOS 5 服务器 apache passenger 上使用 mysql mysql2 gem 设置一个新的 Rails 3 1 3 应用程序 我已经正确设置了一个数据库和该数据库的用户 并且我已将登录名和信息添加到我的数据库
  • 防止 TextView 中出现不需要的换行

    尽管设置如此 我的文本视图仍在换行文本lines 1 and ellipsise end 除了防止换行手出现带有 的文本省略号之外 我还需要做什么
  • 带 INNER JOIN 的 SQL DELETE

    有2张桌子 spawnlist and npc 我需要从中删除数据spawnlsit npc templateid n idTemplate是唯一 连接 表格的东西 我已经尝试过这个脚本 但它不起作用 我已经尝试过这个 DELETE s F
  • 如何在 unix 中解压 tar.bz 文件?

    我发现大量页面说明如何解压缩 tar bz2 文件 但是如何解压缩 tar bz 文件呢 use the j的选项tar tar xjf path to archive tar bz
  • 调用database.rawQuery时Android SQLiteMisuseException

    我在 Android 应用程序中使用 SQLite 数据库 有时在调用 database rawQuery String sql String SelectionArgs 时会收到 SQLiteMisuseException 这很奇怪 因为
  • 在 Canvas 上绘制两个 3D 字符串?

    我必须在画布上绘制 2 个字符串 字符串必须使用相同坐标第二根弦必须是第一根弦绕 Y 轴旋转 45 度的结果 结果必须如下所示 这是我的代码 Matrix matrix new Matrix matrix canvas getMatrix
  • 创建具有最大行数的表 (ORACLE)

    Oracle建表时有没有办法限制最大行数 如果表有数字键 您可以添加一个检查约束 声明该键不超过特定值 ALTER TABLE turnip ADD CONSTRAINT check turnip id CHECK turnip id lt
  • 如何在 Rust 中模拟特定方法而不是所有方法?

    我在确定目标结构的方法的单元测试时遇到了麻烦 我有一个方法random number根据结构体的属性返回一个随机值 还有另一种方法plus one它获取第一个方法的结果并用它做一些事情 pub struct RngTest pub attr
  • Flutter Google Maps - 根据行驶方向旋转标记

    任何人都可以分享 Flutter 谷歌地图插件的文档 代码示例 我可以在其中根据行驶方向旋转标记 例如 汽车图标 我看到这可以通过旋转标记在本机库上实现 但在 Flutter 中找不到任何旋转标记的选项 我想我们在旋转标记时需要考虑以下几点
  • 匹配 gtksourceview 中的整个字符串

    使用这个简短的 XML 片段在 gtksourceview 中定义字符串
  • XACML 3.0 和多种资源

    我试图弄清楚如何使用 Balana 的 XACML 实现来实现授权机制 WSO2 的权利引擎基于 Balana 当用户请求访问单个资源时 例如 鲍勃想要阅读医疗记录 事情就很简单了 然而 假设鲍勃想要阅读他所有患者的医疗记录 这里的第一个问
  • SQLite 异常:SQLite 忙

    任何人都可以提供有关此错误的任何信息 我正在尝试使用 Objective C 插入表 当我这样做时 我收到错误 SQLite Busy 为什么会发生这种情况 如果在调用 sqlite3 函数时得到错误代码 SQLITE BUSY 这意味着根
  • 使用 VBScript 的 IE8 兼容模式

    是否可以使用 VBScript 设置和检查 IE8 中的兼容模式 根据定义文档兼容性 http msdn microsoft com en us library cc288325 VS 85 aspx文章 有文档 文档模式 http msd
  • 关系数据建模与非关系数据建模

    我有一个用户数据库 每个用户具有以下属性 user id name zip city In a 关系型数据库我会在表格中对其进行建模user user id name 位置 ID 并有第二个表称为location location id z
  • 后台和线程中的 JavaFX 图像加载

    我认为这是一个简单的问题 但我很难找到答案 我有一个与 JavaFX Scene 对象关联的 ImageView 对象 我想从磁盘加载大图像并使用 ImageView 依次显示它们 我一直在尝试找到一种好方法来重复检查 Image 对象 当