当前位置: 首页 > 知识库问答 >
问题:

需要使用JavaFX在HBox中动画图像的帮助

司徒隐水
2023-03-14

我正在为一款名为Counter-Strike:Global Avolution的游戏创建一个模拟程序,我一直在考虑如何在HBox中对某些图像进行动画化。游戏中有武器箱,里面装着各种不同稀有度的皮肤。点击“打开”按钮后,可能赢得的项目将开始在HBox中滚动。把它想象成命运之轮,它开始得很快,然后逐渐变慢,直到它停止在一个名字上,但在这种情况下,代替名字的是项目,而不是一个“轮子”,我有一个水平的HBox与图像滚动通过。下面是我正在尝试制作的一个很好的例子:http://cases.goaggro.com/。

目前,我有一个ImageView类的实例分配给每个应该包含在要滚动的项目总组中的单个武器图像,还有一个数组来保存所有这些图像。在GUI上,我设置了HBox的最大宽度和高度,以便任何3个这些图像从左到右放置在HBox内,完全填充它的体积。我的第一个问题就在这里。如果我试着做

Hbox.getChildren().addAll(itemArray); 

它将添加前3个只是很好,但将继续添加超出HBox边界的图像,直到到达windows主边界。有没有办法添加更多的图像到HBox比显示的最大图像数(是3由于当前的HBox大小我已经设置),同时防止他们超过HBox的边界和只是隐藏在后面?

第二个问题是,什么是最好的方法去动画我的HBox内的每一个图像,使它向左滚动,但不超出或超出HBox边界?我需要最左边的图像从屏幕上向左滑动,而中间的图像滑到左边的位置,一个新的图像从右边滑进来填充右边的位置,并且以逐渐减慢的速度重复这样做,直到落在一个物品上的点。

当前,将此代码添加到“打开”按钮的事件处理程序中,可以将item1、item2和item3中的图像正确地添加到HBox中。但是如果我超过了3个图像(例如,将HBox.addAll()设置为itemArray而不是单独设置前3个项目),它就超过了HBox边框,并开始将它们放置在场景的顶部,直到到达windows的主边框。注意:ImageView类总共有15个实例(item1-item15),但我将代码缩短为4个,数组内容也缩短为4个,因为无论将3个以上的图像放入HBox中,问题都会发生。

public class Controller
{
@FXML
private HBox hBox;

    public void openCaseAction(ActionEvent actionEvent)
        {
            final ImageView item1 = new ImageView(new Image(getClass().getResourceAsStream("../images/image1.png")));
            final ImageView item2 = new ImageView(new Image(getClass().getResourceAsStream("../images/image2.png")));
            final ImageView item3 = new ImageView(new Image(getClass().getResourceAsStream("../images/image3.png")));
            final ImageView item4 = new ImageView(new Image(getClass().getResourceAsStream("../images/image4.png")));

            final ImageView[] itemArray ={item1,item2,item3,item4};

            hBox.getChildren().addAll(item1,item2,item3);
    }
}

共有1个答案

凤衡
2023-03-14

您可能希望为此使用自定义布局,而不是HBox。看看展示架示例:

  1. 从Oracle下载Java 8演示和示例。
  2. 提取示例包。
  3. 运行demo/javafx_samples/ensemble8.jar程序。
  4. 在程序的搜索栏中键入“显示货架”。
  5. 查看Display Shelf示例UI和源代码。
  6. 在尊重原始许可条款的前提下,根据您认为合适的情况进行复制和修改。

这将不是你正在寻找的,但它将是一个更接近的起点,比尝试动画项目在一个HBox。

Oracle DisplayShelf示例代码:

/*
 * Copyright (c) 2008, 2014, Oracle and/or its affiliates.
 * All rights reserved. Use is subject to license terms.
 *
 * This file is available and licensed under the following license:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  - Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the distribution.
 *  - Neither the name of Oracle Corporation nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package ensemble.samples.graphics2d.displayshelf;

import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.control.ScrollBar;
import javafx.scene.image.Image;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Region;
import javafx.scene.shape.Rectangle;
import javafx.util.Duration;

/**
 * Simple 7 segment LED style digit. It supports the numbers 0 through 9.
 */
/**
 * A ui control which displays a browse-able display shelf of images
 */
public class DisplayShelf extends Region {

    private final Duration DURATION = Duration.millis(500);
    private final Interpolator INTERPOLATOR = Interpolator.EASE_BOTH;
    private final double SPACING = 50;
    private final double LEFT_OFFSET = -110;
    private final double RIGHT_OFFSET = 110;
    private final double SCALE_SMALL = 0.7;
    private PerspectiveImage[] items;
    private Group centered = new Group();
    private Group left = new Group();
    private Group center = new Group();
    private Group right = new Group();
    private int centerIndex = 0;
    private Timeline timeline;
    private ScrollBar scrollBar = new ScrollBar();
    private boolean localChange = false;
    private Rectangle clip = new Rectangle();

