2016-08-04 3 views
-1

Можно ли отгрузить загруженный контент Image, а затем загрузить его снова? Можно ли загрузить его по требованию?Как загрузить javafx.scene.image.Image по запросу?

У меня есть ImageView, который загружает изображение только на шоу?

+0

Это не совсем понятно, о чем вы просите. «Изображение» представляет собой фиксированный набор данных изображения, если это то, что вы имеете в виду. «WritableImage» представляет изображение фиксированного размера, но данные пикселя могут быть изменены после создания экземпляра через его «PixelWriter». Я понятия не имею, что вы подразумеваете под «Могу ли я иметь ImageView, который загружает изображение только на шоу?». –

+0

@James_D, потому что они заставили 'Image' загружаться с задержкой. См. Методы типа 'cancel()' и 'isBackgroundLoading()'. Странно, что этот процесс может идти только в одном направлении, как в законе термодинамики. – Dims

+0

Хм, не совсем уверен, что вы имеете в виду. Однако решение вашей проблемы состоит в том, чтобы сохранить фиксированный набор «ImageView's» (достаточно, чтобы отобразить экран под любыми значениями смещений прокрутки) и обновить их свойства «Image» по мере необходимости. Вызов 'setImage()' в представлении изображения заставит его перерисовать; если вы используете фоновое скачивание, оно будет перекрашиваться, когда загрузка будет завершена, и это то, что вы хотите. Было бы разумно называть 'cancel()' на текущем 'Image' перед заменой его, чтобы предотвратить ненужную работу в фоновом режиме. Замененные изображения будут gc'd обычным способом. –

ответ

-1

Нет, таких функций нет в договоре Image. Изображение может загружаться в фоновом режиме, но после загрузки оно не может быть выгружено.

При использовании ImageView, то вы должны назначить Image к нему явно, но JavaFX не предоставляет способ для вас, чтобы знать, когда ImageView фактически показано.

Чтобы реализовать требуемый близко к ImageView, я должен был его разветвить и использовать устаревший API с Prism, включая класс NGImageView.

+0

Но вы можете использовать 'ImageView', чтобы сделать то же самое. –

+0

Если вы знаете, тогда ответьте. Не играйте в hide-n-seek. – Dims

+1

Работа над этим ... Это не тривиально и потребуется некоторое время, чтобы написать. –

0

Лучше всего загружать изображения перед их отображением!

Для того, чтобы загрузить изображение, просто установите изображение в значение null! Но у вас будет возможность повторно инициализировать это изображение, чтобы иметь возможность просматривать! Я не рекомендую это!

Если вы будете повторно использовать это изображение, просто сохраните его в памяти! Загрузите его один раз и используйте его на неограниченном изображении.

1

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

Класс ImageView обеспечивает функциональность отображения изображения в пользовательском интерфейсе. Класс ImageView изменен, в том смысле, что вы можете изменить отображаемое изображение.

Основная стратегия, необходимая для реализации функций «черепичных изображений», заключается в создании виртуального контейнера , который имеет коллекцию «ячеек» или «плиток», которые повторно используются для отображения различного контента. По сути, такие средства управления, как ListView, TableView и TreeView, реализованы в JavaFX. Вы также можете быть заинтересованы в реализации Tomas Mikula's Flowless такой же идеи.

Чтобы реализовать функциональность «черепичные изображения», вы можете использовать массив из ImageView s как «ячейки» или «плитки». Вы можете поместить их в панель и реализовать панорамирование/прокрутку в панели, а когда просмотры изображений прокручиваются вне поля зрения, повторно используйте ImageView s, перемещая изображения с одного изображения на другой, загружая новые изображения только для необходимых ему фрагментов , Очевидно, что изображения, которые больше не ссылаются ни на какое изображение, будут иметь право на сбор мусора обычным способом.

Возможно, существуют другие способы достижения этой цели, такие как использование WritableImage и использование PixelWriter для обновления данных пикселя при необходимости. Что лучше всего работает, вероятно, в некоторой степени зависит от того, что наиболее удобно для фактического формата, который у вас есть для данных изображения; существует, вероятно, небольшая разница в производительности между различными стратегиями.

