OutOfMemoryError和ObservableList到ComboBox的问题

时间:2015-01-25 01:30:43

标签: 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控制器的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表示非常感谢,感谢他们帮助我提高英语水平。

1 个答案:

答案 0 :(得分:2)

使用Node类作为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 ;
    }
}

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实施。

这里的要点是,仅为可见单元格创建单元格,因此可以根据需要加载图像&#34;显示细胞。使用带有width和height参数的Image构造函数也会减少内存占用,因为Image对象可以在加载时调整大小。

最后,请注意,使用该标志在后台加载图片非常重要,这样可以保持UI的响应速度。如果您快速滚动,您可能会看到一些图片未加载一段时间;一旦图像可用,细胞将重新适当重新印刷。