JavaFX如何根据鼠标点击判断所点击的Label位置
如何在JavaFX中识别被点击的Label(对应Swing的等效实现)
我尝试编写代码找出被点击的Label,通过事件监听器用getX()和getY()获取了事件位置,但找不到合适的Label位置方法进行对比。
现有JavaFX代码
public class Beta extends Application { final Label[] answerLabel = new Label[4]; @Override public void start(Stage primaryStage) { GridPane root = new GridPane(); root.setGridLinesVisible(true); final int numCols = 7 ; final int numRows = 12 ; for (int i = 0; i < numCols; i++) { ColumnConstraints colConst = new ColumnConstraints(); colConst.setPercentWidth(100.0 / numCols); root.getColumnConstraints().add(colConst); } for (int i = 0; i < numRows; i++) { RowConstraints rowConst = new RowConstraints(); rowConst.setPercentHeight(100.0 / numRows); root.getRowConstraints().add(rowConst); } for(int i = 0; i<4; i++){ answerLabel[i] = new Label(); answerLabel[i].setMaxWidth(Double.MAX_VALUE); answerLabel[i].setMaxHeight(Double.MAX_VALUE); answerLabel[i].setStyle("-fx-background-color: blue;-fx-font-size: 7pt;-fx-padding: 0;"); answerLabel[i].setPadding(new Insets(10)); answerLabel[i].setCursor(Cursor.HAND); root.add(answerLabel[i], 3, i +5, 1, 1); answerLabel[i].setOnMouseClicked(new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent e) { answerLabelPressed(e); } }); } primaryStage.setScene(new Scene(root, 900, 500)); primaryStage.show(); } private void answerLabelPressed(MouseEvent e) { int labelSelected; double px = e.getX(); double py = e.getY(); System.out.println("px = " + px + " py = " + py); for (labelSelected = 0; labelSelected < 4; labelSelected++) { System.out.println("answerLabel[labelSelected].getLayoutX() = " + answerLabel[labelSelected].getLayoutX()); System.out.println("answerLabel[labelSelected].getLayoutY() = " + answerLabel[labelSelected].getLayoutY()); } } public static void main(String[] args) { launch(args); } }
代码输出
px = 42.0 py = 7.0 answerLabel[labelSelected].getLayoutX() = 386.0 view.answerLabel[labelSelected].getLayoutY() = 208.0 answerLabel[labelSelected].getLayoutX() = 386.0 view.answerLabel[labelSelected].getLayoutY() = 250.0 answerLabel[labelSelected].getLayoutX() = 386.0 view.answerLabel[labelSelected].getLayoutY() = 292.0 answerLabel[labelSelected].getLayoutX() = 386.0 view.answerLabel[labelSelected].getLayoutY() = 333.0
更新说明:对比Java Swing实现
我的核心需求是找到JavaFX中对应Java Swing的等效实现。多数Java书籍提到的一种更优写法如下:
MouseListener ml = new MouseListener() { public void mouseClicked(MouseEvent e) { report("mouseClicked", e.paramString()); } }
Swing中获取组件位置并对比的代码:
Point p = e.getComponent().getLocation(); System.out.println("px = " + p.getX() + " py = " + p.getY()); for (labelSelected = 0; labelSelected < 4; labelSelected++) { System.out.println("answerLabel[labelSelected].getX() = " + answerLabel[labelSelected].getX()); System.out.println("answerLabel[labelSelected].getY() = " + answerLabel[labelSelected].getY()); }
解决方案
1. 直接获取点击的源组件(最优方案)
无需对比坐标,JavaFX的MouseEvent提供了getSource()方法,直接返回触发事件的组件,强转为Label即可:
修改事件绑定逻辑(推荐用Lambda简化代码):
answerLabel[i].setOnMouseClicked(e -> { Label clickedLabel = (Label) e.getSource(); // 找到该Label在数组中的索引 for (int j = 0; j < answerLabel.length; j++) { if (answerLabel[j] == clickedLabel) { System.out.println("点击了第" + (j + 1) + "个Label"); // 这里可以添加后续处理逻辑 break; } } });
或者修改answerLabelPressed方法:
private void answerLabelPressed(MouseEvent e) { Label clickedLabel = (Label) e.getSource(); // 处理点击逻辑 }
2. 坐标对比方案(不推荐,仅作参考)
如果一定要通过坐标判断,需要使用组件在父容器中的实际边界范围,而非单纯的布局坐标:
private void answerLabelPressed(MouseEvent e) { double sceneX = e.getSceneX(); double sceneY = e.getSceneY(); for (int labelSelected = 0; labelSelected < 4; labelSelected++) { // 获取Label在父容器中的实际边界 Bounds bounds = answerLabel[labelSelected].getBoundsInParent(); // 将边界转换为场景坐标 Bounds sceneBounds = answerLabel[labelSelected].localToScene(bounds); // 判断点击位置是否在Label范围内 if (sceneX >= sceneBounds.getMinX() && sceneX <= sceneBounds.getMaxX() && sceneY >= sceneBounds.getMinY() && sceneY <= sceneBounds.getMaxY()) { System.out.println("点击了第" + (labelSelected + 1) + "个Label"); break; } } }
解释:e.getX()返回的是点击位置在组件内部的坐标,而getLayoutX()/getLayoutY()是组件在父容器中的布局坐标,受padding、insets等影响,直接对比不准确。getBoundsInParent()能获取组件在父容器中的实际占据区域,再通过localToScene()转换为场景坐标,和e.getSceneX()/e.getSceneY()对比即可准确判断。
Swing与JavaFX对应关系
- Swing的
e.getComponent()→ JavaFX的e.getSource() - Swing的
Component.getX()/getY()→ JavaFX的Node.getLayoutX()/getLayoutY() - 更可靠的范围判断:Swing用
getBounds(),JavaFX用getBoundsInParent()/getBoundsInScene()
内容的提问来源于stack exchange,提问作者Space
相关产品推荐
相关产品推荐

