超过一半重叠时突出显示矩形

Highlighting rectangle when more than half overlaps

我有一个 JavaFX 应用程序,它有一个包含矩形的窗格。这些矩形可以通过拖动鼠标来移动。

当我将一个矩形拖到另一个矩形上时,我希望突出显示第二个(背景)矩形。这有效,请参见下面的代码

private boolean moveInProgress;
private Point2D prevPos;

public void onMousePressed(MouseEvent event) {
    setMouseTransparent(true);
    Point2D point = new Point2D(event.getSceneX(), event.getSceneY());

    if (!moveInProgress) {
        moveInProgress = true;

        prevPos = point;
        LOG.debug("Mouse move started on location " + prevPos);
    }

    event.consume();
}

public void onMouseDragged(MouseEvent event) {
    if (moveInProgress) {
        Point2D point = new Point2D(event.getSceneX(), event.getSceneY());
        this.toFront();

        double[] translationVector = new double[2];
        translationVector[0] = point.getX() - prevPos.getX();
        translationVector[1] = point.getY() - prevPos.getY();

        setTranslateX(getTranslateX() + translationVector[0]);
        setTranslateY(getTranslateY() + translationVector[1]);

        prevPos = point;
    }

    event.consume();
}

public void onMouseReleased(MouseEvent event) {
    setMouseTransparent(false);

    if (moveInProgress) {
        moveInProgress = false;
    }
    event.consume();
}

public void onDragDetected(MouseEvent event) {
    startFullDrag();
    event.consume();
}

public void onMouseDragEntered(MouseDragEvent event) {
    getStyleClass().add("drag-target");
    event.consume();
}

public void onMouseDragExited(MouseDragEvent event) {
    if (getStyleClass().contains("drag-target")) {
        getStyleClass().remove("drag-target");
    }
    event.consume();
}

当超过一半的拖动矩形重叠时,我想突出显示下面的矩形。在这张照片中,我想突出显示红色矩形,因为灰色矩形重叠了一半以上。

问题是 MouseDragEntered 和 MouseDragExited 事件是根据我的鼠标位置触发的。当我的鼠标位置例如图中的黑点时,我的鼠标事件只会在我的鼠标进入红色矩形时触发。

任何人都可以告诉我如何在灰色矩形的拖动操作期间突出显示红色矩形,其中一半以上重叠吗?

一种方法是让每个矩形观察正在拖动的矩形的边界。然后使用 Shape.intersect(或通过其他方式)进行计算以查看矩形是否被拖动的矩形覆盖了 50% 是相当容易的。这里棘手的部分是将侦听器添加到被拖动的矩形中,并在矩形停止拖动时再次删除它们。

这是一个简单的例子。我认为我的设置方式与您设置它们的方式略有不同,但您应该能够轻松地使其适应您的用例。

import java.util.Random;

import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.css.PseudoClass;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;

public class DraggingHighlightRectangles extends Application {

    private final Random rng = new Random();
    private final ObjectProperty<Rectangle> draggingRectangle = new SimpleObjectProperty<>();

    @Override
    public void start(Stage primaryStage) {
        Pane pane = new Pane();
        pane.setMinSize(600, 600);

        Button newRectButton = new Button("New Rectangle");
        newRectButton.setOnAction(e -> pane.getChildren().add(createRectangle()));

        BorderPane.setAlignment(newRectButton, Pos.CENTER);
        BorderPane.setMargin(newRectButton, new Insets(5));

        BorderPane root = new BorderPane(pane);
        root.setBottom(newRectButton);

        Scene scene = new Scene(root);
        scene.getStylesheets().add("style.css");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private Rectangle createRectangle() {
        Rectangle rect = new Rectangle(rng.nextInt(400)+100, rng.nextInt(500)+50, 100, 50);
        rect.setFill(randomColor());
        rect.getStyleClass().add("rect");

        ChangeListener<Bounds> boundsListener = (obs, oldBounds, newBounds) -> {
            double myArea = rect.getWidth() * rect.getHeight() ;
            Shape intersection = Shape.intersect(draggingRectangle.get(), rect);
            Bounds intersectionBounds = intersection.getBoundsInLocal();
            double intersectionArea = intersectionBounds.getWidth() * intersectionBounds.getHeight() ;
            rect.pseudoClassStateChanged(PseudoClass.getPseudoClass("highlight"), intersectionArea >= 0.5 * myArea);
        };

        draggingRectangle.addListener((obs, oldRect, newRect) -> {
            if (oldRect != null) {
                oldRect.boundsInLocalProperty().removeListener(boundsListener);
            }
            if (newRect != null && newRect != rect) {
                newRect.boundsInLocalProperty().addListener(boundsListener);
            }
            rect.pseudoClassStateChanged(PseudoClass.getPseudoClass("highlight"), false);
        });

        class MouseLocation { double x, y ; }
        MouseLocation mouseLocation = new MouseLocation();

        rect.setOnMousePressed(e -> {
            draggingRectangle.set(rect);
            rect.toFront();
            mouseLocation.x = e.getX() ;
            mouseLocation.y = e.getY() ;
        });

        rect.setOnMouseDragged(e -> {
            rect.setX(rect.getX() + e.getX() - mouseLocation.x);
            rect.setY(rect.getY() + e.getY() - mouseLocation.y);
            mouseLocation.x = e.getX() ;
            mouseLocation.y = e.getY() ;
        });

        rect.setOnMouseReleased(e -> draggingRectangle.set(null));

        return rect ;
    }

    private Color randomColor() {
        return Color.rgb(rng.nextInt(256), rng.nextInt(256), rng.nextInt(256));
    }

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

我的样式表,style.css,只包含

.rect:highlight {
    -fx-fill: yellow ;
}