0

0

加载 JavaFX 图像并将其保存到数据库

WBOY

WBOY

发布时间:2024-02-22 14:49:06

|

1442人浏览过

|

来源于stackoverflow

转载

javafx是java编程语言的一个图形用户界面工具包,它可以轻松创建丰富、现代化的用户界面。在实际开发中,有时候需要加载javafx图像并将其保存到数据库中。本文将为您介绍如何实现这一操作,通过简单易懂的步骤,帮助您解决这一问题。让我们一起来探讨吧!

问题内容

我现在正在努力将一个小图像保存在数据库中并将其加载以用作 javafx.scene.image.Image。我尝试过的几个解决方案涉及使用 SwingFXUtils.fromFXImage 和 SwingFXUtils.toFxImage,但该类似乎需要 module-info.java 文件中的一个条目,而我什至不打算使用该条目。

我在尝试使用 SwingFXUtils 时遇到此异常:java.lang.NoClassDefFoundError: javafx/embed/swing/SwingFXUtils

当我使用模块系统时,它破坏了我正在使用的另一个库(itextpdf)。 所以我想避免这种情况,只是找到另一种方法来保存和加载数据库中的 JavaFX 图像。 有什么建议吗?

解决方法

您提到:

这不是真的。尽管 javafx 仅支持作为命名模块加载1,但 javafx 并不要求您自己的代码是模块化的。获得 noclassdeffounderror 的唯一方法是在运行时未能将类包含在模块路径/类路径中(它必须在编译时存在,否则您的代码将无法编译)。我建议阅读 Getting Started with JavaFX,了解如何使用主要 java ide 和/或构建工具之一设置基本 javafx 应用程序。但是,如果不知道您如何配置项目以及如何运行项目,我们将无法告诉您您的设置具体出了什么问题。

立即学习Java免费学习笔记(深入)”;

也就是说,您想要完成的总体目标确实是可能的。下面是一个示例,允许您浏览计算机上的图像并将其保存到内存中的 h2 数据库中。图像的 id 和名称被放入 tableview 中,其中包含一个带有“打开”按钮的列,可让您查看从内存数据库加载的图像。图像以 png 格式作为 blob 存储在数据库中,无论其原始格式如何。 swingfxutilsimageio 类用于将 javafx 图像转换为 png“文件”2

该示例未向您展示如何部署应用程序(例如,通过 jpackage)。

版本

以下是我用于构建和运行示例的库和工具的版本。

  • java 21.0.1(eclipse adoptium / temurin)

  • javafx 21.0.1

  • h2 2.2.224

  • gradle 8.4

  • JavaFX Gradle Plugin 0.1.0

commentprevious question2 中,您声明您正在使用 gradle,因此我在示例中使用的是 gradle。

Artbreeder
Artbreeder

创建令人惊叹的插画和艺术

下载

源代码

没有 module-info.java 文件。

imagerecord.java

package com.example;

public record imagerecord(int id, string name) {}

main.java

package com.example;

import java.io.file;
import java.util.concurrent.executor;
import java.util.concurrent.executors;
import java.util.function.consumer;
import javafx.application.application;
import javafx.beans.property.simpleintegerproperty;
import javafx.beans.property.simpleobjectproperty;
import javafx.beans.property.simplestringproperty;
import javafx.concurrent.task;
import javafx.geometry.insets;
import javafx.geometry.pos;
import javafx.scene.scene;
import javafx.scene.control.button;
import javafx.scene.control.scrollpane;
import javafx.scene.control.tablecell;
import javafx.scene.control.tablecolumn;
import javafx.scene.control.tableview;
import javafx.scene.image.image;
import javafx.scene.image.imageview;
import javafx.scene.layout.borderpane;
import javafx.scene.layout.hbox;
import javafx.stage.filechooser;
import javafx.stage.stage;
import javafx.stage.stagestyle;
import javafx.stage.window;

public class main extends application {

  private final executor executor = executors.newvirtualthreadpertaskexecutor();
  private final imagesdatabase db = new imagesdatabase("test");
  private final imagerepository imagerepo = new imagerepository(db);
  private file lastdirectory;

  @override
  public void start(stage primarystage) {
    var table = createtable(record -> displayimage(primarystage, record));

    var choosebtn = new button("choose image...");
    choosebtn.setonaction(
        e -> {
          e.consume();
          var image = chooseimage(primarystage);
          if (image != null) {
            executor.execute(createsaveimagetask(image, table.getitems()::add));
          }
        });

    var root = new borderpane();
    root.settop(choosebtn);
    root.setcenter(table);
    borderpane.setalignment(choosebtn, pos.center);
    borderpane.setmargin(choosebtn, new insets(10));

    primarystage.setscene(new scene(root, 600, 400));
    primarystage.show();
  }

  @override
  public void stop() throws exception {
    db.close();
  }

