Table des matières
Contenu de la question
Solution
Voici les versions des bibliothèques et des outils que j'ai utilisés pour créer et exécuter les exemples.
Pas de
J'ai utilisé Kotlin DSL, mais vous pouvez également utiliser groovy DSL si vous préférez.
Vous pouvez exécuter ce qui précède en utilisant la commande suivante :
Maison Java Chargez les images JavaFX et enregistrez-les dans la base de données

Chargez les images JavaFX et enregistrez-les dans la base de données

Feb 22, 2024 pm 02:49 PM
overflow

JavaFX est une boîte à outils d'interface utilisateur graphique pour le langage de programmation Java qui facilite la création d'interfaces utilisateur riches et modernes. Dans le développement réel, il est parfois nécessaire de charger des images JavaFX et de les enregistrer dans la base de données. Cet article vous expliquera comment procéder et vous aidera à résoudre ce problème grâce à des étapes simples et faciles à comprendre. Discutons-en ensemble !

Contenu de la question

J'essaie actuellement de sauvegarder une petite image dans une base de données et de la charger pour qu'elle soit utilisée comme javafx.scene.image.Image. Quelques solutions que j'ai essayées impliquent l'utilisation de SwingFXUtils.fromFXImage et SwingFXUtils.toFxImage, mais cette classe semble nécessiter une entrée dans le fichier module-info.java que je n'essaie même pas d'utiliser.

J'ai rencontré cette exception en essayant d'utiliser SwingFXUtils : java.lang.NoClassDefFoundError: javafx/embed/swing/SwingFXUtils.

Lorsque j'ai utilisé le système de modules, cela a cassé une autre bibliothèque que j'utilisais (itextpdf). Je veux donc éviter cela et simplement trouver un autre moyen de sauvegarder et de charger des images JavaFX à partir de la base de données. Aucune suggestion?

Solution

Vous avez mentionné :

Ce n'est pas vrai. Bien que javafx ne prenne en charge que le chargement de 1 en tant que modules nommés, javafx n'exige pas que votre propre code soit modulaire. La seule façon d'obtenir est de ne pas inclure la classe dans le chemin du module/chemin de classe au moment de l'exécution (elle doit être présente au moment de la compilation, sinon votre code ne sera pas compilé). Je recommande de lire Getting Started with JavaFXnoclassdeffounderror pour apprendre à configurer une application javafx de base à l'aide de l'un des principaux IDE Java et/ou outils de construction. Cependant, sans savoir comment vous configurez votre projet et l'exécutez, nous ne serons pas en mesure de vous dire exactement ce qui ne va pas avec votre configuration. Cela dit, l’objectif global que vous souhaitez atteindre est bel et bien possible. Vous trouverez ci-dessous un exemple qui vous permet de rechercher des images sur votre ordinateur et de les enregistrer dans une base de données h2 en mémoire. L'identifiant et le nom de l'image sont placés dans la classe

utilisée pour convertir les images javafx en "fichiers" png

tableview 中,其中包含一个带有“打开”按钮的列,可让您查看从内存数据库加载的图像。图像以 png 格式作为 blob 存储在数据库中,无论其原始格式如何。 swingfxutilsimageio2. L'exemple ne vous montre pas comment déployer l'application (par exemple via

).

jpackageVersion

Voici les versions des bibliothèques et des outils que j'ai utilisés pour créer et exécuter les exemples.

    java 21.0.1 (éclipse adoptium/temurin)
  • javafx 21.0.1
  • h2 2.2.224
  • grade 8.4
  • Plugin JavaFX Gradle

    0.1.0

  • Dans
commentaire

à la question précédente2, vous avez déclaré que vous utilisiez gradle, j'utilise donc gradle dans l'exemple. Code source

Pas de

fichier.

module-info.java

imagerecord.java

package com.example;