Если вы загружаете изображения с сервера или базы данных, вы должны сделать это в фоновом режиме. Если изображение загружено с URL-адреса, класс Image предоставляет функциональные возможности для этого.Если вы загружаетесь из входного потока (например, из поля BLOB базы данных), вам нужно будет реализовать фоновый поток.

Здесь пока основная идея (без резьбы):

import java.util.Random; 

import javafx.application.Application; 
import javafx.beans.property.DoubleProperty; 
import javafx.beans.property.IntegerProperty; 
import javafx.beans.property.SimpleDoubleProperty; 
import javafx.beans.property.SimpleIntegerProperty; 
import javafx.geometry.Insets; 
import javafx.geometry.Pos; 
import javafx.scene.Scene; 
import javafx.scene.control.Label; 
import javafx.scene.image.Image; 
import javafx.scene.image.ImageView; 
import javafx.scene.layout.Background; 
import javafx.scene.layout.BackgroundFill; 
import javafx.scene.layout.CornerRadii; 
import javafx.scene.layout.Pane; 
import javafx.scene.paint.Color; 
import javafx.stage.Stage; 

public class PanningTilesExample extends Application { 

    private static final int TILE_WIDTH = 100; 
    private static final int TILE_HEIGHT = 100; 

    private static final int PANE_WIDTH = 800; 
    private static final int PANE_HEIGHT = 800; 

    // amount scrolled left, in pixels: 
    private final DoubleProperty xOffset = new SimpleDoubleProperty(); 
    // amount scrolled right, in pixels: 
    private final DoubleProperty yOffset = new SimpleDoubleProperty(); 

    // number of whole tiles shifted to left: 
    private final IntegerProperty tileXOffset = new SimpleIntegerProperty(); 
    // number of whole tiles shifted up: 
    private final IntegerProperty tileYOffset = new SimpleIntegerProperty(); 

    private final Pane pane = new Pane(); 

    // for enabling dragging: 
    private double mouseAnchorX; 
    private double mouseAnchorY; 

    // array of ImageViews: 
    private ImageView[][] tiles; 

    private final Random rng = new Random(); 

