2016-08-04 3 views
-1

Image의로드 된 컨텐츠를 삭제하고 나중에로드 할 수 있습니까? 필요할 때로드 할 수 있습니까?요청에 따라 javafx.scene.image.Image를로드하는 방법은 무엇입니까?

ImageView의 이미지를 표시 할 때만 표시 할 수 있습니까?

+0

당신이 무엇을 요구하고 있는지 분명하지 않습니다. 'Image'는 고정 된 이미지 데이터 세트를 의미합니다. 'WritableImage'는 고정 크기의 이미지를 나타내지 만 픽셀 데이터는'PixelWriter'를 통해 인스턴스화 한 후에 변경할 수 있습니다. "이미지보기 만로드하는 ImageView를 사용할 수 있습니까?"라는 말의 의미는 모르겠습니다. –

+0

@ James_D 왜냐하면'Image'가 지연으로로드 프리 블되기 때문입니다. 'cancel()'과'isBackgroundLoading()'과 같은 메소드를 보라. 이 과정은 열역학 법과 마찬가지로 한 방향으로 만 진행될 수 있다는 것은 이상합니다. – Dims

+0

흠, 너 무슨 뜻인지 잘 모르겠다. 그러나, 문제의 해결 방법은'ImageView'의 고정 된 세트를 유지하고 (스크롤 오프셋의 값 아래에서 디스플레이를 타일링하기에 충분할 정도로) 필요에 따라 이미지 속성을 업데이트하는 것입니다. 이미지보기에서'setImage()'를 호출하면 강제로 다시 칠합니다. 백그라운드로드를 사용하는 경우로드가 완료되면 다시 칠하기 때문에 원하는대로 처리됩니다. 백그라운드에서 불필요한 작업을 막기 위해 현재 Image에서'cancel()'을 호출 한 다음 바꾸는 것이 현명 할 것입니다. 대체 된 이미지는 일반적인 방식으로 gc'd됩니다. –

답변

-1

아니요, Image 계약에는 이러한 기능이 없습니다. 이미지는 백그라운드에서로드 할 수 있지만로드 된 후에는 언로드 할 수 없습니다.

ImageView을 사용하는 경우 명시 적으로 Image을 지정해야하지만 ImageView이 실제로 표시되는시기는 JavaFX에서 알 수 없습니다.

ImageView에 가까운 값을 구현하려면 클래스를 포함하여 사용되지 않는 API 인 Prism을 사용하는 것이 좋습니다.

+0

하지만 같은 일을하기 위해서'ImageView'를 사용할 수 있습니다. –

+0

당신이 알고 있다면 대답하십시오. hide-n-seek을하지 마십시오. – Dims

+1

작업 중 ... 사소한 일이 아니며 글을 쓸 시간이 필요합니다. –

0

이미지를 표시하기 전에 이미지를로드하는 것이 가장 좋습니다.

이미지를 없애고 싶다면 단순히 이미지를 null로 설정하십시오! 그런 다음 이미지를 다시 볼 수있게하려면 이미지를 다시 초기화하십시오! 나는 이것을 추천하지 않는다!

이미지를 다시 사용하려면 메모리를 그대로 사용하십시오! 한 번로드하고 무제한 이미지 뷰어에서 사용하십시오!

1

Image 클래스는 건설 시간에 이미지 데이터의 소스를 지정할 수 있다는 점에서 본질적으로 이미지 데이터와 관련하여 불변입니다. 이후 API를 통해 수정할 수 없습니다.

ImageView 클래스는 UI에 이미지를 표시하는 기능을 제공합니다. ImageView 클래스는 표시 할 이미지를 변경할 수 있다는 점에서 변경 가능합니다.

는 "타일 이미지"를 구현하기 위해 필요한 기본 전략이 기능은 "세포"또는 다른 콘텐츠를 표시하기 위해 재사용된다 "타일"의 컬렉션을 가지고 가상화 컨테이너를 만드는 것입니다. 이것은 본질적으로 ListView, TableViewTreeView과 같은 컨트롤이 JavaFX에서 구현되는 방법입니다. 당신은 또한에 관심이있을 수 있습니다 Tomas Mikula의 Flowless 같은 종류의 아이디어의 구현.

"타일 이미지"기능을 구현하려면 ImageView의 배열을 "셀"또는 "타일"로 사용할 수 있습니다. 창에 이들을 배치하고 창에서 패닝/스크롤링을 구현할 수 있으며, 이미지 뷰가 화면 밖으로 스크롤하면 ImageView을 다시 사용하여 하나의 이미지보기에서 다른보기로 이미지를 이동하고 필요로하는 타일에 대해서만 새 이미지를로드 할 수 있습니다 . 분명히 어떤 이미지보기에서 더 이상 참조되지 않는 이미지는 일반적인 방법으로 가비지 컬렉션을받을 수 있습니다.

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

에서 스레딩없이 완전한 버전 : 여기

은 (스레딩) 기본적인 생각입니다) 여기에 추가 할 수 있습니다. 예를 들어, 창의 크기를 조정할 수 있습니다 (업데이트 : 위에 링크 된 요점의 최신 버전이이 작업을 수행합니다). 그리고 창 크기가 바뀔 때 타일을 만들거나 제거합니다. 그러나 이것은 이 기능을위한 기본 템플릿.

+0

요점을 주기적으로 업데이트 했으므로 [개정] (https://gist.github.com/james-d/a249470377fb3c58784a9349a22641c4/revisions) 중 일부를 탐색하는 것이 좋습니다. –

관련 문제