加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

如何在JavaFX中以编程方式触发鼠标事件?

发布时间:2020-12-15 04:36:18 所属栏目:Java 来源:网络整理
导读:以下代码显示了两个面板,黄色和蓝色,其中蓝色是黄色的子项. 如果我单击蓝色面板的中心,将使用两个面板处理鼠标事件. 如何以编程方式模拟相同的行为? 在Fire事件按钮中,我尝试执行此操作,但失败:生成的事件似乎仅由黄色窗格处理. 是否可以发布事件,以便所有
以下代码显示了两个面板,黄色和蓝色,其中蓝色是黄色的子项.

如果我单击蓝色面板的中心,将使用两个面板处理鼠标事件.

如何以编程方式模拟相同的行为?

在Fire事件按钮中,我尝试执行此操作,但失败:生成的事件似乎仅由黄色窗格处理.

是否可以发布事件,以便所有孩子都像处理“本机”事件一样进行处理?

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class FireMouseEventProgrammatically extends Application {

   @Override
   public void start(Stage primaryStage) throws Exception {

      BorderPane root = new BorderPane();




      AnchorPane yellowPane = new AnchorPane();
      yellowPane.setBackground(new Background(new BackgroundFill(Color.YELLOW,CornerRadii.EMPTY,Insets.EMPTY)));
      yellowPane.setOnMouseClicked(new EventHandler<MouseEvent>() {
         @Override
         public void handle(MouseEvent event) {
            System.out.print("yellowPane clicked ");
            printMouseEvent(event);
            System.out.println("");
         }
      });

      root.setCenter(yellowPane);


      Pane bluePane = new Pane();
      bluePane.setBackground(new Background(new BackgroundFill(Color.BLUE,Insets.EMPTY)));
      bluePane.setOnMouseClicked(new EventHandler<MouseEvent>() {
         @Override
         public void handle(MouseEvent event) {
            System.out.print("bluePane clicked ");
            printMouseEvent(event);
            System.out.println("");
         }
      });

      AnchorPane.setLeftAnchor(bluePane,200.);
      AnchorPane.setRightAnchor(bluePane,200.);
      AnchorPane.setTopAnchor(bluePane,200.);
      AnchorPane.setBottomAnchor(bluePane,200.);


      yellowPane.getChildren().add(bluePane);




      FlowPane buttonPane = new FlowPane();
      buttonPane.setHgap(5);
      buttonPane.setPadding(new Insets(5,5,5));

      root.setBottom(buttonPane);



      Button fireEventButton = new Button();
      fireEventButton.setText("Fire event");
      fireEventButton.setOnAction(new EventHandler<ActionEvent>() {
         @Override
         public void handle(ActionEvent event) {

            double blueX = bluePane.getWidth()/2;
            double blueY = bluePane.getHeight()/2;

            Point2D screenCoords = bluePane.localToScreen(blueX,blueY);
            Point2D sceneCoords = bluePane.localToScene(blueX,blueY);

            Event.fireEvent(yellowPane,new MouseEvent(MouseEvent.MOUSE_CLICKED,sceneCoords.getX(),sceneCoords.getY(),screenCoords.getX(),screenCoords.getY(),MouseButton.PRIMARY,1,true,null));

         }
      });

      buttonPane.getChildren().add(fireEventButton);


      Scene scene = new Scene(root,800,600);
      primaryStage.setScene(scene);
      primaryStage.show();

   }

   private void printMouseEvent(MouseEvent event) {
      System.out.print(String.format("x = %f,y = %f,xScreen = %f,yScreen = %f",event.getX(),event.getY(),event.getScreenX(),event.getScreenY()));
   }

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

}

UPDATE

我不能明确提到子节点,因为一般情况下它可以是无数个子节点.

我怎么知道要瞄准哪一个?

我想传递坐标,让系统自动确定目标.

解决方法

实际(phisycal)点击和程序点击之间的区别在于,在第一种情况下,原始事件目标是bluePane(因为它是视觉上的“最上面的”节点),在后一种情况下,目标是yellowPane.

因此,当路由构造发生时(请参考Event Delivery Process section),路由将是root – > yellowPane – > bluePane,在第二种情况下,它只是root – > yellowPane,因此bluePane不受事件的影响.

基于此,您可以定位bluePane:

Event.fireEvent(bluePane,null));

或者您可以使用Robot来生成点击:

try {
    robot = new java.awt.Robot();

    robot.mouseMove((int)screenCoords.getX(),(int)screenCoords.getY());
    robot.mousePress(16);
    robot.mouseRelease(16);
    robot.mouseMove((int) originalLocation.getX(),(int)originalLocation.getY());
} catch (AWTException e) {
    e.printStackTrace();
}

更新1:

如果你想坚持使用JavaFX方式,现在的问题是如何确定位置上的“最上面”节点.

这是一件以干净的方式无法实现的事情.关于此已经有了feature request.

我在fxexperience上的辅助方法上找到了这个,可用于确定某个位置上的节点:

public static Node pick(Node node,double sceneX,double sceneY) {
    Point2D p = node.sceneToLocal(sceneX,sceneY,true /* rootScene */);

    // check if the given node has the point inside it,or else we drop out
    if (!node.contains(p)) return null;

    // at this point we know that _at least_ the given node is a valid
    // answer to the given point,so we will return that if we don't find
    // a better child option
    if (node instanceof Parent) {
        // we iterate through all children in reverse order,and stop when we find a match.
        // We do this as we know the elements at the end of the list have a higher
        // z-order,and are therefore the better match,compared to children that
        // might also intersect (but that would be underneath the element).
        Node bestMatchingChild = null;
        List<Node> children = ((Parent)node).getChildrenUnmodifiable();
        for (int i = children.size() - 1; i >= 0; i--) {
            Node child = children.get(i);
            p = child.sceneToLocal(sceneX,true /* rootScene */);
            if (child.isVisible() && !child.isMouseTransparent() && child.contains(p)) {
                bestMatchingChild = child;
                break;
            }
        }

        if (bestMatchingChild != null) {
            return pick(bestMatchingChild,sceneX,sceneY);
        }
    }

    return node;
}

您可以使用如下:

Node pick = pick(root,sceneCoords.getY());
Event.fireEvent(pick,null));

UPDATE2:

您还可以使用不推荐使用的方法Node.impl_pickNode(PickRay pickRay,PickResultChooser结果)来获取场景位置上的相交节点:

PickRay pickRay = new PickRay((int) sceneCoords.getX(),(int) sceneCoords.getY(),1.0,1.0);
PickResultChooser pickResultChooser = new PickResultChooser();
root.impl_pickNode(pickRay,pickResultChooser);
Node intersectedNode = pickResultChooser.getIntersectedNode();

您也可以同样使用此节点作为目标.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读