public record imagerecord(int id, string name) {}
Copier après la connexion

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<imagerecord> createtable(consumer<imagerecord> onopen) {
    var table = new tableview<imagerecord>();
    table.setcolumnresizepolicy(tableview.constrained_resize_policy_flex_last_column);

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

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

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

    return table;
  }

  private tablecell<imagerecord, imagerecord> createopenbuttoncell(consumer<imagerecord> 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<imagerecord> onsuccess) {
    return new task<imagerecord>() {
      @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<image> onsuccess) {
    return new task<image>() {
      @override
      protected image call() throws exception {
        return imagerepo.getimage(record).orelsethrow();
      }

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

      @override
      protected void failed() {
        getexception().printstacktrace();
      }
    };
  }
}
Copier après la connexion

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<imagerecord> getrecords() throws sqlexception {
    return db.execute(
        conn -> {
          try (var stat = conn.createstatement()) {
            var result = stat.executequery(select_all_records_sql);

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

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

  public optional<image> 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());
  }
}
Copier après la connexion

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> {

    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> t execute(sqlfunction<t> 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();
    }
  }
}
Copier après la connexion
fichier de graduation

J'ai utilisé Kotlin DSL, mais vous pouvez également utiliser groovy DSL si vous préférez.

settings.gradle.kts

rootproject.name = "h2images-example"
Copier après la connexion

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")
}
Copier après la connexion
Exécuter

Vous pouvez exécuter ce qui précède en utilisant la commande suivante :

./gradlew run
Copier après la connexion

Note

appelle le

Gradle Wrapper./gradlew. Si vous avez une version Gradle installée sur votre machine, vous pouvez générer un wrapper pour la version 8.4 via :

1. javafx ne prend pas techniquement en charge le chargement à partir du chemin de classe. Cela signifie qu'idéalement, le module javafx devrait se trouver sur le chemin du module et se résoudre en un module nommé, même si votre propre code et d'autres dépendances sont chargés à partir du chemin de classe. Cependant, je ne sais pas ce qui se passe breaks si javafx est sur le chemin de classe (au moins à partir de javafx 21), sauf que votre classe principale ne peut plus l'être (vous avez besoin d'une "classe de lancement" distincte comme classe principale ) . Sachez simplement qu'il est peu probable que les problèmes causés par la présence de javafx sur le chemin de classe soient résolus par l'équipe javafx. javafx.application 的子类。 application

Veuillez noter que les plugins gradle et maven fournis par openjfx configurent ces outils de construction pour mettre javafx sur le chemin du module.

2. Basierend auf dem Kontext Ihrer beiden Fragen konvertiert dieses Beispiel image Objekte in PNG-Bytes. Wenn Sie das Bild jedoch bereits in Bytes erhalten (d. h. als lokale oder Remote-Datei), ist es möglicherweise einfacher und effizienter, diese Bytes direkt in die Datenbank zu übertragen.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Comment réparer l'audio si vous n'entendez personne
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Où trouver la courte de la grue à atomide atomique
1 Il y a quelques semaines By DDD

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Le prix du Bitcoin depuis sa naissance 2009-2025 Le résumé le plus complet des prix historiques du BTC Le prix du Bitcoin depuis sa naissance 2009-2025 Le résumé le plus complet des prix historiques du BTC Jan 15, 2025 pm 08:11 PM

Depuis sa création en 2009, Bitcoin est devenu un leader dans le monde des cryptomonnaies et son prix a connu d’énormes fluctuations. Pour fournir un aperçu historique complet, cet article compile les données sur les prix du Bitcoin de 2009 à 2025, couvrant les principaux événements du marché, les changements de sentiment du marché et les facteurs importants influençant les mouvements de prix.

Aperçu du prix historique du Bitcoin depuis sa naissance. Collection complète des tendances historiques des prix du Bitcoin. Aperçu du prix historique du Bitcoin depuis sa naissance. Collection complète des tendances historiques des prix du Bitcoin. Jan 15, 2025 pm 08:14 PM

Le Bitcoin, en tant que crypto-monnaie, a connu une volatilité importante sur le marché depuis sa création. Cet article fournira un aperçu du prix historique du Bitcoin depuis sa naissance pour aider les lecteurs à comprendre ses tendances de prix et ses moments clés. En analysant les données historiques sur les prix du Bitcoin, nous pouvons comprendre l'évaluation de sa valeur par le marché, les facteurs affectant ses fluctuations et fournir une base pour les décisions d'investissement futures.

