JavaFX ist ein grafisches Benutzeroberflächen-Toolkit für die Programmiersprache Java, mit dem sich auf einfache Weise umfangreiche, moderne Benutzeroberflächen erstellen lassen. In der tatsächlichen Entwicklung ist es manchmal erforderlich, JavaFX-Bilder zu laden und in der Datenbank zu speichern. Dieser Artikel stellt Ihnen die Vorgehensweise vor und hilft Ihnen, dieses Problem durch einfache und leicht verständliche Schritte zu lösen. Lassen Sie uns gemeinsam darüber diskutieren!
Ich versuche gerade, ein kleines Bild in einer Datenbank zu speichern und es zu laden, um es als javafx.scene.image.Image zu verwenden. Einige Lösungen, die ich ausprobiert habe, beinhalten die Verwendung von SwingFXUtils.fromFXImage und SwingFXUtils.toFxImage, aber diese Klasse scheint einen Eintrag in der Datei module-info.java zu erfordern, den ich gar nicht zu verwenden versuche.
Beim Versuch, SwingFXUtils zu verwenden, ist diese Ausnahme aufgetreten: java.lang.NoClassDefFoundError: javafx/embed/swing/SwingFXUtils
.
Als ich das Modulsystem verwendet habe, hat es eine andere Bibliothek, die ich verwendet habe, kaputt gemacht (itextpdf). Deshalb möchte ich dies vermeiden und einfach eine andere Möglichkeit finden, JavaFX-Bilder aus der Datenbank zu speichern und zu laden. Irgendwelche Vorschläge?
Sie haben erwähnt:
Das ist nicht wahr. Obwohl Javafx nur das Laden von 1 als benannte Module unterstützt, erfordert Javafx nicht, dass Ihr eigener Code modular ist. Die einzige Möglichkeit, zu erhalten, besteht darin, die Klasse zur Laufzeit nicht in den Modulpfad/Klassenpfad aufzunehmen (sie muss zur Kompilierungszeit vorhanden sein, sonst wird Ihr Code nicht kompiliert). Ich empfehle die Lektüre von „Erste Schritte mit JavaFX“, um zu erfahren, wie man eine einfache JavaFX-Anwendung mit einer der wichtigsten Java-IDEs und/oder Build-Tools einrichtet. Ohne zu wissen, wie Sie Ihr Projekt konfigurieren und ausführen, können wir Ihnen jedoch nicht sagen, was genau mit Ihrem Setup nicht stimmt.
Das heißt, das Gesamtziel, das Sie erreichen möchten, ist tatsächlich möglich. Unten finden Sie ein Beispiel, mit dem Sie auf Ihrem Computer nach Bildern suchen und diese in einer speicherinternen h2-Datenbank speichern können. Die ID und der Name des Bildes werden in die Klasse eingefügt, die zum Konvertieren von JavaFX-Bildern in PNG-„Dateien“ noclassdeffounderror
2
tableview
中,其中包含一个带有“打开”按钮的列,可让您查看从内存数据库加载的图像。图像以 png 格式作为 blob 存储在数据库中,无论其原始格式如何。 swingfxutils
和 imageio
Das Beispiel zeigt Ihnen nicht, wie Sie die Anwendung bereitstellen (z. B. über ).
Version
jpackage
0.1.0
Im Kommentar zur
vorherigen Frage2 haben Sie angegeben, dass Sie Gradle verwenden, daher verwende ich Gradle im Beispiel. Quellcode Keine Datei.
package com.example; public record imagerecord(int id, string name) {}
module-info.java
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();
}
};
}
}
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());
}
}
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();
}
}
}
Gradle-Datei
Ich habe Kotlin DSL verwendet, aber Sie können auch Groovy DSL verwenden, wenn Sie möchten.
settings.gradle.ktsrootproject.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")
}
Ausführen
Sie können das Obige mit dem folgenden Befehl ausführen:
./gradlew run
Hinweis
gradle wrapper --gradle-version 8.4, wenn sich Javafx im Klassenpfad befindet (zumindest ab Javafx 21), außer dass Ihre Hauptklasse nicht mehr sein kann
(Sie benötigen eine separate „Launcher-Klasse“ als Hauptklasse ). Beachten Sie jedoch, dass Probleme, die dadurch verursacht werden, dass sich Javafx im Klassenpfad befindet, wahrscheinlich nicht vom Javafx-Team behoben werden können.
Bitte beachten Sie, dass die von openjfx bereitgestellten Gradle- und Maven-Plugins diese Build-Tools so konfigurieren, dass Javafx in den Modulpfad eingefügt wird. 2. Basierend auf dem Kontext Ihrer beiden Fragen konvertiert dieses Beispiel javafx.application 的子类。 application
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.
Das obige ist der detaillierte Inhalt vonLaden Sie JavaFX-Bilder und speichern Sie sie in der Datenbank. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!