当前位置: 首页 > 知识库问答 >
问题:

尝试使用JavaFX Gridpane推断鼠标拖动的位置

朱祺
2023-03-14

注:用Java 25年,用Java FX 2.5小时(差不多)。

我希望能够突出显示鼠标拖动过的GridPane的所有单元格——即与被点击点和当前拖动点包围的矩形相交的所有单元格。如果所有的孩子都是1x1,我可以这样做,但是对于混合大小,我不高兴。

例如,如果第一行有1个1列单元格(A)和1个2列单元格(B ),第二行有1个2列单元格(C)和1个1列单元格(D ),如果我单击A并向下拖动到C中,我可以突出显示这两个单元格。然而,我不知道什么时候我拖动到C的右半部分,以便B应该被突出显示。

样品板:

为HSCE道歉-它有点长,但我觉得去掉它会降低可读性。

import java.util.*;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent; 
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.*;
import javafx.scene.Node;
import javafx.stage.Stage;
import javafx.geometry.*;

public class AddTestSSCE extends Application
{
    ArrayList<StackPane> sPanes = new ArrayList<StackPane>(); // selected panes
    GridPane theGrid;
    Node startNode = null;
    int col0, col1;
    int row0, row1;

    @Override
    public void start(Stage stage) {
        theGrid = new GridPane();
        ColumnConstraints col = new ColumnConstraints(300);
        theGrid.getColumnConstraints().addAll(col, col, col);
        RowConstraints row = new RowConstraints(200);
        theGrid.getRowConstraints().addAll(row, row, row);
        addGridPane();
        theGrid.getStyleClass().add("bg-grid");
        Scene scene = new Scene(theGrid, 1024, 768);
        scene.getStylesheets().add("addtestssce.css");
        stage.setScene(scene);
        stage.show();
    }

    public void addGridPane() {
        theGrid.setHgap(10);
        theGrid.setVgap(10);
        theGrid.setPadding(new Insets(0, 10, 0, 10));

        StackPane theSP = sPAdd(new Label("A"));
        theGrid.add(theSP, 0, 0, 1, 1); 

        theSP = sPAdd(new Label("B"));
        theGrid.add(theSP, 1, 0, 2, 1);

        theSP = sPAdd(new Label("C"));
        theGrid.add(theSP, 0, 1, 2, 1);

        theSP = sPAdd(new Label("D"));
        theGrid.add(theSP, 2, 1, 1, 1);

        theGrid.addEventFilter(MouseEvent.MOUSE_PRESSED,     //Creating the mouse event handler 
        new EventHandler<MouseEvent>() { 
            @Override 
            public void handle(MouseEvent e) { 
                System.out.println("We're Moving!!");

                startNode = (Node)e.getTarget();
                sPanes.add((StackPane)startNode);
                col0 = GridPane.getColumnIndex(startNode).intValue();
                row0 = GridPane.getRowIndex(startNode).intValue();
                System.out.printf("Starting at %d %d\n", col0, row0);
            }
        });

        theGrid.addEventFilter(MouseEvent.MOUSE_DRAGGED,     //Creating the mouse event handler 
        new EventHandler<MouseEvent>() { 
            Node lastNode = null;

            @Override 
            public void handle(MouseEvent e) { 
                Node target = (Node)e.getTarget();
                double xLoc = e.getX();
                double yLoc = e.getY();
                Bounds bs = target.localToScene(target.getBoundsInLocal());
                Node moveTarget;
                if( bs.contains(xLoc, yLoc) )
                {
                    moveTarget = target;
                }
                else
                {
                    moveTarget = getContainingNode((int)xLoc, (int)yLoc);
                }
                if( moveTarget != null && lastNode != moveTarget )
                {
                    col1 = GridPane.getColumnIndex(moveTarget).intValue();
                    row1 = GridPane.getRowIndex(moveTarget).intValue();
                    doHighlighting();
                    lastNode = moveTarget;
                }
            }
        });
    }

    void doHighlighting()
    {
        int c0, c1, r0, r1;

        c0 = col0 > col1 ? col1 : col0;
        c1 = !(col0 > col1) ? col1 : col0;
        r0 = row0 > row1 ? row1 : row0;
        r1 = !(row0 > row1) ? row1 : row0;

        Rectangle2D rec1 = new Rectangle2D(c0, r0, c1-c0+1, r1-r0+1);

        System.out.printf("Box: %d %d %d %d\n", c0, c1, r0, r1);
        List<Node> nodes = theGrid.getChildren();
        for( Node node : nodes )
        {
            StackPane sp = (StackPane)node;
            unhighlight(sp);
            int col = GridPane.getColumnIndex(sp).intValue();
            int row = GridPane.getRowIndex(sp).intValue(); 

            if( occupiesCell(sp, rec1) )
            {
                highlight(sp);
            }
        }
    }

