JavaFX事件处理程序不再工作

时间:2016-04-14 02:19:55

标签: javafx event-handling

在我的代码中,我创建了一个最初工作的事件处理程序;但是在添加更多代码之后它停止了工作,所以我恢复到我的更改之前它仍然无法工作。有什么我做错了吗?另外,如果这有助于确定原因,我正在使用eclipse。

Main.java:     包裹申请;

import java.util.ArrayList;

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.input.InputEvent;
import javafx.scene.input.MouseEvent;


public class Main extends Application {
    public Parent root;
    public ChessUtil chess = new ChessUtil();
    @Override
    public void start(Stage primaryStage) {
        try {
            root = FXMLLoader.load(getClass().getResource("/Chess.fxml"));
            Node peice;
            for(int x = 0; x < 16 ;x++)
            {
                peice = root.lookup("#" + chess.whiteID[x]);
                peice.addEventHandler(MouseEvent.MOUSE_CLICKED, peiceClick);
                peice = root.lookup("#" + chess.blackID[x]);
                peice.addEventHandler(MouseEvent.MOUSE_CLICKED, peiceClick);
            }
            disablePeicesToggle(chess.blackID, true);
            Scene scene = new Scene(root,740,740);
            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    EventHandler peiceClick = new EventHandler<InputEvent>() {
        public void handle(InputEvent event) {
            String id = ((Node) event.getSource()).getId();
            ArrayList<String> moves = chess.findPeiceMoves(id);
            System.out.println(moves.size());
            if(moves.size() > 0)
            {
                System.out.println(moves);
            }
            System.out.println("Handling event " + event.getEventType()); 
            event.consume();
        }
     };
    public void disablePeicesToggle(String[] idSet, boolean disable)
    {
        Node peice;
        for(int x = 0; x < 16 ;x++)
        {
            peice = root.lookup("#" + idSet[x]);
            peice.setDisable(disable);
        }

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

Chess.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="740.0" prefWidth="740.0" stylesheets="@application/application.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <AnchorPane id="chessboard" layoutX="10.0" layoutY="10.0" prefHeight="720.0" prefWidth="720.0" stylesheets="@application/application.css" />
      <AnchorPane id="board-spaces" layoutX="50.0" layoutY="50.0" prefHeight="640.0" prefWidth="640.0">
         <children>
            <Region id="b7" prefHeight="80.0" prefWidth="80.0" styleClass="bRook" />
            <Region id="b3" layoutX="160.0" prefHeight="80.0" prefWidth="80.0" styleClass="bBishop" />
            <Region id="b5" layoutX="80.0" prefHeight="80.0" prefWidth="80.0" styleClass="bKnight" />
            <Region id="b2" layoutX="240.0" prefHeight="80.0" prefWidth="80.0" styleClass="bQueen" />
            <Region id="b1" layoutX="320.0" prefHeight="80.0" prefWidth="80.0" styleClass="bKing" />
            <Region id="b4" layoutX="400.0" prefHeight="80.0" prefWidth="80.0" styleClass="bBishop" />
            <Region id="b6" layoutX="480.0" prefHeight="80.0" prefWidth="80.0" styleClass="bKnight" />
            <Region id="b8" layoutX="560.0" prefHeight="80.0" prefWidth="80.0" styleClass="bRook" />
            <Region id="b12" layoutX="240.0" layoutY="80.0" prefHeight="80.0" prefWidth="80.0" styleClass="bPawn" />
            <Region id="b10" layoutX="80.0" layoutY="80.0" prefHeight="80.0" prefWidth="80.0" styleClass="bPawn" />
            <Region id="b13" layoutX="320.0" layoutY="80.0" prefHeight="80.0" prefWidth="80.0" styleClass="bPawn" />
            <Region id="b16" layoutX="560.0" layoutY="80.0" prefHeight="80.0" prefWidth="80.0" styleClass="bPawn" />
            <Region id="b9" layoutY="80.0" prefHeight="80.0" prefWidth="80.0" styleClass="bPawn" />
            <Region id="b15" layoutX="480.0" layoutY="80.0" prefHeight="80.0" prefWidth="80.0" styleClass="bPawn" />
            <Region id="b11" layoutX="160.0" layoutY="80.0" prefHeight="80.0" prefWidth="80.0" styleClass="bPawn" />
            <Region id="b14" layoutX="400.0" layoutY="80.0" prefHeight="80.0" prefWidth="80.0" styleClass="bPawn" />
            <Region id="w3" layoutX="160.0" layoutY="560.0" prefHeight="80.0" prefWidth="80.0" styleClass="wBishop" />
            <Region id="w12" layoutX="240.0" layoutY="480.0" prefHeight="80.0" prefWidth="80.0" styleClass="wPawn" />
            <Region id="w10" layoutX="80.0" layoutY="480.0" prefHeight="80.0" prefWidth="80.0" styleClass="wPawn" />
            <Region id="w5" layoutX="80.0" layoutY="560.0" prefHeight="80.0" prefWidth="80.0" styleClass="wKnight" />
            <Region id="w7" layoutY="560.0" prefHeight="80.0" prefWidth="80.0" styleClass="wRook" />
            <Region id="w14" layoutX="400.0" layoutY="480.0" prefHeight="80.0" prefWidth="80.0" styleClass="wPawn" />
            <Region id="w1" layoutX="320.0" layoutY="560.0" prefHeight="80.0" prefWidth="80.0" styleClass="wKing" />
            <Region id="w2" layoutX="240.0" layoutY="560.0" prefHeight="80.0" prefWidth="80.0" styleClass="wQueen" />
            <Region id="w6" layoutX="480.0" layoutY="560.0" prefHeight="80.0" prefWidth="80.0" styleClass="wKnight" />
            <Region id="w13" layoutX="320.0" layoutY="480.0" prefHeight="80.0" prefWidth="80.0" styleClass="wPawn" />
            <Region id="w16" layoutX="560.0" layoutY="480.0" prefHeight="80.0" prefWidth="80.0" styleClass="wPawn" />
            <Region id="w9" layoutY="480.0" prefHeight="80.0" prefWidth="80.0" styleClass="wPawn" />
            <Region id="w15" layoutX="480.0" layoutY="480.0" prefHeight="80.0" prefWidth="80.0" styleClass="wPawn" />
            <Region id="w11" layoutX="160.0" layoutY="480.0" prefHeight="80.0" prefWidth="80.0" styleClass="wPawn" />
            <Region id="w8" layoutX="560.0" layoutY="560.0" prefHeight="80.0" prefWidth="80.0" styleClass="wRook" />
            <Region id="w4" layoutX="400.0" layoutY="560.0" prefHeight="80.0" prefWidth="80.0" styleClass="wBishop" />
         </children></AnchorPane>
         <AnchorPane id="board-overlay" layoutX="60.0" layoutY="60.0" prefHeight="640.0" prefWidth="640.0" />
   </children>
</AnchorPane>

更新:我已将我的代码放在GitHub仓库中。  完整源代码在github.com/stitch366/chess/tree/master/chess。

1 个答案:

答案 0 :(得分:0)

您已将锚定窗格(ID为board-overlay)放置在主布局中的所有其他组件之上。它出现在“顶部”(按Z顺序),因为你把它放在最后。当用户点击电路板时,由于该节点位于顶部,它接收鼠标事件;因此,代表作品的Region没有一个接收鼠标事件并调用监听器。

目前尚不清楚为什么需要覆盖:很明显,如果你只是删除它,一切都会起作用。如果由于其他原因需要它,可以通过在FXML中设置mouseTransparent="true"来阻止它拦截鼠标事件:

<AnchorPane id="board-overlay" layoutX="60.0" layoutY="60.0" 
    prefHeight="640.0" prefWidth="640.0" mouseTransparent="true"/>

可能偏离主题:

您的应用程序结构 非常强烈不推荐 Application子类的目的是管理应用程序生命周期:即启动应用程序(start(...)方法)并在需要时干净地关闭它(stop()方法) 。应用程序类不负责管理用户事件:这是控制器类的明确目的。我 强烈 建议重构此操作,以便在控制器中管理您的事件处理。一个原因(主要原因)是,通过这样做,您的应用程序变得更加灵活。 (例如,如果你想要一个应用程序,其中多个游戏显示在不同的选项卡中,那么从现在的位置进行重构将非常困难。使用控制器来管理每个FXML的事件处理将非常容易。)另一个原因是使用查找是非常脆弱的:通常它依赖于已经应用于场景图的CSS,默认情况下,直到第一次将场景实际渲染到屏幕时才会发生。这似乎可以正常工作,可能是因为CSS ID是明确设置的,但实际上并不能保证这将在JavaFX的未来版本中有效。

我会重构您的应用程序类,以便它不会启动应用程序(这是它的责任):

package application;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;


public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            Parent root = FXMLLoader.load(getClass().getResource("/Chess.fxml"));

            Scene scene = new Scene(root,740,740);
            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        launch(args);
    }
}

并将事件处理移至控制器类:

package application;


import java.util.ArrayList;

import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;

public class Controller {

    @FXML
    private AnchorPane root ;

    private ChessUtil chess = new ChessUtil();

    @FXML
    private void click(MouseEvent event) {
        String id = ((Node) event.getSource()).getId();
        ArrayList<String> moves = chess.findPeiceMoves(id);
        System.out.println(moves.size());
        if(moves.size() > 0)
        {
            System.out.println(moves);
        }
        System.out.println("Handling event " + event.getEventType()); 
        event.consume();
    }

    public void initialize() {
        disablePeicesToggle(chess.blackID, true);
    }


    public void disablePeicesToggle(String[] idSet, boolean disable)
    {
        Node peice;
        for(int x = 0; x < 16 ;x++)
        {
            peice = root.lookup("#" + idSet[x]);
            peice.setDisable(disable);
        }

    }
}

然后只需更新FXML以引用根节点,并将表示一个片段的每个Region映射到控制器中的事件处理程序方法:

<AnchorPane prefHeight="740.0" prefWidth="740.0" stylesheets="@application/application.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
        fx:controller="application.Controller" fx:id="root">
   <children>
      <AnchorPane id="chessboard" layoutX="10.0" layoutY="10.0" prefHeight="720.0" prefWidth="720.0" stylesheets="@application/application.css"/>
      <AnchorPane id="board-spaces" layoutX="50.0" layoutY="50.0" prefHeight="640.0" prefWidth="640.0">
         <children>
            <Region id="b7" prefHeight="80.0" prefWidth="80.0" styleClass="bRook" onMouseClicked="#click" />
            <Region id="b3" layoutX="160.0" prefHeight="80.0" prefWidth="80.0" styleClass="bBishop" onMouseClicked="#click" />
            <Region id="b5" layoutX="80.0" prefHeight="80.0" prefWidth="80.0" styleClass="bKnight" onMouseClicked="#click" />

            <!-- etc... -->
         </children></AnchorPane>
         <AnchorPane id="board-overlay" layoutX="60.0" layoutY="60.0" 
             prefHeight="640.0" prefWidth="640.0" mouseTransparent="true"/>
   </children>
</AnchorPane>