【问题标题】:JavafX & CSS - Move Node to FrontJavafX & CSS - 将节点移到前面
【发布时间】:2018-12-06 20:09:52
【问题描述】:

基本上就像标题一样。我在 JavaFX 中有一个节点,我希望根据某些 CSS 规则将其显示在所有其他节点的前面。我不希望这改变我的VBox 中节点的顺序,.toFront() 似乎这样做。请参阅this 问题。

这可能吗?

编辑:澄清一下。情况如下。我有一个VBox 包含一堆紧密包装的ImageViews。当我将鼠标悬停在一个上时,我希望它稍微变大,让它有一种图像被从屏幕上抬起的感觉。但是由于ImageViews 如此紧密地包装,只有顶部边缘会增长(可见)。底部边缘增大,但低于下图,无法看到。

编辑 2:根据要求,这里是我正在做的事情的屏幕截图。

不同的颜色渐变是ImageViews,当我将鼠标悬停在一个上时,它应该会随着此图像中顶部渐变的顶部边缘而增长(仔细查看右上角的 X 旁边)。然而,在这张图片中也可以看到,这个ImageView 的底部边缘已经被这个VBox 中的下一个渐变隐藏了,并且增长不可见。

【问题讨论】:

  • 据我所知,如果不实际重新排序节点(在窗格内等),不可能将节点设置在顶部,这只能通过调用 toFront() 或手动重新排序节点。
  • 我猜这是XY problem,通过提供一个小的可运行示例,我们可以为您提供替代方案或解决方法。老实说,我不能 100% 确定我理解你在这里想要达到的目标。也许截图可以更清楚地说明问题:P
  • 嗯,读了几次之后,我想我明白了:P。您可以在“选择”图像时使用 VBox 的间距,以便在底部显示发光。我会尝试重新创建它,也许我认为更好。
  • 我确实创建了新 Stage 方法的工作原型,但没有完成。但如果你决定走那条路,这很简单。挑战在于捕捉正确的鼠标事件并为新阶段设置坐标。
  • 看看NodeviewOrderProperty (Java 9+) 看看这是否对您有帮助。

标签: css javafx bringtofront


【解决方案1】:

这是一个这样的解决方案,创建一个新的舞台来显示放大的图像。

我没有在此示例中设置正确的坐标,但这可以作为概念证明。

简而言之:捕获onMouseEnteredonMouseExited 事件并隐藏或显示新阶段。

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class Main extends Application {

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

    @Override
    public void start(Stage primaryStage) {

        FlowPane root = new FlowPane();
        root.setHgap(5);
        root.setVgap(5);
        for (int i = 0; i < 25; i++) {
            root.getChildren().add(getImagePane());
        }

        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }

    private VBox getImagePane() {

        VBox pane = new VBox() {{
            setAlignment(Pos.CENTER);
            setPadding(new Insets(5));
            setWidth(50);
            setHeight(50);
            setStyle("-fx-border-color: black");
        }};

        ImageView img = new ImageView("sample/imageGallery/cerulean.png") {{
            setFitWidth(50);
            setFitHeight(50);
            setPreserveRatio(true);

            Stage stage = zoomedStage(pane, this);

            setOnMouseEntered(mouseEvent -> stage.show());
            setOnMouseExited(mouseEvent -> stage.hide());

        }};

        pane.getChildren().add(img);
        return pane;

    }

    private Stage zoomedStage(VBox parent, ImageView img) {

        Stage stage = new Stage();
        stage.setWidth(110);
        stage.setHeight(110);

        VBox pane = new VBox() {{
            setAlignment(Pos.CENTER);
            setPadding(new Insets(5));
            setWidth(110);
            setHeight(110);
            setStyle("-fx-border-color: black");
        }};

        pane.setPickOnBounds(false);

        ImageView zoomedImage = new ImageView(img.getImage());
        zoomedImage.setFitHeight(100);
        zoomedImage.setFitWidth(100);

        pane.getChildren().add(zoomedImage);

        stage.setScene(new Scene(pane));
        stage.initStyle(StageStyle.UNDECORATED);
        return stage;
    }
}

从这里开始,应该只是将舞台的坐标固定在图像的中心,然后移除舞台的装饰。

已知问题:

您还需要处理鼠标光标被新阶段阻止的问题。这将导致鼠标不断进入和退出图像缩略图的循环,导致放大阶段闪烁。

【讨论】:

    【解决方案2】:

    在我看来,您有一个间距为 0 的 VBox,因此每个 ImageView 彼此紧密排列,因此在每个图像中都不能很好地看到发光效果。在这种情况下,您可以在每次想要选择 ImageView 时添加一个边距,以“帮助”出现发光效果。

    对于 Java 8:

    遗憾的是,这不能从 CSS 中发生,因为 ImageView 没有提供任何设置边距或填充的规则。因此,您或多或少(在我看来)必然会通过代码编写该行为。 :

    private Node createImageView(String imageLink) {
            // Setting the image view
            ImageView imageView = new ImageView(imageLink);
    
            // setting the fit width of the image view
            imageView.setFitWidth(400);
    
            // Setting the preserve ratio of the image view
            imageView.setPreserveRatio(true);
    
            // Instantiating the Glow class
            Glow glow = new Glow();
    
            imageView.setOnMouseEntered(e -> {
                // setting level of the glow effect
                glow.setLevel(0.9);
                // Adding a margin on TOP and Bottom side just to make the 
                // glowing effect visible
                VBox.setMargin(imageView, new Insets(2,0,2,0));
            });
    
            imageView.setOnMouseExited(e -> {
                // remove the glow effect
                glow.setLevel(0.0);
                // remove the margins 
                VBox.setMargin(imageView, new Insets(0));
            });
    
            // Applying bloom effect to text
            imageView.setEffect(glow);
    
            return imageView;
        }
    

    【讨论】:

      【解决方案3】:

      这听起来像是使用 Java 9 中添加的 NodeviewOrder 属性的完美情况。viewOrder 控制如何绘制 Nodes 与相同 @987654330 的其他 Nodes 的关系@ 不改变子列表中Nodes 的顺序。这是 Javadoc:

      定义此节点在其父节点中的渲染和选取顺序。

      此属性用于更改渲染和拾取顺序 其父节点中的节点,而无需重新排序父节点的子列表。 例如,这可以作为一种更有效的方式来实现 透明排序。为此,应用程序可以分配 每个节点的 viewOrder 值到该节点之间的计算距离 节点和查看器。

      父级将按 viewOrder 降序遍历其子级。 这意味着 viewOrder 较低的孩子将在前面 具有更高 viewOrder 的孩子。如果两个孩子有相同的 viewOrder,父级会按照它们出现的顺序遍历它们 父母的孩子名单。

      但是,viewOrder 不会改变布局和焦点遍历顺序 此节点在其父节点中的。父母总是遍历它的孩子 在进行布局或焦点遍历时按顺序列出。

      以下是使用此属性的示例:

      import javafx.animation.ScaleTransition;
      import javafx.application.Application;
      import javafx.geometry.Insets;
      import javafx.geometry.Pos;
      import javafx.scene.Scene;
      import javafx.scene.layout.HBox;
      import javafx.scene.paint.Color;
      import javafx.scene.shape.Rectangle;
      import javafx.stage.Stage;
      import javafx.util.Duration;
      
      import java.util.ArrayList;
      
      public class Main extends Application {
      
          @Override
          public void start(Stage primaryStage) throws Exception {
              var box = new HBox(createRectangles(Color.DARKBLUE, Color.FIREBRICK, 25));
              box.setAlignment(Pos.CENTER);
              box.setPadding(new Insets(50, 20, 50, 20));
              primaryStage.setScene(new Scene(box));
              primaryStage.show();
          }
      
          private Rectangle[] createRectangles(Color start, Color end, int count) {
              var list = new ArrayList<Rectangle>(count);
              for (double i = 0; i < count; i++) {
                  var rect = new Rectangle(30, 60, start.interpolate(end, i / count));
      
                  var scaleTrans = new ScaleTransition(Duration.millis(250), rect);
                  scaleTrans.setFromX(1.0);
                  scaleTrans.setFromY(1.0);
                  scaleTrans.setToX(1.2);
                  scaleTrans.setToY(1.2);
      
                  rect.setOnMouseEntered(e -> {
                      scaleTrans.stop(); // <--- doesn't seem necessary*
                      scaleTrans.setRate(1.0);
                      rect.setViewOrder(-1.0);
                      scaleTrans.play();
                  });
                  rect.setOnMouseExited(e -> {
                      scaleTrans.stop(); // <--- doesn't seem necessary*
                      scaleTrans.setRate(-1.0);
                      rect.setViewOrder(0.0);
                      scaleTrans.play();
                  });
                  // *the "stop()"'s don't seem to be necessary. When I commented
                  // them out the animation still worked. In fact, the animation
                  // actually seems smoother in the situation where you move the
                  // mouse over and then away quickly (before the zoom-in completes).
      
                  list.add(rect);
              }
              return list.toArray(new Rectangle[0]);
          }
      
      }
      

      它使用Rectangles 而不是ImageViews,但概念是一样的。当鼠标悬停在Rectangle 上时,它会将视图顺序设置为低于其他顺序,然后播放ScaleTransition 以使其更大。当鼠标退出时,它会将视图顺序重置回0,然后反转ScaleTransition

      注意:我使用了 Java 10 中添加的 var 关键字。

      下面是实际示例的 GIF:

      编辑:既然你提到了 CSS,我就去检查是否可以从样式表中设置视图顺序。它似乎可以。查看CSS Reference Guide,有一个为Node 定义的名为-fx-view-order 的CSS 属性。

      【讨论】:

      • 这是一个很好的答案,也是对 JavaFX 的一个很好的补充。
      猜你喜欢
      • 1970-01-01
      • 2018-07-04
      • 2016-04-09
      • 1970-01-01
      • 2019-10-25
      • 2022-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多