2015-01-25 1 views
0

Я создаю файл fxml в javafx2.OutOfMemoryError и проблемы с ObservableList в ComboBox

У меня есть список объектов 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);     
} 

Он работает нормально, но после нескольких пут изображений виртуальная машина дает мне ниже сообщение об ошибке:

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

Эта ошибка происходит из строки кода image1 = new Image("file:"+currentEntry.getIcon());

Наконец, я хочу поместить все элементы myObservableList в элементы ComboBox. По этой причине в методе Initialize контроллера Java Я пишу:

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, и я не знаю, как я должен обращаться за меня выпадающий с парами значок и текст в одной ячейке для всех элементов.

Я хочу выразить благодарность Питеру Дунихо и ПаккуДон за помощь в улучшении английского языка в моем тексте.

+0

Сколько предметов (приблизительно) в списке? Насколько велики, в среднем, изображения? –

+0

Список получает загрузку с базы данных. У меня есть таблица «Человек» с 8 столбцами.Из этого я прочитал только 2 столбца, имя и имя файла (значка человека). Может быть примерно 200 человек имен и значков. Все это должно загружаться в поле со списком. Каждый значок составляет около 70Kb или 100kb. Я не знаю, как я справляюсь с этим. – Farmer

ответ

2

Это почти всегда ошибка использования класса Node в качестве типа данных для ComboBox (или для любого другого элемента управления). Вы должны использовать класс, который представляет только данные, и зарегистрировать фабрику ячеек, чтобы настроить способ отображения данных.

В вашем случае, если вы включаете изображение в данные, вы, вероятно, столкнетесь с проблемами памяти. Каждое изображение, вероятно, будет представлено в памяти на несколько мегабайт. Поэтому ваш класс данных должен содержать имя изображения, а затем вы можете использовать ячейку в поле со списком для создания изображения.

Вот некоторые примеры кода, чтобы дать вам идею:

класса Data (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); 
       } 
      } 
     }; 
    } 
}); 

You может использовать ту же самую реализацию ListCell для ComboBox's buttonCell.

Дело в том, что ячейки создаются только для видимых ячеек, поэтому изображения загружаются «по требованию» при отображении ячеек. Использование конструктора Image, который принимает параметры ширины и высоты, также уменьшает площадь памяти, так как объект Image может изменять размер при загрузке.

Наконец, обратите внимание на то, что для загрузки изображений в фоновом режиме важно использовать флаг, который обеспечивает отзывчивость пользовательского интерфейса. Если вы быстро прокрутите страницу, вы, скорее всего, увидите некоторые изображения, которые не загружаются в течение короткого времени; ячейки будут перерисовываться соответствующим образом после того, как изображение станет доступным.

+0

дорогой James_D, Большое спасибо за ваш ответ очень полезно для меня. Я использую Java 7 и свою линию: comboBox.setCellFactory (ListView -> новый ListCell () { для Java 8. Если вы, пожалуйста, чтобы переписать для Java 7 – Farmer

+0

Вы просто должны преобразовать лямбда? к классу «Обратный звонок» (например, анонимный внутренний класс). Я отредактировал в строке, я думаю, что это правильно, но вы можете исправить какие-либо опечатки отсюда. –

+0

Вы очень быстрый и мощный человек. Действительно благодарю вас для вашей добросердечной помощи. – Farmer

Смежные вопросы