  private image chooseimage(window owner) {
    var chooser = new filechooser();
    chooser.settitle("choose image file");
    chooser
        .getextensionfilters()
        .add(new filechooser.extensionfilter("image files", "*.jpeg", "*.jpg", "*.png"));
    if (lastdirectory != null) {
      chooser.setinitialdirectory(lastdirectory);
    }

    var file = chooser.showopendialog(owner);
    if (file != null) {
      lastdirectory = file.getparentfile();
      return new image(file.touri().tostring());
    }
    return null;
  }

  private void displayimage(window owner, imagerecord record) {
    var view = new imageview();

    var task = creategetimagetask(record, view::setimage);
    executor.execute(task);

    var sp = new scrollpane(view);
    sp.setpannable(true);

    var window = new stage(stagestyle.utility);
    window.initowner(owner);
    window.settitle(record.name());
    window.setscene(new scene(sp, 500, 300));
    window.setonhiding(e -> task.cancel());
    window.show();
  }

  private tableview createtable(consumer onopen) {
    var table = new tableview();
    table.setcolumnresizepolicy(tableview.constrained_resize_policy_flex_last_column);

    var idcol = new tablecolumn("id");
    idcol.setcellvaluefactory(data -> new simpleintegerproperty(data.getvalue().id()));
    table.getcolumns().add(idcol);

    var namecol = new tablecolumn("name");
    namecol.setcellvaluefactory(data -> new simplestringproperty(data.getvalue().name()));
    table.getcolumns().add(namecol);

    var openbtncol = new tablecolumn();
    openbtncol.setcellvaluefactory(data -> new simpleobjectproperty<>(data.getvalue()));
    openbtncol.setcellfactory(tc -> createopenbuttoncell(onopen));
    table.getcolumns().add(openbtncol);

    return table;
  }

  private tablecell createopenbuttoncell(consumer onopen) {
    return new tablecell<>() {
      final hbox container = new hbox();
      final button openbutton = new button("open");

      {
        container.getchildren().add(openbutton);
        container.setalignment(pos.center);
        openbutton.setonaction(
            e -> {
              e.consume();
              var item = isempty() ? null : getitem();
              if (item != null) {
                onopen.accept(item);
              }
            });
      }

      @override
      protected void updateitem(imagerecord item, boolean empty) {
        super.updateitem(item, empty);
        if (empty || item == null) {
          setgraphic(null);
        } else {
          setgraphic(container);
        }
      }
    };
  }

  private task createsaveimagetask(image image, consumer onsuccess) {
    return new task() {
      @override
      protected imagerecord call() throws exception {
        return imagerepo.insertimage(image);
      }

      @override
      protected void succeeded() {
        onsuccess.accept(getvalue());
      }

      @override
      protected void failed() {
        getexception().printstacktrace();
      }
    };
  }

  private task creategetimagetask(imagerecord record, consumer onsuccess) {
    return new task() {
      @override
      protected image call() throws exception {
        return imagerepo.getimage(record).orelsethrow();
      }

      @override
      protected void succeeded() {
        onsuccess.accept(getvalue());
      }

      @override
      protected void failed() {
        getexception().printstacktrace();
      }
    };
  }
}

imagerepository.java

package com.example;

import static java.sql.statement.return_generated_keys;

import java.io.bytearrayinputstream;
import java.io.bytearrayoutputstream;
import java.io.ioexception;
import java.io.inputstream;
import java.io.uncheckedioexception;
import java.sql.sqlexception;
import java.util.arraylist;
import java.util.list;
import java.util.objects;
import java.util.optional;
import java.util.concurrent.atomic.atomicinteger;
import javafx.embed.swing.swingfxutils;
import javafx.scene.image.image;
import javax.imageio.imageio;

public class imagerepository {

  private static final string select_all_records_sql = "select id, name from images";
  private static final string select_image_sql = "select image from images where id = ?";
  private static final string insert_sql = "insert into images (name, image) values (?, ?)";

  private final atomicinteger generatednamecount = new atomicinteger();
  private final imagesdatabase db;

  public imagerepository(imagesdatabase db) {
    this.db = db;
  }

  public list getrecords() throws sqlexception {
    return db.execute(
        conn -> {
          try (var stat = conn.createstatement()) {
            var result = stat.executequery(select_all_records_sql);

            var records = new arraylist();
            while (result.next()) {
              int id = result.getint(1);
              var name = result.getstring(2);
              records.add(new imagerecord(id, name));
            }
            return records;
          }
        });
  }

  public optional getimage(imagerecord record) throws sqlexception {
    return getimage(record.id());
  }

  public optional getimage(int recordid) throws sqlexception {
    if (recordid <= 0) {
      throw new illegalargumentexception("recordid <= 0: " + recordid);
    }
    return db.execute(
        conn -> {
          try (var stat = conn.preparestatement(select_image_sql)) {
            stat.setint(1, recordid);

            var result = stat.executequery();
            if (result.next()) {
              var image = new image(result.getbinarystream(1));
              return optional.of(image);
            } else {
              return optional.empty();
            }
          }
        });
  }

