如何在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(); 您也可以同样使用此节点作为目标. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
