As the title basically. I have a node in JavaFX which I want to be displayed in front of all other nodes according to certain CSS rules. I do not want this to change the ordering of the nodes in my VBox
which .toFront()
appears to do. See this question.
Is this even possible?
EDIT: To clarify. The situation is the following. I have a VBox
containing a bunch of tightly packed ImageView
s. When I hover over one I want it to grow slightly to give it the feel that the image is being lifted off of the screen. But since the ImageView
s are so tightly packed only the top edge grows (visibly). The bottom edge grows but is below the following image and cannot be seen.
EDIT 2: Upon request here is a screenshot of what I am doing.
The different colour gradients are ImageView
s and as I hover over one it should grow as the top edge of the top gradient has in this image (look closely at the top right corner next to the X). However as is also visible in this image the bottom edge of this ImageView
has become hidden by the next gradient in this VBox
and the grow is not visible.
This sounds like the perfect situation for using the viewOrder
property of Node
added in Java 9. The viewOrder
controls how Node
s are drawn in relation to other Node
s of the same Parent
without changing the order of the Node
s in the child list. Here's the Javadoc:
Defines the rendering and picking order of this Node within its parent.
This property is used to alter the rendering and picking order of a node within its parent without reordering the parent's children list. For example, this can be used as a more efficient way to implement transparency sorting. To do this, an application can assign the viewOrder value of each node to the computed distance between that node and the viewer.
The parent will traverse its children in decreasing viewOrder order. This means that a child with a lower viewOrder will be in front of a child with a higher viewOrder. If two children have the same viewOrder, the parent will traverse them in the order they appear in the parent's children list.
However, viewOrder does not alter the layout and focus traversal order of this Node within its parent. A parent always traverses its children list in order when doing layout or focus traversal.
Here's an example using this property:
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]);
}
}
It uses Rectangle
s instead of ImageView
s but the concept is the same. When the mouse hovers over a Rectangle
it sets the view order to be lower than the others and then plays a ScaleTransition
to make it bigger. When the mouse exits it resets the view order back to 0
and then reverses the ScaleTransition
.
Note: I used the var
keyword which was added in Java 10.
And here is a GIF of the example in action:
Edit: Since you brought up CSS I went and checked if the view order could be set from a stylesheet. And it appears it can. Looking at the CSS Reference Guide there is a CSS property defined for Node
named -fx-view-order
.