Как показать конкретную часть изображения в javafx

1

Изображение 174551

У меня есть эта картина (все эти эффекты находятся в одном.png файле). Я хочу отобразить, например, второе изображение, как я могу использовать Image и ImageView в javafx для отображения определенной части этого изображения? благодаря

  • 2
    Если бы вы использовали BufferedImage, это было бы очень просто, но нет, JavaFX должен иметь свой собственный класс Image ...
  • 0
    Как я могу сделать это с BufferedImage?
Показать ещё 1 комментарий
Теги:
javafx

2 ответа

4
Лучший ответ

Этот ответ излишне. Но с хорошим набором изображений, как у вас в вашем вопросе, может быть, излишний - это то, что требуется :-)

Фундаментальный дизайн такой же, как Улук, он просто настраивает Видовой экран ImageView, а не устанавливает клип, но концепция такая же.

Beware => Java 8

import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.event.*;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Control;
import javafx.scene.effect.*;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;

class ExploadableImageView extends ImageView {
    private final Rectangle2D[] cellClips;
    private int numCells;
    private final Duration FRAME_TIME = Duration.seconds(.5);

    public ExploadableImageView(Image explosionImage, int numCells) {
        this.numCells = numCells;

        double cellWidth  = explosionImage.getWidth() / numCells;
        double cellHeight = explosionImage.getHeight();

        cellClips = new Rectangle2D[numCells];
        for (int i = 0; i < numCells; i++) {
            cellClips[i] = new Rectangle2D(
                    i * cellWidth, 0,
                    cellWidth, cellHeight
            );
        }

        setImage(explosionImage);
        setViewport(cellClips[0]);
    }

    public void explode(EventHandler<ActionEvent> onFinished) {
        final IntegerProperty frameCounter = new SimpleIntegerProperty(0);
        Timeline kaboom = new Timeline(
                new KeyFrame(FRAME_TIME, event -> {
                    frameCounter.set((frameCounter.get() + 1) % numCells);
                    setViewport(cellClips[frameCounter.get()]);
                })
        );
        kaboom.setCycleCount(numCells);
        kaboom.setOnFinished(onFinished);
        kaboom.play();
    }
}

class ExplodableItem extends StackPane {
    public ExplodableItem(Image objectImage, Image explosionImage, int numCells) {
        ImageView objectView = new ImageView(objectImage);
        ExploadableImageView explosionView = new ExploadableImageView(
                explosionImage, numCells
        );

        setMinSize(
                Math.max(
                        objectImage.getWidth(),
                        explosionView.getViewport().getWidth()
                ),
                Math.max(
                        objectImage.getHeight(),
                        explosionView.getViewport().getHeight()
                )
        );

        objectView.setPickOnBounds(false);
        objectView.setOnMouseClicked(event -> {
            getChildren().setAll(explosionView);
            explosionView.explode(complete -> getChildren().setAll(objectView));
        });

        DropShadow drop = new DropShadow(10, Color.GOLD);
        drop.setInput(new Glow());
        objectView.setOnMouseEntered(event -> objectView.setEffect(drop));
        objectView.setOnMouseExited(event -> objectView.setEffect(null));

        getChildren().setAll(objectView);
    }
}

public class CatWhack extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    private static final int NUM_CELLS_PER_EXPLOSION = 6;

    @Override
    public void start(Stage stage) {
        Image objectImage    = new Image("http://icons.iconarchive.com/icons/iconka/meow/96/cat-box-icon.png");  // cat icon linkware: backlink to http://www.iconka.com required
        // looks likes imgur may have blocked direct access to following png from a Java app (somehow).
        // but you can still download the QMqbQ.png from that location 
        // and save it locally in the same directory as the CatWhack program
        // then pick it up by replacing the new Image call with:
        //    new Image(CatWhack.class.getResourceAsStream("QMqbQ.png")); 
        Image explosionImage = new Image("http://i.stack.imgur.com/QMqbQ.png");

        TilePane tiles = new TilePane();
        tiles.setPrefColumns(4);
        for (int i = 0; i <16; i++) {
            tiles.getChildren().add(
                    new ExplodableItem(objectImage, explosionImage, NUM_CELLS_PER_EXPLOSION)
            );
        }
        tiles.setMinSize(Control.USE_PREF_SIZE, Control.USE_PREF_SIZE);

        stage.setTitle("Cat Whack - Click a cat to whack it!");
        stage.setScene(new Scene(tiles));
        stage.show();
    }
}

Изображение 174551

Простой пример

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

Анимированное изображение похоже на Sprite. Код, приведенный ниже, не предназначен для создания системы Sprite качества производства (вероятно, настоящая система Sprite для игры будет иметь больше функций и функций), она просто демонстрирует очень простое отображение анимированного изображения на основе Viewport.

