如何在JavaFX中以编程方式触发鼠标事件?
以下代码显示了两个面板,黄色和蓝色,其中蓝色是黄色的子项.
如果我单击蓝色面板的中心,将使用两个面板处理鼠标事件. 如何以编程方式模拟相同的行为? 在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(); 您也可以同样使用此节点作为目标. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |