我正在研究一种元素周期表,有一个事件最终,当您将鼠标悬停时,会放大一点所述元素并显示更多信息,但事实是它并没有真正完成这项工作很好。可以说是跟踪,因为如果鼠标移动得有点快,或者很快离开位于边缘的面板,它就不会检测到鼠标的退出。这是鼠标进入或退出时应执行的动画代码:
public void onScale(int i){
double currentScaleX = Panes[i].getScaleX();
double currentScaleY = Panes[i].getScaleY();//stores the current scale
if (currentScaleX == 1.0 && currentScaleY == 1.0) {//verify that said scale is the original (equal to 1)
TranslateTransition translate = new TranslateTransition(Duration.millis(50), Symbol[i]);
translate.setToY(-4);
translate.playFromStart();//move the symbol up a little
TranslateTransition tratn = new TranslateTransition(Duration.millis(50), AtomicNumber[i]);
tratn.setToY(-2);
tratn.playFromStart();
TranslateTransition tratm = new TranslateTransition(Duration.millis(50), AtomicMass[i]);
tratm.setToY(-2);
tratm.playFromStart();
TranslateTransition trnm = new TranslateTransition(Duration.millis(50), Name[i]);
trnm.setToY(3);
trnm.playFromStart();
AtomicMass[i].setVisible(true);
OxidationNumber[i].setVisible(true);//makes the atomic mass and oxidation number visible
ScaleTransition scale = new ScaleTransition(Duration.millis(100), Panes[i]);
scale.setToX(1.5);
scale.setToY(1.5);
scale.playFromStart();
//The panel is brought to the foreground, (note that this will not affect its position in the childlist unlike the .tofront method)
Panes[i].setViewOrder(-1.0);
Panes[i].getParent().setViewOrder(-1.0);
}
}
public void offScale(int i){
double currentScaleX = Panes[i].getScaleX();
double currentScaleY = Panes[i].getScaleY();
if (currentScaleX > 1.0 && currentScaleY > 1.0) {
TranslateTransition translate = new TranslateTransition(Duration.millis(50), Symbol[i]);
translate.setToY(0);
translate.playFromStart();
TranslateTransition tratn = new TranslateTransition(Duration.millis(50), AtomicNumber[i]);
tratn.setToY(0);
tratn.playFromStart();
TranslateTransition tratm = new TranslateTransition(Duration.millis(50), AtomicMass[i]);
tratm.setToY(0);
tratm.playFromStart();
TranslateTransition trnm = new TranslateTransition(Duration.millis(50), Name[i]);
trnm.setToY(0);
trnm.playFromStart();
AtomicMass[i].setVisible(false);
OxidationNumber[i].setVisible(false);
ScaleTransition scale = new ScaleTransition(Duration.millis(100), Panes[i]);
scale.setToX(1.0);
scale.setToY(1.0);
scale.playFromStart();
Panes[i].setViewOrder(0.0);
Panes[i].getParent().setViewOrder(0.0);
}
}
Run Code Online (Sandbox Code Playgroud)
那么,您有什么建议吗?我正在使用窗格向量。PS:我现在用来完成类似工作的方法是创建另一个方法,稍后在初始化整个表的另一个方法中调用该方法。调用动画的方法:
@FXML
private void MouseEntered(MouseEvent event) {
Pane pane = (Pane) event.getSource();//creates a local variable based on the pane
onScale(Integer.parseInt(pane.getId()));
for(int i=1; i<=118; i++){
offScale(i);
}
}
@FXML
private void MouseExited(MouseEvent event) {
Pane pane = (Pane) event.getSource();
offScale(Integer.parseInt(pane.getId()));
}
Run Code Online (Sandbox Code Playgroud)
在初始化方法的一部分中有一个循环,它分配如下事件:
Panes[i].setOnMouseEntered(this::MouseEntered);
Panes[i].setOnMouseExited(this::MouseExited);
Run Code Online (Sandbox Code Playgroud)
无论移动鼠标的速度如何或鼠标是否离开整个窗口,都应始终传递和MOUSE_ENTERED事件。您没有提供一个最小的、完整的示例,所以我不能绝对确定问题是什么。但是,我认为问题在于您正在为每个“方向”创建两个单独的动画。这意味着“按比例”动画可以与“非比例”动画并行运行,从而导致结果不一致。同样奇怪的是,您手动注册了一个用 注释的事件处理程序方法,但这是否会导致问题取决于您未显示的其余代码。MOUSE_EXITED@FXML
您应该使用单个动画并操纵其rate属性。这不仅可以防止两个动画发生冲突,而且可以让动画在播放过程中轻松切换方向,而不会影响动画的速度。ParallelTransition如果您希望多个动画并行运行,我还建议您使用 a ,而不是单独播放每个动画。
这是一个演示上面讨论的建议的示例。最后有一个 GIF 显示了代码的输出。
动画是在类CellAnimation中嵌套的类中实现的Cell。您会注意到有关“单元格”的逻辑viewOrder比您当前的代码稍微复杂一些。本质上,逻辑是:
上升单元格:视图顺序从0到-1立即,然后 到-2动画的中间点。
降低单元格:视图顺序从-2到-1位于动画的中间点,然后转到0动画的结尾处。请注意,如果单元格未升起至少一半,则查看顺序将从 开始-1。
这种逻辑给出了上升单元和下降单元在中间标记处相互“穿过”的错觉。这也意味着动画单元始终呈现在所有非动画单元上方。换句话说,这一切都让动画看起来更加自然。
主要.java:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class Main extends Application {
private static final int ROWS = 5;
private static final int COLUMNS = 5;
@Override
public void start(Stage primaryStage) throws Exception {
var root = new GridPane();
root.setPadding(new Insets(30));
root.setHgap(5);
root.setVgap(5);
root.setAlignment(Pos.CENTER);
for (int row = 0; row < ROWS; row++) {
for (int col = 0; col < COLUMNS; col++) {
var cell = new Cell(row * COLUMNS + col);
root.add(cell.getNode(), col, row);
}
}
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
Run Code Online (Sandbox Code Playgroud)
细胞.java:
import javafx.animation.Animation;
import javafx.animation.FadeTransition;
import javafx.animation.ParallelTransition;
import javafx.animation.ScaleTransition;
import javafx.animation.TranslateTransition;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.util.Duration;
public class Cell {
private final StackPane container;
private final Label indexLabel;
private final Label moreInfoLabel;
public Cell(int index) {
var square = new Rectangle(75, 75, Color.WHITE);
square.setStroke(Color.BLACK);
square.setStrokeWidth(1);
indexLabel = new Label(Integer.toString(index));
moreInfoLabel = new Label("More info!");
moreInfoLabel.setOpacity(0);
container = new StackPane(square, indexLabel, moreInfoLabel);
// must be instantiated after creating nodes
var animation = new CellAnimation();
container.addEventHandler(MouseEvent.MOUSE_ENTERED, e -> {
e.consume();
animation.playForward();
});
container.addEventHandler(MouseEvent.MOUSE_EXITED, e -> {
e.consume();
animation.playBackward();
});
}
public Node getNode() {
return container;
}
private class CellAnimation {
private static final Duration DURATION = Duration.millis(250);
private final ParallelTransition transition;
private boolean rising;
private boolean changeViewOrder;
CellAnimation() {
var toCorner = createToCornerAnimation();
var fadeInOut = createFadeInAndOutAnimation();
var scale = createScaleAnimation();
transition = new ParallelTransition(toCorner, fadeInOut, scale);
transition.currentTimeProperty().addListener(obs -> {
if (changeViewOrder) {
var currentTime = transition.getCurrentTime();
var halfwayTime = transition.getCycleDuration().divide(2);
int compare = currentTime.compareTo(halfwayTime);
if (rising && compare >= 0) {
changeViewOrder = false;
container.setViewOrder(-2);
} else if (!rising && compare <= 0) {
changeViewOrder = false;
container.setViewOrder(-1);
}
}
});
transition.statusProperty().addListener((obs, oldVal, newVal) -> {
if (newVal == Animation.Status.RUNNING && rising) {
container.setViewOrder(-1);
} else if (newVal == Animation.Status.STOPPED && !rising) {
container.setViewOrder(0);
}
});
}
void playForward() {
rising = true;
changeViewOrder = true;
transition.setRate(1);
transition.play();
}
void playBackward() {
rising = false;
changeViewOrder = true;
transition.setRate(-1);
transition.play();
}
private Animation createToCornerAnimation() {
var toCorner = new TranslateTransition(DURATION, indexLabel);
toCorner.setFromX(0);
toCorner.setFromY(0);
toCorner.toXProperty().bind(indexLabel.layoutXProperty().negate().add(5));
toCorner.toYProperty().bind(indexLabel.layoutYProperty().negate().add(5));
return toCorner;
}
private Animation createFadeInAndOutAnimation() {
var fadeInOut = new FadeTransition(DURATION, moreInfoLabel);
fadeInOut.setFromValue(0);
fadeInOut.setToValue(1);
return fadeInOut;
}
private Animation createScaleAnimation() {
var scale = new ScaleTransition(DURATION, container);
scale.setFromX(1.0);
scale.setFromY(1.0);
scale.setToX(1.5);
scale.setToY(1.5);
return scale;
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
| 归档时间: |
|
| 查看次数: |
106 次 |
| 最近记录: |