JavaFX - обработчики событий для различных объектов, созданных циклом for

Я хочу создать набор из десяти различных кругов с циклом for, чтобы каждый из них менял цвет при наведении курсора мыши на один из них, а также менял их на третий цвет щелчком мыши. Однако только один из кругов - последний из созданных в цикле - имеет изменения цвета, независимо от того, на какой круг щелкнули или навели курсор. Может кто-нибудь объяснить мне, почему и как я могу это исправить? Я был бы очень признателен. Hier это мой код:

public class View extends Parent{
BorderPane gameScreen;
Group hexaBlock;
ArrayList<Circle> circleList = new ArrayList<>(); 
Circle circle;
...
public View(){
        gameScreen = new BorderPane();
        hexaBlock = new Group(); 
        ...
        for(int y=0; y<2; y++ ){
            for(double x=0; x<5; x++){
                circle = new Circle(xPosition(hexagon width*x), yPosition(hexagon height*4*y), radius);
                circleList.add(circle);
                circle.setFill(Color.BLACK);
                circle.setOnMousePressed(new EventHandler<MouseEvent>() {
                    @Override
                    public void handle(MouseEvent event) {
                        circle.setFill(Color.CYAN);
                    }
                });
                circle.addEventHandler(MouseEvent.MOUSE_ENTERED, new EventHandler<MouseEvent>(){
                    @Override
                    public void handle(MouseEvent t) {
                        circle.setFill(Color.RED);
                    }
                });
                circle.addEventHandler(MouseEvent.MOUSE_EXITED, new EventHandler<MouseEvent>(){
                     @Override
                        public void handle(MouseEvent t) {
                         circle.setFill(Color.BLACK);
                        }
                });
}
this.getChildren().add(gameScreen);
... 
gameScreen.setCenter(hexaBlock);
...
hexaBlock.getChildren().addAll(circleList);

.....

3 ответа

circle это поле. Когда выполняются обработчики событий, извлекается значение поля, и в этом случае оно содержит значение, присвоенное ему последним, то есть круг, созданный последним.

Обратите внимание, что вы можете получить доступ final (эффективно final для java >= 8) локальные переменные в окружающих областях из классов anonymus. Я рекомендую удалить circle поле и декларирование circle где вы присваиваете ему значение:

for(int y=0; y<2; y++ ){
    for(double x=0; x<5; x++){
        final Circle circle = new Circle(xPosition(hexagon width*x), yPosition(hexagon height*4*y), radius);

        ...
        // init circle handlers/properties
    }
}

Вот пример приложения. Это приложение использует лямбды для слушателей.

import java.util.Random;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

/**
 *
 * @author blj0011
 */
public class JavaFXApplication54 extends Application
{

    @Override
    public void start(Stage primaryStage)
    {
        Random random = new Random();

        AnchorPane root = new AnchorPane();

        for (int i = 0; i < 5; i++)
        {
            int x1 = random.nextInt(300);
            System.out.println("l: " + x1);
            int y1 = random.nextInt(250);
            int radius = random.nextInt(10) + 3;
            root.getChildren().add(getCircle(x1, y1, radius));
        }

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)
    {
        launch(args);
    }

    Circle getCircle(int x1, int y1, int radius)
    {
        Circle tempCircle = new Circle(x1, y1, radius);
        tempCircle.setFill(Color.BLACK);

        tempCircle.setOnMousePressed(me -> tempCircle.setFill(Color.CYAN));
        tempCircle.setOnMouseEntered(me -> tempCircle.setFill(Color.RED));
        tempCircle.setOnMouseExited(me -> tempCircle.setFill(Color.BLACK));

        return tempCircle;
    }
}

Это мое мнение, раскомментируйте setOnMouseExited, если хотите, чтобы он снова стал черным.

import java.util.Random;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

public class CircleColours extends Application {

    private final Random random = new Random();

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

    @Override
    public void start(Stage primaryStage) {
        AnchorPane pane = new AnchorPane();
        Scene scene = new Scene(pane, 600, 400);
        addCircles(pane, 10, 50);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public void addCircles(AnchorPane pane, int amount, int radius) {
        for (int i = 0; i < amount; i++) {
            Circle circle = new Circle(random.nextInt((int) pane.getWidth()), random.nextInt((int) pane.getHeight()), radius);
            circle.setOnMouseEntered(event -> circle.setFill(Color.rgb(random.nextInt(255), random.nextInt(255), random.nextInt(255))));
            circle.setOnMouseClicked(event -> circle.setFill(Color.rgb(random.nextInt(255), random.nextInt(255), random.nextInt(255))));
            //circle.setOnMouseExited(event -> circle.setFill(Color.BLACK));
            pane.getChildren().add(circle);
        }
    }

}
Другие вопросы по тегам