    boolean occupiesCell(Node node, Rectangle2D r1)
    {
        boolean result = false;
        int col = GridPane.getColumnIndex(node).intValue();
        int row = GridPane.getRowIndex(node).intValue(); 
        int wid = GridPane.getColumnSpan(node).intValue();
        int hei = GridPane.getRowSpan(node).intValue(); 

        Rectangle2D r2 = new Rectangle2D( col, row, wid, hei);

        return r2.intersects(r1);
    }

    void unhighlight(Node node)
    {
        if( !(node instanceof StackPane) )
        {
            return;
        }
        StackPane label = (StackPane)node;
        List<String> cList = label.getStyleClass();
        cList.remove("b2");
        cList.add("b1");
    }

    void highlight(Node node)
    {
        if( !(node instanceof StackPane) )
        {
            return;
        }
        StackPane label = (StackPane)node;
        List<String> cList = label.getStyleClass();
        cList.remove("b1");
        cList.add("b2");
    }

    private Node getContainingNode(int xLoc, int yLoc)
    {
        Node tgt = null;

        for( Node node : theGrid.getChildren() )
        {
            Bounds boundsInScene = node.localToScene(node.getBoundsInLocal());
            if( boundsInScene.contains(xLoc, yLoc) )
            {
                return node;
            }
        }

        return tgt;
    }

    private StackPane sPAdd(Label label)
    {
        StackPane gPPane = new StackPane();
        gPPane.getChildren().add(label);
        gPPane.getStyleClass().addAll("b1", "grid-element");
        GridPane.setFillHeight(gPPane, true);
        GridPane.setFillWidth(gPPane, true);

        return gPPane;
    }

    public static void main(String[] args)
    {
        launch();
    }
}
.bg-grid {
    -fx-background-color: slategrey;
}
.grid-element {
    -fx-border-width: 10; 
    -fx-border-color: rgb(225, 128, 217);
    -fx-background-color: rgb(247, 146, 146);
    -fx-font: 36 arial;
}

.b1 {
    -fx-text-base-color: white;
    -fx-border-color: rgb(225, 128, 217);
}
.b2 {
    -fx-text-base-color: lightgray;
    -fx-border-color: rgb(233, 228, 86);
}

共有1个答案

华凯捷
2023-03-14

经过与@james_d和@slaw的一些来回,终于想出了一个可行的解决方案。

import java.util.*;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent; 
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.*;
import javafx.scene.Node;
import javafx.stage.Stage;
import javafx.geometry.*;
import javafx.css.PseudoClass;

public class AddTestSSCE extends Application
{
    private static final PseudoClass highlight = PseudoClass.getPseudoClass("highlight"); 
    ArrayList<StackPane> sPanes = new ArrayList<StackPane>(); // selected panes
    GridPane theGrid;
    Node startNode = null;
    int x0, y0, x1, y1;

    @Override
    public void start(Stage stage) {
        theGrid = new GridPane();
        ColumnConstraints col = new ColumnConstraints(300);
        theGrid.getColumnConstraints().addAll(col, col, col);
        RowConstraints row = new RowConstraints(200);
        theGrid.getRowConstraints().addAll(row, row, row);
        addGridPane();
        theGrid.getStyleClass().add("bg-grid");
        Scene scene = new Scene(theGrid, 1024, 768);
        scene.getStylesheets().add("addtestssce.css");
        stage.setScene(scene);
        stage.show();
    }

    public void addGridPane() {
        theGrid.setHgap(10);
        theGrid.setVgap(10);
        theGrid.setPadding(new Insets(0, 10, 0, 10));

        StackPane theSP = sPAdd(new Label("A"));
        theGrid.add(theSP, 0, 0, 1, 1); 

        theSP = sPAdd(new Label("B"));
        theGrid.add(theSP, 1, 0, 2, 1);

        theSP = sPAdd(new Label("C"));
        theGrid.add(theSP, 0, 1, 2, 1);

        theSP = sPAdd(new Label("D"));
        theGrid.add(theSP, 2, 1, 1, 1);

        theGrid.addEventFilter(MouseEvent.MOUSE_PRESSED,     //Creating the mouse event handler 
        new EventHandler<MouseEvent>() { 
            @Override 
            public void handle(MouseEvent e) { 
                System.out.println("We're Moving!!");

                startNode = (Node)e.getTarget();
                sPanes.add((StackPane)startNode);
                x0 = x1 = (int)e.getX();
                y0 = y1 = (int)e.getY();
                doHighlighting();
                System.out.printf("Starting at %d %d\n", x0, y0);
            }
        });

        theGrid.addEventFilter(MouseEvent.MOUSE_DRAGGED,     //Creating the mouse event handler 
        new EventHandler<MouseEvent>() { 

            @Override 
            public void handle(MouseEvent e) { 
                Node target = (Node)e.getTarget();
                x1 = (int)e.getX();
                y1 = (int)e.getY();
                Bounds bs = target.localToScene(target.getBoundsInLocal());
                Node moveTarget;
                if( bs.contains(x1, y1) )
                {
                    moveTarget = target;
                }
                else
                {
                    moveTarget = getContainingNode( x1, y1);
                }
                if( moveTarget != null )
                {
                    doHighlighting();
                }
            }
        });
    }