    public DisplayShelf(Image[] images) {
        // set clip
        setClip(clip);
        // set ids for styling via CSS
        setId("displayshelf");  
        scrollBar.setId("display-scrollbar");
        // create items
        items = new PerspectiveImage[images.length];
        for (int i = 0; i < images.length; i++) {
            final PerspectiveImage item =
                    items[i] = new PerspectiveImage(images[i]);
            final double index = i;
            item.setOnMouseClicked((MouseEvent me) -> {
                localChange = true;
                scrollBar.setValue(index);
                localChange = false;
                shiftToCenter(item);
            });
        }
        // setup scroll bar
        scrollBar.setMax(items.length - 1);
        scrollBar.setVisibleAmount(1);
        scrollBar.setUnitIncrement(1);
        scrollBar.setBlockIncrement(1);
        scrollBar.valueProperty().addListener((Observable ov) -> {
            if (!localChange) {
                shiftToCenter(items[(int) Math.round(scrollBar.getValue())]);
            }
        });
        // create content
        centered.getChildren().addAll(left, right, center);
        getChildren().addAll(centered, scrollBar);
        // listen for keyboard events
        setFocusTraversable(true);
        setOnKeyPressed((KeyEvent ke) -> {
            if (ke.getCode() == KeyCode.LEFT) {
                shift(1);
                localChange = true;
                scrollBar.setValue(centerIndex);
                localChange = false;
            } else if (ke.getCode() == KeyCode.RIGHT) {
                shift(-1);
                localChange = true;
                scrollBar.setValue(centerIndex);
                localChange = false;
            }
        });
        // update
        update();
    }

    @Override
    protected void layoutChildren() {
        // update clip to our size
        clip.setWidth(getWidth());
        clip.setHeight(getHeight());
        // keep centered centered
        centered.setLayoutY((getHeight() - PerspectiveImage.HEIGHT) / 2);
        centered.setLayoutX((getWidth() - PerspectiveImage.WIDTH) / 2);
        // position scroll bar at bottom
        scrollBar.setLayoutX(10);
        scrollBar.setLayoutY(getHeight() - 25);
        scrollBar.resize(getWidth() - 20, 15);
    }

    private void update() {
        // move items to new homes in groups
        left.getChildren().clear();
        center.getChildren().clear();
        right.getChildren().clear();
        for (int i = 0; i < centerIndex; i++) {
            left.getChildren().add(items[i]);
        }
        center.getChildren().add(items[centerIndex]);
        for (int i = items.length - 1; i > centerIndex; i--) {
            right.getChildren().add(items[i]);
        }
        // stop old timeline if there is one running
        if (timeline != null) {
            timeline.stop();
        }
        // create timeline to animate to new positions
        timeline = new Timeline();
        // add keyframes for left items
        final ObservableList<KeyFrame> keyFrames = timeline.getKeyFrames();
        for (int i = 0; i < left.getChildren().size(); i++) {
            final PerspectiveImage it = items[i];
            double newX = -left.getChildren().size()
                    * SPACING + SPACING * i + LEFT_OFFSET;
            keyFrames.add(new KeyFrame(DURATION,
                    new KeyValue(it.translateXProperty(), newX, INTERPOLATOR),
                    new KeyValue(it.scaleXProperty(), SCALE_SMALL, INTERPOLATOR),
                    new KeyValue(it.scaleYProperty(), SCALE_SMALL, INTERPOLATOR),
                    new KeyValue(it.angle, 45.0, INTERPOLATOR)));
        }
        // add keyframe for center item
        final PerspectiveImage centerItem = items[centerIndex];
        keyFrames.add(new KeyFrame(DURATION,
                new KeyValue(centerItem.translateXProperty(), 0, INTERPOLATOR),
                new KeyValue(centerItem.scaleXProperty(), 1.0, INTERPOLATOR),
                new KeyValue(centerItem.scaleYProperty(), 1.0, INTERPOLATOR),
                new KeyValue(centerItem.angle, 90.0, INTERPOLATOR)));
        // add keyframes for right items
        for (int i = 0; i < right.getChildren().size(); i++) {
            final PerspectiveImage it = items[items.length - i - 1];
            final double newX = right.getChildren().size()
                    * SPACING - SPACING * i + RIGHT_OFFSET;
            keyFrames.add(new KeyFrame(DURATION,
                    new KeyValue(it.translateXProperty(), newX, INTERPOLATOR),
                    new KeyValue(it.scaleXProperty(), SCALE_SMALL, INTERPOLATOR),
                    new KeyValue(it.scaleYProperty(), SCALE_SMALL, INTERPOLATOR),
                    new KeyValue(it.angle, 135.0, INTERPOLATOR)));
        }
        // play animation
        timeline.play();
    }