Изображение 174551

import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.ToggleButton;
import javafx.scene.image.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;

class Sprite extends ImageView {
    private final Rectangle2D[] cellClips;
    private int numCells;
    private final Timeline timeline;
    private final IntegerProperty frameCounter = new SimpleIntegerProperty(0);

    public Sprite(Image animationImage, int numCells, Duration frameTime) {
        this.numCells = numCells;

        double cellWidth  = animationImage.getWidth() / numCells;
        double cellHeight = animationImage.getHeight();

        cellClips = new Rectangle2D[numCells];
        for (int i = 0; i < numCells; i++) {
            cellClips[i] = new Rectangle2D(
                    i * cellWidth, 0,
                    cellWidth, cellHeight
            );
        }

        setImage(animationImage);
        setViewport(cellClips[0]);

        timeline = new Timeline(
                new KeyFrame(frameTime, event -> {
                    frameCounter.set((frameCounter.get() + 1) % numCells);
                    setViewport(cellClips[frameCounter.get()]);
                })
        );
    }

    public void playOnce() {
        frameCounter.set(0);
        timeline.setCycleCount(numCells);
        timeline.stop();
        timeline.playFromStart();
    }

    public void playContinuously() {
        frameCounter.set(0);
        timeline.setCycleCount(Timeline.INDEFINITE);
        timeline.stop();
        timeline.playFromStart();
    }

    public void stop() {
        frameCounter.set(0);
        setViewport(cellClips[frameCounter.get()]);
        timeline.stop();
    }
}

public class SpriteSample extends Application {
    private static final int NUM_CELLS_PER_ANIMATION = 6;
    private static final Duration FRAME_TIME = Duration.seconds(.5);

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

    @Override
    public void start(Stage stage) {
        // looks likes imgur may have blocked direct access to following png from a Java app (somehow).
        // but you can still download the QMqbQ.png from that location 
        // and save it locally in the same directory as the CatWhack program
        // then pick it up by replacing the new Image call with:
        //    new Image(Sprite.class.getResourceAsStream("QMqbQ.png")); 
        Image tilesheetImage = new Image(SpriteSample.class.getResourceAsStream("QMqbQ.png"));
        Sprite sprite = new Sprite(tilesheetImage, NUM_CELLS_PER_ANIMATION, FRAME_TIME);

        ToggleButton animationControl = new ToggleButton("Animate");
        animationControl.setOnAction(event -> {
            if (animationControl.isSelected()) {
                animationControl.setText("Stop");
                sprite.playContinuously();
            } else {
                animationControl.setText("Animate");
                sprite.stop();
            }
        });

        VBox layout = new VBox(10, sprite, animationControl);
        layout.setPadding(new Insets(10));
        layout.setAlignment(Pos.CENTER);

        stage.setScene(new Scene(layout));
        stage.show();
    }
}
  • 0
    Просто будьте осторожны, не каждый будет использовать Java 8;)
  • 2
    После некоторых экспериментов я обнаружил, что использование отдельных изображений (setImage ()) имеет гораздо лучшую производительность> 100% по сравнению с setViewport, а также имеет лучшую производительность GC. Я согласен, что метод setViewport () более чистый.
4

Вы можете использовать свойство клипа Node, а также свойство x ImageView. Ниже приведена демонстрация части изображения на временной шкале, например, анимированная картинка gif:

@Override
public void start(Stage stage) {

    Group root = new Group();
    Image image = new Image(this.getClass().getResource("your.png").toExternalForm());

    final int numberOfFrames = 6; // in image
    double frameWidth = image.getWidth() / numberOfFrames;
    Scene scene = new Scene(root, frameWidth, image.getHeight());
    final ImageView view = new ImageView(image);

    Rectangle mask = new Rectangle(frameWidth, image.getHeight());
    view.setClip(mask);

    Timeline timeline = new Timeline();

    for (int i = 0; i <= numberOfFrames; i++) {
        KeyFrame kf = new KeyFrame(Duration.seconds(i), new KeyValue(view.xProperty(), -frameWidth * i, Interpolator.DISCRETE));
        timeline.getKeyFrames().add(kf);
    }
    timeline.setCycleCount(Timeline.INDEFINITE);
    timeline.play();

    root.getChildren().add(view);
    stage.setScene(scene);
    stage.show();

}
  • 0
    спасибо, но как я могу показать каждое изображение в первом кадре (я имею в виду, если у меня есть 6 частей изображения, как мое изображение сверху, я показываю все изображения на первом изображении)
  • 0
    Какой будет метод для ручного смещения маски на изображении? (без использования ключевого кадра, чтобы сделать это повторно)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню