JavafX & CSS - переместить узел вперед - PullRequest
0 голосов
/ 27 июня 2018

Как заголовок в основном. У меня есть узел в JavaFX, который я хочу отображать перед всеми остальными узлами в соответствии с определенными правилами CSS. Я не хочу, чтобы это изменило порядок узлов в моем VBox, что, похоже, делает .toFront(). См. этот вопрос.

Возможно ли это вообще?

РЕДАКТИРОВАТЬ: Чтобы уточнить. Ситуация следующая. У меня есть VBox, содержащий кучу плотно упакованных ImageView с. Когда я наводю курсор мыши на одну из них, я хочу, чтобы она немного увеличилась, чтобы создать ощущение, что изображение снимается с экрана. Но так как ImageView s так плотно упакованы, только верхний край увеличивается (заметно). Нижний край увеличивается, но находится ниже следующего изображения и не виден.

РЕДАКТИРОВАТЬ 2: По запросу вот скриншот того, что я делаю.

enter image description here

Различные цветовые градиенты составляют ImageView с, и когда я наведу курсор на один из них, он должен увеличиться, как и верхний край верхнего градиента на этом изображении (посмотрите внимательно на верхний правый угол рядом с X). Однако, как также видно на этом изображении, нижний край этого ImageView стал скрыт следующим градиентом в этом VBox, и рост не виден.

Ответы [ 3 ]

0 голосов
/ 28 июня 2018

С моей точки зрения, у вас есть VBox с интервалом 0, поэтому каждый 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;
    }
0 голосов
/ 28 июня 2018

Это похоже на идеальную ситуацию для использования viewOrder свойства Node, добавленного в Java 9. viewOrder контролирует, как Node s рисуется относительно других Node с одинаковыми Parent без изменения порядка Node в дочернем списке. Вот этот 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]);
    }

}

Используется Rectangle с вместо ImageView с, но концепция та же. Когда мышь наводит курсор на Rectangle, она устанавливает порядок просмотра ниже, чем у других, а затем воспроизводит ScaleTransition, чтобы увеличить его. Когда мышь выходит, она сбрасывает порядок просмотра обратно на 0, а затем переворачивает ScaleTransition.

Примечание: я использовал ключевое слово var, которое было добавлено в Java 10.

А вот GIF-пример в действии:

the GIF of the application in action

Редактировать: Так как вы открыли CSS, я пошел и проверил, можно ли установить порядок просмотра из таблицы стилей. И кажется, что может. Глядя на Справочное руководство по CSS , для Node определено свойство CSS с именем -fx-view-order.

0 голосов
/ 28 июня 2018

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

Я не устанавливаю правильные координаты в этом примере, но это работает как подтверждение концепции.

В двух словах: захватить события onMouseEntered и onMouseExited и скрыть или показать новый этап.

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;
    }
}

Отсюда, это просто вопрос или фиксация координат сцены, которые должны быть центрированы по изображению, а затем удаление декорации сцены.

Известные проблемы:

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

...