    @Override 
    public void start(Stage primaryStage) { 

     // update number of tiles offset when number of pixels offset changes: 
     tileXOffset.bind(xOffset.divide(TILE_WIDTH)); 
     tileYOffset.bind(yOffset.divide(TILE_HEIGHT)); 

     // create the images views, etc. This method could be called 
     // when the pane size changes, if you want a resizable pane with fixed size tiles: 
     build(); 

     // while tile offsets change, allocate new images to existing image views: 

     tileXOffset.addListener(
       (obs, oldOffset, newOffset) -> rotateHorizontal(oldOffset.intValue() - newOffset.intValue())); 

     tileYOffset.addListener(
       (obs, oldOffset, newOffset) -> rotateVertical(oldOffset.intValue() - newOffset.intValue())); 

     // Simple example just has a fixed size pane: 
     pane.setMinSize(PANE_WIDTH, PANE_HEIGHT); 
     pane.setPrefSize(PANE_WIDTH, PANE_HEIGHT); 
     pane.setMaxSize(PANE_WIDTH, PANE_HEIGHT); 


     // enable panning on pane (just update offsets when dragging): 

     pane.setOnMousePressed(e -> { 
      mouseAnchorX = e.getSceneX(); 
      mouseAnchorY = e.getSceneY(); 
     }); 

     pane.setOnMouseDragged(e -> { 
      double deltaX = e.getSceneX() - mouseAnchorX; 
      double deltaY = e.getSceneY() - mouseAnchorY; 
      xOffset.set(xOffset.get() + deltaX); 
      yOffset.set(yOffset.get() + deltaY); 
      mouseAnchorX = e.getSceneX(); 
      mouseAnchorY = e.getSceneY(); 
     }); 

     // display in stage: 
     Scene scene = new Scene(pane); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    private void build() { 

     // create array of image views: 

     int numTileCols = (int) (PANE_WIDTH/TILE_WIDTH + 2); 
     int numTileRows = (int) (PANE_HEIGHT/TILE_HEIGHT + 2); 

     tiles = new ImageView[numTileCols][numTileRows]; 

     // populate array: 

     for (int colIndex = 0; colIndex < numTileCols; colIndex++) { 

      final int col = colIndex; 

      for (int rowIndex = 0; rowIndex < numTileRows; rowIndex++) { 

       final int row = rowIndex; 

       // create actual image view and initialize image:     
       ImageView tile = new ImageView(); 
       tile.setImage(getImage(col - tileXOffset.get(), row - tileYOffset.get())); 
       tile.setFitWidth(TILE_WIDTH); 
       tile.setFitHeight(TILE_HEIGHT); 

       // position image by offset, and register listeners to keep it updated: 
       xOffset.addListener((obs, oldOffset, newOffset) -> { 
        double offset = newOffset.intValue() % TILE_WIDTH + (col - 1) * TILE_WIDTH; 
        tile.setLayoutX(offset); 
       }); 
       tile.setLayoutX(xOffset.intValue() % TILE_WIDTH + (col - 1) * TILE_WIDTH); 

       yOffset.addListener((obs, oldOffset, newOffset) -> { 
        double offset = newOffset.intValue() % TILE_HEIGHT + (row - 1) * TILE_HEIGHT; 
        tile.setLayoutY(offset); 
       }); 
       tile.setLayoutY(yOffset.intValue() % TILE_HEIGHT + (row - 1) * TILE_HEIGHT); 

       // add image view to pane: 
       pane.getChildren().add(tile); 

       // store image view in array: 
       tiles[col][row] = tile; 
      } 
     } 
    } 

    // tiles have been shifted off-screen in vertical direction 
    // need to reallocate images to image views, and get new images 
    // for tiles that have moved into view: 

    // delta represents the number of tiles we have shifted, positive for up 
    private void rotateVertical(int delta) { 

     for (int colIndex = 0; colIndex < tiles.length; colIndex++) { 


      if (delta > 0) { 

       // top delta rows have shifted off-screen 
       // shift top row images by delta 
       // add new images to bottom rows: 

       for (int rowIndex = 0; rowIndex + delta < tiles[colIndex].length; rowIndex++) { 

        // stop any background loading we no longer need 
        if (rowIndex < delta) { 
         Image current = tiles[colIndex][rowIndex].getImage(); 
         if (current != null) { 
          current.cancel(); 
         } 
        } 

        // move image up from lower rows: 
        tiles[colIndex][rowIndex].setImage(tiles[colIndex][rowIndex + delta].getImage()); 
       } 

       // fill lower rows with new images: 
       for (int rowIndex = tiles[colIndex].length - delta; rowIndex < tiles[colIndex].length; rowIndex++) { 
        tiles[colIndex][rowIndex].setImage(getImage(-tileXOffset.get() + colIndex, -tileYOffset.get() + rowIndex)); 
       } 
      } 

      if (delta < 0) { 

       // similar to previous case... 
      } 
     } 

    } 


    // similarly, rotate images horizontally: 
    private void rotateHorizontal(int delta) { 
     // similar to rotateVertical....  
    } 

    // get a new image for tile represented by column, row 
    // this implementation just snapshots a label, but this could be 
    // retrieved from a file, server, or database, etc 
    private Image getImage(int column, int row) { 
     Label label = new Label(String.format("Tile [%d,%d]", column, row)); 
     label.setPrefSize(TILE_WIDTH, TILE_HEIGHT); 
     label.setMaxSize(TILE_WIDTH, TILE_HEIGHT); 
     label.setAlignment(Pos.CENTER); 
     label.setBackground(new Background(new BackgroundFill(randomColor(), CornerRadii.EMPTY , Insets.EMPTY))); 

     // must add label to a scene for background to work: 
     new Scene(label); 
     return label.snapshot(null, null); 
    } 


    private Color randomColor() { 
     return Color.rgb(rng.nextInt(256), rng.nextInt(256), rng.nextInt(256)); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 

Полный код (с обработкой потоков) here, полная версия без резьбы в previous revision

Существует, очевидно, больше функциональных возможностей (и повышение производительности), которые могут быть добавлены здесь, например, вы можете разрешить изменение размера панели (обновление: последняя версия связанного выше gist делает это), а также создавать или удалять плитки, когда панель меняет размер и т. д. Но это должно функционировать как базовый шаблон для этой функции.

+0

Периодически обновлял gists, я рекомендую просмотреть некоторые из [ревизий] (https://gist.github.com/james-d/a249470377fb3c58784a9349a22641c4/revisions). –

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