2014-11-24 4 views
1

Я делаю чат-приложение с использованием JavaFX для графического интерфейса. Я показываю содержимое чата в ListView, но у меня одна большая проблема - это очень медленно. Когда я добавляю новые элементы в список и особенно когда я просматриваю список вверх/вниз. Я думаю, возможно, это связано с тем, что список обновляет itsellf каждый раз, когда добавляется новый элемент (каждая ячейка в списке!), А также обновляется каждый раз, когда я просматриваю вверх/вниз. Кто-нибудь знает, что я могу сделать для решения этой проблемы? TNXJavaFX ListView очень медленный

Я переопределить updateItem ListCell в:

chatListView.setCellFactory (новый обратный вызов, ListCell>() { @Override ListCell вызов общественности (ListView р) { ListCell клетка = новый ListCell() { @Override защищен недействительным updateItem (UserInfo пункт, булево млрд) { super.updateItem (пункт, млрд);

    if (item != null) { 
         BorderPane borderPane = new BorderPane(); 
         ImageView profileImage = new ImageView(new Image(item.getImageURL())); 
         profileImage.setFitHeight(32); 
         profileImage.setFitWidth(32); 

         Rectangle clip = new Rectangle(
           profileImage.getFitWidth(), profileImage.getFitHeight() 
         ); 
         clip.setArcWidth(30); 
         clip.setArcHeight(30); 
         profileImage.setClip(clip); 
         SnapshotParameters parameters = new SnapshotParameters(); 
         parameters.setFill(Color.TRANSPARENT); 
         WritableImage image = profileImage.snapshot(parameters, null); 
         profileImage.setClip(null); 
         profileImage.setImage(image); 

         ImageView arrowImage = new ImageView(new Image("arrow1.png")); 
         ImageView arrowImage2 = new ImageView(new Image("arrow1.png")); 
         Label nameLabel = new Label(item.getUserName()); 
         nameLabel.setStyle(" -fx-text-alignment: center; -fx-padding: 2;"); 

         HBox hbox = null; 
         Label textLabel = new Label(); 
         String messageText = splitTolines(item.getMessage()); 
         textLabel.setText(messageText); 
         textLabel.setStyle("-fx-background-color: #a1f2cd; " 
           + "-fx-padding: 10;\n" 
           + "-fx-spacing: 5;"); 
         hbox = new HBox(arrowImage, textLabel); 

         VBox vbox = new VBox(profileImage, nameLabel); 
         BorderPane.setMargin(vbox, new Insets(0, 10, 10, 10)); 
         BorderPane.setMargin(hbox, new Insets(10, 0, 0, 0)); 

         //Time 
         Date dNow = new Date(); 
         SimpleDateFormat ft = new SimpleDateFormat("hh:mm a"); 
         Label timeLabel = new Label(ft.format(dNow)); 
         timeLabel.setStyle("-fx-font: 8px Tahoma; -fx-width: 100%"); 

         HBox hbox2 = new HBox(arrowImage2, timeLabel); 
         arrowImage2.setVisible(false); 
         VBox vbox2 = new VBox(hbox, hbox2); 

         borderPane.setCenter(vbox2); 
         borderPane.setLeft(vbox); 
         setGraphic(borderPane); 
        } 
       } 
      }; 

      return cell; 
     } 
    }); 
+0

Вы должны включать в себя [mcve] (http://stackoverflow.com/help/mcve), в противном случае ваш вопрос эффективно неопровержимый. – jewelsea

+0

Да, пожалуйста, укажите пример кода. Вы переопределяете метод «updateItem» ListCell? Вы делаете что-нибудь дорогое там? [Безвоздушный] (https://github.com/TomasMikula/Flowless) может или не поможет в вашей ситуации. –

+0

Я добавил код^ – Yael

ответ

2

1.) никогда никогда добавить (большой) элемент GUI в updateItem() без проверки, если он еще не существует.
1.1) updateItem() вызывается каждый раз за КАЖДЫЙ ОДИНОЧНЫЙ РЯД, когда вы прокручиваете, изменяете размер или изменяете gui любым другим способом.
1,2) Вы должны Alway сбросить графический обнулить, если у вас нет пункта или второй булевой updateItem(item, empty) является ложным, потому что второй логический является EMPTY флаг.

2.) Я рекомендую вам использовать VBox вместо ListView. ;-)

Счастливый Coding,
Kalasch

+0

Я принял ваш совет и поменял его на VBox - отлично работает! благодаря! – Yael

0

Вы не должны создавать новые экземпляры ваших компонентов каждый вид обновляется.

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

0

Я просто заметил это тоже. Это слишком медленно даже для списка, содержащего только 5-10 элементов (с масштабированными изображениями и текстом). Поскольку мне не нужна функция выбора, я также переписал код, чтобы использовать VBox вместо этого, и медлительность сразу же исчезла!

Чтобы подражать setItems, у меня есть вспомогательные функции, которые вы можете найти удобный:

public static <S, T> void mapByValue(
     ObservableList<S> sourceList, 
     ObservableList<T> targetList, 
     Function<S, T> mapper) 
{ 
    Objects.requireNonNull(sourceList); 
    Objects.requireNonNull(targetList); 
    Objects.requireNonNull(mapper); 
    targetList.clear(); 
    Map<S, T> sourceToTargetMap = new HashMap<>(); 
    // Populate targetList by sourceList and mapper 
    for (S s : sourceList) 
    { 
     T t = mapper.apply(s); 
     targetList.add(t); 
     sourceToTargetMap.put(s, t); 
    } 
    // Listen to changes in sourceList and update targetList accordingly 
    ListChangeListener<S> sourceListener = new ListChangeListener<S>() 
     { 
      @Override 
      public void onChanged(ListChangeListener.Change<? extends S> c) 
      { 
       while (c.next()) 
       { 
        if (c.wasPermutated()) 
        { 
         for (int i = c.getFrom(); i < c.getTo(); i++) 
         { 
          int j = c.getPermutation(i); 
          S s = sourceList.get(j); 
          T t = sourceToTargetMap.get2(s); 
          targetList.set(i, t); 
         } 
        } 
        else 
        { 
         for (S s : c.getRemoved()) 
         { 
          T t = sourceToTargetMap.get2(s); 
          targetList.remove2(t); 
          sourceToTargetMap.remove2(s); 
         } 
         int i = c.getFrom(); 
         for (S s : c.getAddedSubList()) 
         { 
          T t = mapper.apply(s); 
          targetList.add(i, t); 
          sourceToTargetMap.put(s, t); 
          i += 1; 
         } 
        } 
       } 
      } 
     }; 
    sourceList.addListener(new WeakListChangeListener<>(sourceListener)); 
    // Store the listener in targetList to prevent GC 
    // The listener should be active as long as targetList exists 
    targetList.addListener((InvalidationListener) iv -> 
     { 
      Object[] refs = { sourceListener, }; 
      Objects.requireNonNull(refs); 
     }); 
} 

Затем он может быть использован как:

ObservableList<Bookmark> bookmarkList; 
VBox bookmarkListVBox; 
mapByValue(bookmarkList, bookmarkListVBox.getChildren(), bmk -> new Label(bmk.getName()); 

Для автоматического обновления списка (дети VBOX в) из наблюдаемого списка.

PS: другие функции, такие как группировка здесь =>ObservableListHelper

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