    private void shiftToCenter(PerspectiveImage item) {
        for (int i = 0; i < left.getChildren().size(); i++) {
            if (left.getChildren().get(i) == item) {
                int shiftAmount = left.getChildren().size() - i;
                shift(shiftAmount);
                return;
            }
        }
        if (center.getChildren().get(0) == item) {
            return;
        }
        for (int i = 0; i < right.getChildren().size(); i++) {
            if (right.getChildren().get(i) == item) {
                int shiftAmount = -(right.getChildren().size() - i);
                shift(shiftAmount);
                return;
            }
        }
    }

    public void shift(int shiftAmount) {
        if (centerIndex <= 0 && shiftAmount > 0) {
            return;
        }
        if (centerIndex >= items.length - 1 && shiftAmount < 0) {
            return;
        }
        centerIndex -= shiftAmount;
        update();
    }
}
/*
 * Copyright (c) 2008, 2014, Oracle and/or its affiliates.
 * All rights reserved. Use is subject to license terms.
 *
 * This file is available and licensed under the following license:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  - Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the distribution.
 *  - Neither the name of Oracle Corporation nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package ensemble.samples.graphics2d.displayshelf;

import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.scene.Parent;
import javafx.scene.effect.PerspectiveTransform;
import javafx.scene.effect.Reflection;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;

/**
 * A Node that displays a image with some 2.5D perspective rotation around the Y
 * axis.
 */
public class PerspectiveImage extends Parent {

    private static final double REFLECTION_SIZE = 0.25;

    public static final double WIDTH = 200;
    public static final double HEIGHT = WIDTH + (WIDTH * REFLECTION_SIZE);

    private static final double RADIUS_H = WIDTH / 2;
    private static final double BACK = WIDTH / 10;
    private PerspectiveTransform transform = new PerspectiveTransform();
    /**
     * Angle Property
     */
    public final DoubleProperty angle = new SimpleDoubleProperty(45) {
        @Override
        protected void invalidated() {
            // when angle changes calculate new transform
            double lx = (RADIUS_H - Math.sin(Math.toRadians(angle.get())) * RADIUS_H - 1);
            double rx = (RADIUS_H + Math.sin(Math.toRadians(angle.get())) * RADIUS_H + 1);
            double uly = (-Math.cos(Math.toRadians(angle.get())) * BACK);
            double ury = -uly;
            transform.setUlx(lx);
            transform.setUly(uly);
            transform.setUrx(rx);
            transform.setUry(ury);
            transform.setLrx(rx);
            transform.setLry(HEIGHT + uly);
            transform.setLlx(lx);
            transform.setLly(HEIGHT + ury);
        }
    };

    public final double getAngle() {
        return angle.getValue();
    }

    public final void setAngle(double value) {
        angle.setValue(value);
    }

    public final DoubleProperty angleModel() {
        return angle;
    }

    public PerspectiveImage(Image image) {
        ImageView imageView = new ImageView(image);
        Reflection reflection = new Reflection();
        reflection.setFraction(REFLECTION_SIZE);
        imageView.setEffect(reflection);
        setEffect(transform);
        getChildren().addAll(imageView);
    }
}
 类似资料:
  • 我想旋转组中的图像,并将该组放入HBox中,而没有明显的“弹跳”效果。上图是一个使用JavaFX形状代替图像的例子,但最终结果是一样的。顶部的HBox包含一个旋转矩形,它看起来很好。底部的HBox在同一组中包含一个矩形和一个圆形,但是旋转矩形会导致“弹跳”副作用。为什么会弹跳?以下是我的代码:

  • 如何使用Rethfit在同一个参数上添加多个图像/文件以及其他文本数据?

  • 我再次下载了java sdk(如这里所示:http://www.oracle.com/technetwork/java/JavaFX/downloads/index.html),但是当我右键单击一个项目时,JavaFX并没有显示出来。(如果有关系的话,我使用的是eclipse上的scala插件) 我去了这里:http://www.eclipse.org/efxclipse/install.html

  • 我的javafx应用程序中有一个带有ImageViews的HBox,现在我需要一些方法来迭代这个HBox,但是我找不到一个算法来实现它,我试着做了这样的事情: 这里堆栈是我的HBox,但这样的ImageViews会重复,我不想要的。我不知道为什么,所以我该怎么做…

  • 主要内容:示例,示例2,在HBox中增长,设置HBox首选宽度,在HBox的控件之间设置空格(空间),HBox设置填充和间距JavaFX API具有将UI控件显示到场景图上的布局类。 HBox布局类将JavaFX子节点放在水平行中。 新的子节点附加到右侧的末尾。默认情况下,HBox布局尊重子节点的首选宽度和高度。 当父节点不可调整大小时,例如节点,的行高度设置为子节点的最大首选高度。 默认情况下,每个子节点与左上()位置对齐。 我们可以通过编程方式改变HBox的布局约束,例如边框,填充,边距,间

  • activity\u checklist\u详细信息。xml 以下是ChecklistDetail活动 但对我来说什么都不管用。如果我将activity\u checklist\u detail中的布局更改为水平或垂直,我将得到下图。 注意:我知道使用RecyclerView是最好的选择,但这里我没有很多项目。提前谢谢。