java - OutOfMemoryError 和 ObservableList 进入 ComboBox 的问题

标签 java javafx observablelist

我在javafx2中制作了一个fxml文件。

我有一个 Person 对象列表。该列表的名称是Entries。我有一个 ObservableList,myObservableList。我想在其中贴上标签。每个标签必须包含一对人物图像和他的名字的文本。 我写了这段代码:

for (int i=0; i<numberOfEntries; i++){                               
    currentEntry = Entries.get(i);
    name=currentEntry.getName();                                  
    image1 = new Image("file:"+currentEntry.getIcon());                    
    imageView1= new ImageView();
    imageView1.setFitHeight(50);
    imageView1.setFitWidth(70);
    imageView1.setImage(image1);                       
    label = new Label(name, imageView1);
    label.setFont(new Font("serif", 32));                         
    myObservableList.add(label);                   
}

它工作正常,但是在放置了几次图像之后,JVM 给出了以下错误消息:

Caused by: java.lang.OutOfMemoryError: Java heap space.

此错误来自代码行image1 = new Image("file:"+currentEntry.getIcon());

最后,我想将 myObservableList 的所有元素放入 ComboBox 项目中。为此,我在 java Controller 的 Initialize 方法中写道:

    myComboBox.setItems(myObservableList);

    ListCell<Label> buttonCell = new ListCell<Label>() {
         @Override protected void updateItem(Label item, boolean isEmpty) {
         super.updateItem(item, isEmpty);
            setText(item==null ? "" : item.getText());                 
        }
    };

    myComboBox.setButtonCell(buttonCell);

我确信我在 javafx 方面没有足够的经验,并且我不知道我必须如何处理,因为我有一个组合框,其中所有项目的同一单元格中都有成对的图标和文本。

我要向 Peter Duniho 和 PakkuDon 表示衷心的感谢,他们帮助我提高了文本中的英语水平。

最佳答案

使用 Node 几乎总是错误的class 作为 ComboBox 的数据类型(或任何其他控制)。您应该使用仅代表数据的类,并注册一个单元工厂来配置数据的显示方式。

就您而言,如果将图像包含在数据中,则可能会遇到内存问题。每个图像在内存中可能由几兆字节表示。因此,您的数据类应该保存图像名称,然后您可以使用组合框中的单元格来创建图像。

这里有一些示例代码可以让您了解:

数据类(Person.java):

public class Person {
    private final String name ;
    private final String imageFileName ;

    public Person(String name, String imageFileName) {
        this.name = name ;
        this.imageFileName = imageFileName ;
    }

    public String getName() {
        return name ;
    }

    public String getImageFileName() {
        return imageFileName ;
    }
}

创建 UI 代码 ComboBox来自List<Person> :

List<Person> entries = ... ; // populated from DB

ComboBox<Person> comboBox = new ComboBox<>();
comboBox.getItems().addAll(entries);

comboBox.setCellFactory(new Callback<ListView<Person>, ListCell<Person>>() {
    @Override
    public ListCell<Person> call(ListView<Person> listCell) {

        return new ListCell<Person>() {
            private final ImageView = new ImageView();
            @Override
            public void updateItem(Person person, boolean empty) {
                super.updateItem(person, empty);
                if (empty) {
                    setText(null);
                    setGraphic(null);
                } else {
                    File imageFile = new File(person.getImageFileName());
                    String imageUrl = imageFile.toURI().toURL().toExternalForm();
                    Image image = new Image(imageUrl, 70, 50, 
                        // preserve ratio
                        true, 
                        // smooth resizing
                        true,
                        // load in background
                        true);
                    imageView.setImage(image);
                    setText(person.getName());
                    setGraphic(imageView);
                }
            }
        };
    }
});

您可以使用相同的 ListCell ComboBox 的实现的buttonCell .

这里的要点是,单元格仅为可见单元格创建,因此图像在显示单元格时“按需”加载。使用Image采用宽度和高度参数的构造函数也减少了内存占用,如 Image对象可以在加载时调整大小。

最后,请注意,使用该标志在后台加载图像非常重要,这可以保持 UI 的响应能力。如果您快速滚动,您可能会看到一些图像暂时未加载;一旦图像可用,单元格将适本地重新绘制。

关于java - OutOfMemoryError 和 ObservableList 进入 ComboBox 的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28132266/

相关文章:

java - 如何将 Int 转换为无符号字节并返回

java - 代码厨师 : Runtime Error (NZEC)

transactions - 具有事务支持的 JavaFX TableView

java - Java FX 中的 Android 适配器替代方案

java - 将表单参数从 JSP 发送到 Struts 操作类

java - 如何使用 Java 获取日志并在 Web 上显示它们(基本 Java)

Javafx,有没有办法检查按钮的状态并根据其状态执行 if 语句?

java - 如何强制Java FX场景刷新?

JavaFX ScrollPane - 检查显示哪些组件