Une liste des prix historiques depuis la naissance du tableau des tendances des prix historiques Bitcoin BTC (dernier résumé) Une liste des prix historiques depuis la naissance du tableau des tendances des prix historiques Bitcoin BTC (dernier résumé) Feb 11, 2025 pm 11:36 PM

Depuis sa création en 2009, le prix de Bitcoin a connu plusieurs fluctuations majeures, passant à 69 044,77 $ en novembre 2021 et tombant à 3191,22 $ en décembre 2018. En décembre 2024, le dernier prix a dépassé 100 204 $.

Le dernier prix du bitcoin en 2018-2024 USD Le dernier prix du bitcoin en 2018-2024 USD Feb 15, 2025 pm 07:12 PM

Prix ​​USD Bitcoin en temps réel Facteurs qui affectent le prix du bitcoin Indicateurs pour prédire les prix des futurs bitcoins Voici quelques informations clés sur le prix du bitcoin en 2018-2024:

Le résumé le plus complet des détails des prix historiques depuis la naissance de Bitcoin (la dernière version en 2025) Le résumé le plus complet des détails des prix historiques depuis la naissance de Bitcoin (la dernière version en 2025) Feb 15, 2025 pm 06:45 PM

Nœud important pour le prix historique du Bitcoin 3 janvier 2009: Genesis Block a été généré, le premier Bitcoin a été généré, avec une valeur de 0 USD. 5 octobre: ​​La première transaction Bitcoin, un programmeur a acheté deux pizzas avec 10 000 Bitcoins, ce qui équivaut à 0,008 $. 9 février 2010: Le Mt. Gox Exchange est allé en ligne et est devenu la plate-forme principale du commerce du bitcoin précoce. 22 mai: Bitcoin percède 1 $ pour la première fois. 17 juillet: le prix du bitcoin a plongé à 0,008 $, atteignant un creux historique. 9 février 2011: Le prix du bitcoin perdra 10 $ pour la première fois. 10 avril: Mt. Go

À l'ère Chatgpt, comment la communauté technique des questions et réponses peut-elle répondre aux défis? À l'ère Chatgpt, comment la communauté technique des questions et réponses peut-elle répondre aux défis? Apr 01, 2025 pm 11:51 PM

La communauté technique de questions-réponses à l'ère Chatgpt: Stratégie de réponse de SegmentFault StackOverflow ...

Dans un article, découvrez: quel est le taux de fonds de monnaie virtuel et comment utiliser le taux de fonds pour négocier Dans un article, découvrez: quel est le taux de fonds de monnaie virtuel et comment utiliser le taux de fonds pour négocier Feb 15, 2025 pm 10:06 PM

Les taux de financement de monnaie virtuelle sont des frais facturés aux commerçants occupant des postes dans le commerce des dérivés. Il reflète une prime ou une remise entre le prix du marché au comptant et le prix du contrat à terme lorsque le contrat expire. Lorsque le prix au comptant est plus élevé que le prix à terme, le taux de capital est négatif, ce qui signifie que les commerçants qui sont à court terme paient des frais aux commerçants qui se positionnent longtemps. Au contraire, lorsque le prix au comptant est inférieur au prix à terme, le taux de capital est positif, ce qui signifie que les commerçants qui font des postes à long terme paient des frais aux commerçants qui font des positions courtes.

Comment utiliser l'attribut Clip-Path de CSS pour réaliser l'effet de courbe à 45 degrés du segmenter? Comment utiliser l'attribut Clip-Path de CSS pour réaliser l'effet de courbe à 45 degrés du segmenter? Apr 04, 2025 pm 11:45 PM

Comment réaliser l'effet de courbe à 45 degrés du segmenter? Dans le processus de mise en œuvre du segmentant, comment faire transformer la bordure droite en une courbe de 45 degrés lorsque vous cliquez sur le bouton gauche, et le point ...