    void doHighlighting()
    {
        int c0, c1, r0, r1;

        c0 = x0 > x1 ? x1 : x0;
        c1 = !(x0 > x1) ? x1 : x0;
        r0 = y0 > y1 ? y1 : y0;
        r1 = !(y0 > y1) ? y1 : y0;

        Bounds dragged = new BoundingBox(c0, r0, c1-c0+1, r1-r0+1);

        for (Node child : theGrid.getChildren()) 
        {
            child.pseudoClassStateChanged(highlight, dragged.intersects(child.getBoundsInParent())); 
        }
    }

    private Node getContainingNode(int xLoc, int yLoc)
    {
        Node tgt = null;

        for( Node node : theGrid.getChildren() )
        {
            Bounds boundsInScene = node.localToScene(node.getBoundsInLocal());
            if( boundsInScene.contains(xLoc, yLoc) )
            {
                return node;
            }
        }

        return tgt;
    }

    private StackPane sPAdd(Label label)
    {
        StackPane gPPane = new StackPane();
        gPPane.getChildren().add(label);
        gPPane.getStyleClass().addAll("b1", "grid-element");
        GridPane.setFillHeight(gPPane, true);
        GridPane.setFillWidth(gPPane, true);

        return gPPane;
    }

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

和CSS:

.bg-grid {
    -fx-background-color: slategrey;
}
.grid-element {
    -fx-border-width: 10; 
    -fx-border-color: rgb(225, 128, 217);
    -fx-background-color: rgb(247, 146, 146);
    -fx-font: 36 arial;
}

.grid-element:highlight {
    -fx-text-base-color: lightgray;
    -fx-border-color: rgb(233, 228, 86);
}
 类似资料:
  • 问题内容: 因此,正如标题所述,我想在鼠标拖动时移动椭圆。我先声明了椭圆并将其画出(因为我有8个椭圆,它们带有不同的颜色信息。四个是白色,另一个是红色)。我尝试做我对矩形所做的事情: 但这似乎不起作用。它给我一个错误 我有点困惑,因为我已经阅读了文档,并且Ellipse2D.Double存在这样的变量。 这是一个MCVE: 那么是否有替代算法,或者我只是在语法上缺少什么?我想知道解决方案。谢谢。

  • 当鼠标按下拖拽某div时,位置会跳一下,这个怎么解决? https://play.vuejs.org/#eNqlV29v20QY/yqHVamOlDmFl6GtxjQESExIE...

  • 在ListView中,我可以按下< kbd>Ctrl Shift并单击项目进行选择。但是,我想拖动鼠标来选择项目(如DataGridView)。我尝试了下面的代码,我遇到了这样的问题: 我的代码:

  • 我有一个带有多个选项卡的选项卡。我想通过在特定位置拖动选项卡来重新定位选项卡(就像我们能够在浏览器中排列选项卡一样。有什么办法可以实现它吗?

  • 本文向大家介绍VB键盘鼠标无动作调用程序的尝试,包括了VB键盘鼠标无动作调用程序的尝试的使用技巧和注意事项,需要的朋友参考一下 我想要实现的功能是,当键盘无输入、鼠标无移动或点击动作时调用程序。首先想到的是用钩子HOOK来获取键盘或者鼠标的动作,如果无动作时调用程序。我尝试的结果是HOOK来HOOK去总是有问题。 后来想到Windows的屏幕保护程序就是当键盘鼠标无动作时进入屏幕保护的,于是改变思

  • 问题内容: 我在JLabel中有一个图像。 我想要以下功能。 -我单击JLabel内部的位置(在图像上)。 -按下鼠标按钮,即可更改JLabel中图像的位置。(我将图片拖到JLabel中的不同位置) 好吧,这意味着在许多情况下,图片将被裁剪并且在视野之外。 请告诉我如何实现此功能? 什么是要添加到我的JLabel的正确事件监听器? 问题答案: 这是一个基本的例子… 通过将标签划分为3x3网格来工作