关闭应用程序后程序不会停止

Program doesn't stop after closing application

我尝试重新创建 Connect Four,我成功了。但我想通过每隔一段时间切换颜色,让玩家知道获胜的四张棋子在哪里。我对线程和编程中的时间概念不熟悉。

我也成功地给了用户这个指示,但是在我关闭应用程序后,控制台仍然有输出,当我使用 setOnCloseRequest 时也是如此。

其他几个问题:
1:对于我使用 html 名称的颜色,是使用十六进制三元组更好还是不使用偏好更好。
2: 为了不让网格和其他元素紧贴屏幕左侧,我添加了一个与背景颜色相同的边框,有没有更好的方法?
3:我没有创建将键码转换为整数的方法,而是在 init 函数中创建的。我这样做是因为我不知道如何传递关键事件。如何做到这一点?

代码如下:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class FourInARow extends Application {

GridPane boardGrid = new GridPane();

Label[][] labels = new Label[7][7];
Label statusLabel = new Label();
int[][] cell = new int[7][6];

int player = 0;
int won = 0;

String baseStyle = "-fx-background-radius: 40; -fx-min-width: 80; -fx-min-height: 80; -fx-alignment: center; -fx-border-width: 2; -fx-border-color: #000000;-fx-background-color: ";

ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();

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

private void init(Stage window){

    createLabels();
    startGame();

    Label above = new Label("Try to connect four discs in a row!");
    above.setStyle("-fx-font-size: 30; -fx-alignment: center; -fx-min-width: 600");
    boardGrid.setStyle("-fx-background-color: silver;-fx-border-color: #F4F4F4;-fx-border-width: 0 20 0 20");
    Button newGame = new Button("New Game");
    newGame.setStyle("-fx-min-width: 100;-fx-font-size:20");
    newGame.setOnAction(e -> startGame());
    statusLabel.setStyle("-fx-font-size: 30;-fx-alignment: center; -fx-min-width: 300;");
    HBox below = new HBox();
    below.setStyle("-fx-border-width: 0 0 0 20;-fx-border-color: #F4F4F4");
    below.getChildren().addAll(newGame, statusLabel);
    VBox layout = new VBox();
    layout.getChildren().addAll(above, boardGrid, below);
    Scene scene = new Scene(layout, 600, 620);
    scene.setOnKeyPressed(e -> {
        if (won == 0) {
            try {
                String k = e.getCode().toString();
                int l = k.length();
                int col = Integer.parseInt(k.substring(l - 1, l)) - 1;
                placeDisc(col, player);
                switchPlayer();
                updateScreen();
            } catch (NumberFormatException | ArrayIndexOutOfBoundsException error) {
                System.out.println("error: " + error);
            }
        }
    });
    window.setScene(scene);
    window.setTitle("Connect Four");

    threadThing();
}

private void threadThing() {
    service.scheduleAtFixedRate(() -> {
        try {
            wonStyle();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }, 0, 1, TimeUnit.SECONDS);
}

private void startGame() {
    cell = new int[7][6];
    won = player = 0;
    statusLabel.setText("");
    updateScreen();
}

private void updateScreen() {
    for (int i = 0; i < 7; i++) {
        for (int j = 0; j < 6; j++) {
            labels[i][j].setStyle(baseStyle + addStyle(cell[i][j]));
        }
        labels[i][6].setText(Integer.toString(i+1));
        labels[i][6].setStyle("-fx-alignment: center;-fx-min-width: 80;-fx-background-color: #F4F4F4;-fx-font-size: 30;");
    }

    switch(won) {
        case 1: statusLabel.setText("Blue has won!");break;
        case 2: statusLabel.setText("Yellow has won!");break;
    }
}

private String addStyle(int cell) {
    String style = "silver";
    switch(cell){
        case 1: style = "blue"; break;
        case 2: style = "yellow"; break;
        case 3: style = "darkblue"; break;
        case 4: style = "gold;"; break;
    }
    return style;
}

private void placeDisc(int col, int player) {
    for (int i = 5; i >= 0 ; i--) {
        if(cell[col][i] == 0){
            cell[col][i] = 1;
            if(player == 1) cell[col][i] = 2;
            break;
        }else{
            if(i==0) switchPlayer();
        }
    }
    checkWon();
}

private void checkWon() {
    for (int i = 0; i < 7; i++) {
        for (int j = 0; j < 6; j++) {
            if (cell[i][j] != 0) {
                try {
                    if (cell[i][j] == cell[i][j + 1] && cell[i][j] == cell[i][j + 2] && cell[i][j] == cell[i][j + 3]) {
                        won = cell[i][j];
                        cell[i][j] = cell[i][j + 1] = cell[i][j + 2] = cell[i][j + 3] = cell[i][j] + 2;
                    }
                }catch(ArrayIndexOutOfBoundsException error) {}
                try {
                    if (cell[i][j] == cell[i + 1][j] && cell[i][j] == cell[i + 2][j] && cell[i][j] == cell[i + 3][j]) {
                        System.out.println("Horizontal win");
                        won = cell[i][j];
                        cell[i][j] = cell[i + 1][j] = cell[i + 2][j] = cell[i + 3][j] = cell[i][j] + 2;
                    }
                }catch(ArrayIndexOutOfBoundsException error) {}
                try {
                    if (cell[i][j] == cell[i + 1][j + 1] && cell[i][j] == cell[i + 2][j + 2] && cell[i][j] == cell[i + 3][j + 3]) {
                        won = cell[i][j];
                        cell[i][j] = cell[i + 1][j + 1] = cell[i + 2][j + 2] = cell[i + 3][j + 3] = cell[i][j] + 2;
                    }
                }catch(ArrayIndexOutOfBoundsException error) {}
                try {
                    if (cell[i][j] == cell [i + 1][j - 1] && cell[i][j] == cell[i + 2][j - 2] && cell[i][j] == cell[i + 3][j - 3]) {
                        won = cell[i][j];
                        cell[i][j] = cell[i + 1][j - 1] = cell[i + 2][j - 2] = cell[i + 3][j - 3] = cell[i][j] + 2;
                    }
                }catch(ArrayIndexOutOfBoundsException error) {}
            }
        }
    }
}

private void switchPlayer() {
    if(player == 0) player = 2;
    player--;
}

private void createLabels() {
    for (int i = 0; i < 7; i++) {
        for (int j = 0; j < 7; j++) {
            labels[i][j] = new Label();
            boardGrid.add(labels[i][j], i, j);
        }
    }
}

private void wonStyle() throws InterruptedException {
    System.out.println("Test");
    boolean run = false;
    for (int i = 0; i < 7; i++) {
        for (int j = 0; j < 6; j++) {
            if(cell[i][j] > 2 && !run){
                Thread.sleep(500);
                addStyleFlicker();
                run = true;
            }
        }
    }
}

private void addStyleFlicker() throws InterruptedException {
    String[] styleOne = {"-fx-background-radius: 40; -fx-min-width: 80; -fx-min-height: 80; -fx-alignment: center; -fx-border-width: 2; -fx-border-color: #000000;-fx-background-color: blue;",
                         "-fx-background-radius: 40; -fx-min-width: 80; -fx-min-height: 80; -fx-alignment: center; -fx-border-width: 2; -fx-border-color: #000000;-fx-background-color: darkblue;"};
    String[] styleTwo = {"-fx-background-radius: 40; -fx-min-width: 80; -fx-min-height: 80; -fx-alignment: center; -fx-border-width: 2; -fx-border-color: #000000;-fx-background-color: yellow;",
                         "-fx-background-radius: 40; -fx-min-width: 80; -fx-min-height: 80; -fx-alignment: center; -fx-border-width: 2; -fx-border-color: #000000;-fx-background-color: gold;"};
    for (int i = 0; i < 7; i++) {
        for (int j = 0; j < 6; j++) {
            if(cell[i][j] == 3){
                labels[i][j].setStyle(styleOne[0]);
            }else if(cell[i][j] == 4){
                labels[i][j].setStyle(styleTwo[0]);
            }
        }
    }
    Thread.sleep(500);
    for (int i = 0; i < 7; i++) {
        for (int j = 0; j < 6; j++) {
            if(cell[i][j] == 3){
                labels[i][j].setStyle(styleOne[1]);
            }else if(cell[i][j] == 4) {
                labels[i][j].setStyle(styleTwo[1]);
            }
        }
    }
}

@Override
public void start(Stage window) throws Exception {
    init(window);
    window.show();
}
}

覆盖 stop() method from the Application class 将允许您关闭控制台应用程序:

@Override
public void stop() {
    System.exit(0);
}

根据线程 Java API 文档 class...

The Java Virtual Machine continues to execute threads until either of the following occurs:

  • The exit method of class Runtime has been called and the security manager has permitted the exit operation to take place.
  • All threads that are not daemon threads have died, either by returning from the call to the run method or by throwing an exception that propagates beyond the run method.

因此,您需要 Executor 来创建守护线程,这些线程将在 JVM 准备好退出时终止。您可以使用自定义线程工厂来执行此操作。这是一个非常简单的例子:

Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
        
        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            t.setDaemon(true);
            return t;
        }
    });