  public imagerecord insertimage(image image) throws sqlexception {
    objects.requirenonnull(image);
    return db.execute(
        conn -> {
          try (var stat = conn.preparestatement(insert_sql, return_generated_keys)) {
            var name = getimagename(image);

            stat.setstring(1, name);
            stat.setbinarystream(2, imagetoinputstream(image));
            stat.executeupdate();

            var keys = stat.getgeneratedkeys();
            if (keys.next()) {
              int id = keys.getint(1);
              return new imagerecord(id, name);
            } else {
              throw new illegalstateexception("generated key not returned");
            }
          }
        });
  }

  private string getimagename(image image) {
    var source = image.geturl();
    return source == null ? generateimagename() : source;
  }

  private string generateimagename() {
    return "generated image name " + generatednamecount.incrementandget();
  }

  private inputstream imagetoinputstream(image image) {
    var out = new bytearrayoutputstream();
    try {
      imageio.write(swingfxutils.fromfximage(image, null), "png", out);
    } catch (ioexception ex) {
      throw new uncheckedioexception(ex);
    }
    return new bytearrayinputstream(out.tobytearray());
  }
}

imagesdatabase.java

package com.example;

import java.sql.connection;
import java.sql.sqlexception;
import java.util.objects;
import java.util.concurrent.locks.lock;
import java.util.concurrent.locks.reentrantlock;
import javax.sql.datasource;
import org.h2.jdbcx.jdbcdatasource;

public class imagesdatabase implements autocloseable {

  private static final string create_table_sql =
      "create table images (id identity, name varchar(255), image blob)";

  @functionalinterface
  public interface sqlfunction {

    t execute(connection connection) throws sqlexception;
  }

  private final lock mutex = new reentrantlock();

  private final datasource source;
  private connection connection;
  private boolean open = true;
  private boolean initialized;

  public imagesdatabase(string name) {
    if (name.isblank()) {
      throw new illegalargumentexception("blank name");
    }
    var source = new jdbcdatasource();
    source.seturl("jdbc:h2:mem:" + name + ";db_close_delay=-1");
    this.source = source;
  }

  public  t execute(sqlfunction function) throws sqlexception {
    objects.requirenonnull(function);
    mutex.lock();
    try {
      checkopen();
      return function.execute(getoropenconnection());
    } finally {
      mutex.unlock();
    }
  }

  private connection getoropenconnection() throws sqlexception {
    if (connection == null || connection.isclosed()) {
      connection = source.getconnection();
      initialize(connection);
    }
    return connection;
  }

  private void initialize(connection conn) throws sqlexception {
    if (!initialized) {
      try (var stat = conn.createstatement()) {
        stat.executeupdate(create_table_sql);
      }
      initialized = true;
    }
  }

  private void shutdown() throws sqlexception {
    if (initialized) {
      try (var conn = getoropenconnection();
          var stat = conn.createstatement()) {
        stat.execute("shutdown");
      }
      connection = null;
    }
  }

  private void checkopen() {
    if (!open) {
      throw new illegalstateexception("closed");
    }
  }

  @override
  public void close() throws sqlexception {
    mutex.lock();
    try {
      if (open) {
        open = false;
        shutdown();
      }
    } finally {
      mutex.unlock();
    }
  }
}

gradle 文件

我使用了 kotlin dsl,但如果您愿意,您也可以使用 groovy dsl。

settings.gradle.kts

rootproject.name = "h2images-example"

build.gradle.kts

plugins {
    id("org.openjfx.javafxplugin") version "0.1.0"
    application
}

group = "com.example"
version = "1.0"

javafx {
    modules("javafx.controls", "javafx.swing")
    version = "21.0.1"
}

application {
    mainclass.set("com.example.main")
}

repositories {
    mavencentral()
}

dependencies {
    implementation("com.h2database:h2:2.2.224")
}

执行

您可以使用以下命令执行上述内容:

./gradlew run

注意 ./gradlew 调用 Gradle Wrapper。如果您的计算机上安装了 gradle 版本,则可以通过以下方式生成版本 8.4 的包装器:

gradle wrapper --gradle-version 8.4

1. javafx 在技术上不支持从类路径加载。这意味着理想情况下,javafx 模块应该位于模块路径上并解析为命名模块,即使您自己的代码和其他依赖项是从类路径加载的。但是,我不知道如果 javafx 位于类路径上(至少从 javafx 21 开始),会发生什么中断,除了您的主类不能再是 javafx.application 的子类。 application(您需要一个单独的“启动器类”作为主类)。只需要知道,由于 javafx 位于类路径上而导致的任何问题都不太可能被 javafx 团队修复。

请注意,openjfx 提供的 gradle 和 maven 插件会配置这些构建工具以将 javafx 放在模块路径上。

2. 根据您的两个问题的上下文,该示例将 image 对象转换为 png 字节。但是,如果您已经以字节形式接收图像(即作为本地或远程文件),那么将这些字节直接放入数据库可能会更容易、更高效。

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

832

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

738

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

734

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

397

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

398

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

446

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

430

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

16925

2023.08.03

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

36

2026.01.14

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号