我正在尝试使用JavaFX使用存储在Sqlite数据库中的图像填充tableView单元格。我在这里找到了一些非常好的信息,感觉我已经非常接近了。如果没有图像,我希望它保持约束,使细胞总是相同的大小。存储在数据库中的图像是300x300,但行将小得多。到目前为止,我的代码是:
public void buildDataAseptic(){
listNum = 1;
data = FXCollections.observableArrayList();
try{
String SQL = "Select * from aseptic_parts_list"; //Order By id
ResultSet rs = con.createStatement().executeQuery(SQL);
while(rs.next()){
Part cm = new Part();
cm.id.set(listNum++);
if (rs.getBlob("image") != null ) {
Blob blob = rs.getBlob("image");
byte[] ndata = blob.getBytes(1, (int) blob.length());
image = new Image(new ByteArrayInputStream(ndata));
ImageView imageView = new ImageView();
imageView.setImage(image);
imageView.setFitWidth(70);
imageView.setFitHeight(80);
cm.image.set(image);
}
cm.vendor_part_number.set(rs.getString("vendor_part_number"));
cm.description.set(rs.getString("description"));
cm.quantity.set(rs.getInt("quantity"));
cm.vendor_name.set(rs.getString("vendor_name"));
cm.model_number.set(rs.getString("model_number"));
cm.equipment_id.set(rs.getString("equipment_id"));
data.add(cm);
}
tableView.setItems(data);
}
catch(Exception e){
e.printStackTrace();
System.out.println("Error on Building Data" + e.getMessage());
}
filterData();
//filterEquipIDData();
}
这只是从comboBox调用的一个特定方法。除了图像之外,所有其他数据都在表中填充。在initialize()方法中,我将列设置为:
assert tableView != null;
idCol.setCellValueFactory(
new PropertyValueFactory<Part, Integer>("id"));
imgCol.setCellValueFactory(
new PropertyValueFactory<Object,ImageView>("image"));
pnCol.setCellValueFactory(
new PropertyValueFactory<Part,String>("vendor_part_number"));
descCol.setCellValueFactory(
new PropertyValueFactory<Part,String>("description"));
quantityCol.setCellValueFactory(
new PropertyValueFactory<Part,Integer>("quantity"));
venCol.setCellValueFactory(
new PropertyValueFactory<Part,String>("vendor_name"));
mnCol.setCellValueFactory(
new PropertyValueFactory<Part,String>("model_number"));
equipmentIDCol.setCellValueFactory(
new PropertyValueFactory<Part,String>("equipment_id"));
存储图像对象的Part类是:
public SimpleObjectProperty<Image> image = new SimpleObjectProperty<>();
public Object getImage() {
return image.get();
}
我已经在这几天摆弄这个并感觉非常接近,只是没有雪茄,请帮助和谢谢!
答案 0 :(得分:1)
以下是使用图像填充TableView单元格的示例。
解决方案的关键是适当地设置单元格值工厂和单元格工厂:
TableColumn<Fish, Image> imageColumn = new TableColumn<>("Picture");
imageColumn.setCellValueFactory(new PropertyValueFactory<>("image"));
imageColumn.setCellFactory(param -> new ImageTableCell<>());
ImageTableCell类包含ImageView作为单元格的图形,并在底层图像数据更改时更新ImageView:
private class ImageTableCell<S> extends TableCell<S, Image> {
final ImageView imageView = new ImageView();
ImageTableCell() {
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
@Override
protected void updateItem(Image item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
imageView.setImage(null);
setText(null);
setGraphic(null);
}
imageView.setImage(item);
setGraphic(imageView);
}
}
有关此实现的一点需要注意的是,它假定所有图像都已加载到表的基础数据结构中。这意味着如果表中有很多行,则会占用大量数据,因为所有图像都会加载到内存中。另一种解决方案是基础数据结构只是存储图像的地址(url)而不是图像数据本身,然后在单元工厂中加载图像(可能通过LRU缓存机制)。不同方法之间的权衡取决于GUI的操作速度和用户交互时消耗的资源(这是所有内存中方法优化的方式),而不是较慢的GUI但减少了内存占用(这就是在updateItem调用中动态加载图像将优化)。一般来说,我觉得最好尽量保持updateItem调用的速度,这就是解决方案按原样显示的原因。
我不会提供同样集成SQLLite的示例,因为我对该技术一无所知,因此解决方案与数据库系统的进一步集成由读者完成。
完整代码
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.image.*;
import javafx.stage.Stage;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class ImageTable extends Application {
@Override
public void start(Stage stage) {
List<Fish> fish = Arrays.stream(fishData)
.map(data -> new Fish(data[0], new Image(data[1])))
.collect(Collectors.toList());
TableView<Fish> tableView = new TableView<>(FXCollections.observableList(fish));
TableColumn<Fish, String> nameColumn = new TableColumn<>("Name");
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
tableView.getColumns().add(nameColumn);
TableColumn<Fish, Image> imageColumn = new TableColumn<>("Picture");
imageColumn.setCellValueFactory(new PropertyValueFactory<>("image"));
imageColumn.setCellFactory(param -> new ImageTableCell<>());
tableView.getColumns().add(imageColumn);
stage.setScene(new Scene(tableView));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
// image license: linkware - backlink to http://www.fasticon.com
private static final String[][] fishData = {
{ "Blue Fish", "http://icons.iconarchive.com/icons/fasticon/fish-toys/128/Blue-Fish-icon.png" },
{ "Red Fish", "http://icons.iconarchive.com/icons/fasticon/fish-toys/128/Red-Fish-icon.png" },
{ "Yellow Fish", "http://icons.iconarchive.com/icons/fasticon/fish-toys/128/Yellow-Fish-icon.png" },
{ "Green FIsh", "http://icons.iconarchive.com/icons/fasticon/fish-toys/128/Green-Fish-icon.png" }
};
private class ImageTableCell<S> extends TableCell<S, Image> {
final ImageView imageView = new ImageView();
ImageTableCell() {
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
@Override
protected void updateItem(Image item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
imageView.setImage(null);
setText(null);
setGraphic(null);
}
imageView.setImage(item);
setGraphic(imageView);
}
}
public static final class Fish {
private ReadOnlyStringWrapper name;
private ReadOnlyObjectWrapper<Image> image;
public Fish(String name, Image image) {
this.name = new ReadOnlyStringWrapper(name);
this.image = new ReadOnlyObjectWrapper<>(image);
}
public String getName() {
return name.get();
}
public ReadOnlyStringProperty nameProperty() {
return name.getReadOnlyProperty();
}
public Image getImage() {
return image.get();
}
public ReadOnlyObjectProperty<Image> imageProperty() {
return image.getReadOnlyProperty();
}
}
}
答案 1 :(得分:0)
非常感谢jewelsea!我最后做了你说的,创建另一个文件夹来保存图像,并使用网址引用文件夹中的图片。我使用的代码是:
if(rs.getString("image") != null) {
Image img = new Image(rs.getString("image"));
ImageView imageView = new ImageView();
imageView.setImage(img);
cm.image.set(imageView);
imageView.setFitWidth(130);
imageView.setFitHeight(100);
} else {
Image img = new Image("/img/NoImageFound.png");
ImageView imageView = new ImageView();
imageView.setImage(img);
cm.image.set(imageView);
imageView.setFitWidth(130);
imageView.setFitHeight(100);
}
此代码在数据库中查询图像,如果没有,则使用我为未找到图像创建的图像。我之所以这样做是因为它将我的数据库结果缩短为只有具有图像的查询,否则现在显示数据库中的所有结果。很高兴知道这将使它更快。我正在为我的工作构建一个零件数据库,用于过滤零件的监听器,一旦数据库变得非常大,将所有零件直接存储在数据库上,这可能太慢了。你的帮助让我朝着正确的方向前进,感谢百万!