0

我在 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 帮助我提高文本中的英语水平。

4

1 回答 1

2

Node使用类作为 a 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从 a创建的 UI 代码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);
                }
            }
        };
    }
});

您可以对's使用相同的ListCell实现。ComboBoxbuttonCell

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

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

于 2015-01-26T13:42:17.427 回答