Ошибка визуального холста в программе JavaFX для анимации алгоритмов поиска пути.JAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Ошибка визуального холста в программе JavaFX для анимации алгоритмов поиска пути.

Сообщение Anonymous »

Репозиторий и запуск приложения
Репозиторий всего программного обеспечения находится на GitHub. Самый простой способ запустить его – запустить

Код: Выделить всё

mvn javafx:run
из командной строки (требуется установленный Maven).

Класс потенциального виновника:

Код: Выделить всё

io.github.coderodde.pathfinding.app.SettingsPane.java:
[/b]

Код: Выделить всё

package io.github.coderodde.pathfinding.app;

import static io.github.coderodde.pathfinding.app.Configuration.FREQUENCIES;
import static io.github.coderodde.pathfinding.finders.Finder.computePathCost;
import io.github.coderodde.pathfinding.controller.GridController;
import io.github.coderodde.pathfinding.finders.AStarFinder;
import io.github.coderodde.pathfinding.finders.BFSFinder;
import io.github.coderodde.pathfinding.finders.BeamSearchFinder;
import io.github.coderodde.pathfinding.finders.BestFirstSearchFinder;
import io.github.coderodde.pathfinding.finders.BidirectionalBFSFinder;
import io.github.coderodde.pathfinding.finders.BidirectionalBeamSearchFinder;
import io.github.coderodde.pathfinding.finders.BidirectionalBestFirstSearchFinder;
import io.github.coderodde.pathfinding.finders.BidirectionalDijkstraFinder;
import io.github.coderodde.pathfinding.finders.DijkstraFinder;
import io.github.coderodde.pathfinding.finders.Finder;
import io.github.coderodde.pathfinding.finders.IDAStarFinder;
import io.github.coderodde.pathfinding.finders.IDDFSFinder;
import io.github.coderodde.pathfinding.finders.JumpPointSearchFinder;
import io.github.coderodde.pathfinding.finders.NBAStarFinder;
import io.github.coderodde.pathfinding.finders.PEAStarFinder;
import io.github.coderodde.pathfinding.heuristics.ChebyshevHeuristicFunction;
import io.github.coderodde.pathfinding.heuristics.EuclideanHeuristicFunction;
import io.github.coderodde.pathfinding.heuristics.HeuristicFunction;
import io.github.coderodde.pathfinding.heuristics.ManhattanHeuristicFunction;
import io.github.coderodde.pathfinding.heuristics.OctileHeuristicFunction;
import io.github.coderodde.pathfinding.logic.GridCellNeighbourIterable;
import io.github.coderodde.pathfinding.logic.GridNodeExpander;
import io.github.coderodde.pathfinding.logic.PathfindingSettings;
import io.github.coderodde.pathfinding.logic.PathfindingSettings.DiagonalWeight;
import io.github.coderodde.pathfinding.logic.SearchState;
import io.github.coderodde.pathfinding.logic.SearchState.CurrentState;
import io.github.coderodde.pathfinding.logic.SearchStatistics;
import io.github.coderodde.pathfinding.model.GridModel;
import io.github.coderodde.pathfinding.utils.Cell;
import io.github.coderodde.pathfinding.view.GridView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.function.UnaryOperator;
import java.util.regex.Pattern;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.geometry.Rectangle2D;
import javafx.scene.control.Accordion;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.control.TitledPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.Screen;
import javafx.util.converter.DoubleStringConverter;

/**
*
* @author Rodion "rodde"  EFremov
* @version 1.0.0 (Aug 27, 2025)
* @since 1.0.0 (Aug 27, 2025)
*/
public final class SettingsPane extends Pane {

private static final String EUCLIDEAN = "Euclidean";
private static final String MANHATTAN = "Manhattan";
private static final String OCTILE    = "Octile";
private static final String CHEBYSHEV = "Chebyshev";

private static final String ASTAR             = "A* search";
private static final String BFS               = "BFS";
private static final String BEAM_SEARCH       = "Beam search";
private static final String BEST_FIRST_SEARCH = "Best First search";
private static final String BI_BFS            = "Bidirectional BFS";
private static final String BI_BEAM_SEARCH    = "Bidirectional beam search";
private static final String BI_BEST_FS        = "Bidirectional BeFS";
private static final String BI_DIJKSTRA       = "Bidirectional Dijkstra";
private static final String DIJKSTRA          = "Dijkstra";
private static final String IDASTAR           = "IDA* search";
private static final String IDDFS             = "IDDFS";
private static final String JUMP_POINT_SEARCH = "Jump point search";
private static final String NBASTAR           = "NBA* search";
private static final String PEASTAR           = "PEA* search";

private static final String[] HEURISTIC_NAMES = {
MANHATTAN,
EUCLIDEAN,
OCTILE,
CHEBYSHEV,
};

private static final String[] FINDER_NAMES = {
ASTAR,
BFS,
BEAM_SEARCH,
BEST_FIRST_SEARCH,
BI_BFS,
BI_BEAM_SEARCH,
BI_BEST_FS,
BI_DIJKSTRA,
DIJKSTRA,
IDASTAR,
IDDFS,
JUMP_POINT_SEARCH,
NBASTAR,
PEASTAR,
};

private static final Map HEURISTIC_MAP =
new HashMap();

private static final Map FINDER_MAP =
new HashMap();

static {
HEURISTIC_MAP.put(EUCLIDEAN, new EuclideanHeuristicFunction());
HEURISTIC_MAP.put(MANHATTAN, new ManhattanHeuristicFunction());
HEURISTIC_MAP.put(OCTILE,    new OctileHeuristicFunction());
HEURISTIC_MAP.put(CHEBYSHEV, new ChebyshevHeuristicFunction());

FINDER_MAP.put(ASTAR,             new AStarFinder());
FINDER_MAP.put(DIJKSTRA,          new DijkstraFinder());
FINDER_MAP.put(BI_DIJKSTRA,       new BidirectionalDijkstraFinder());
FINDER_MAP.put(BFS,               new BFSFinder());
FINDER_MAP.put(BI_BFS,            new BidirectionalBFSFinder());
FINDER_MAP.put(BEST_FIRST_SEARCH, new BestFirstSearchFinder());
FINDER_MAP.put(BI_BEAM_SEARCH,    new BidirectionalBeamSearchFinder());
FINDER_MAP.put(BEAM_SEARCH,       new BeamSearchFinder());
FINDER_MAP.put(IDASTAR,           new IDAStarFinder());
FINDER_MAP.put(IDDFS,             new IDDFSFinder());
FINDER_MAP.put(JUMP_POINT_SEARCH, new JumpPointSearchFinder());
FINDER_MAP.put(NBASTAR,           new NBAStarFinder());
FINDER_MAP.put(BI_BEST_FS,
new BidirectionalBestFirstSearchFinder());

FINDER_MAP.put(PEASTAR,           new PEAStarFinder());
}

private static final int PIXELS_WIDTH  = 300;
private static final int PIXELS_HEIGHT = 200;
private static final int PIXELS_MARGIN = 20;
private final double[] offset = new double[2];
private GridNodeExpander gridNodeExpander;
private final SearchState searchState;
private Finder finder;
private List path = new ArrayList();

private final ComboBox comboBoxFrequency        = new ComboBox();
private final ComboBox comboBoxDiagonalWeight   = new ComboBox();
private final ComboBox comboBoxFinder           = new ComboBox();
private final ComboBox comboBoxHeuristic        = new ComboBox();
private final ComboBox  comboBoxBeamWidth        = new ComboBox();

private final CheckBox checkBoxAllowDiagonals =
new CheckBox("Allow diagonals");

private final CheckBox checkBoxDontCrossCorners =
new CheckBox("Don't cross corners");

private final TitledPane titledPaneFrequency =
new TitledPane("Frequency", comboBoxFrequency);

private final TitledPane titledPaneDiagonalWeight =
new TitledPane("Diagonal weight", comboBoxDiagonalWeight);

private final TitledPane titledPaneFinder =
new TitledPane("Finder", comboBoxFinder);

private final TitledPane titledPaneHeuristic =
new TitledPane("Heuristic", comboBoxHeuristic);

private final TitledPane titledPaneBeamWidth =
new TitledPane("Beam width", comboBoxBeamWidth);

private final TextField textFieldCutoffValue = new TextField();

private final TitledPane titledPaneCutoffValue =
new TitledPane("Cutoff value", textFieldCutoffValue);

private final TitledPane titledPaneDiagonalSettings;

private final Label labelPathCost      = new Label("Path cost: N/A");
private final Label labelVisitedCount  = new Label("Visited cells: N/A");
private final Label labelOpenedCount   = new Label("Opened cells: N/A");
private final Label labelTracedCount   = new Label("Traced cells: N/A");
private final Label labelRejectedCount = new Label("Rejected cells: N/A");

private final VBox vboxDiagonalSettings = new VBox();

private final Button buttonStartPause = new Button("Start");
private final Button buttonReset      = new Button("Reset");
private final Button buttonClearWalls = new Button("Clear walls");
private final Button buttonDrawMaze   = new Button("Draw random maze");

private boolean previouslyReset = false;

private static final Pattern CUTOFF_VALUE_PATTERN =
Pattern.compile("\\d*(\\.\\d*)?");

private static final UnaryOperator cutoffValueFilter =
change -> {
String newText = change.getControlNewText();

if (CUTOFF_VALUE_PATTERN.matcher(newText).matches()) {
return change;
}

return null;
};

private static final TextFormatter TEXT_FOMATTER =
new TextFormatter(
new DoubleStringConverter(),
0.0,
cutoffValueFilter);

private volatile boolean searchIsRunning = false;

public SettingsPane(GridModel gridModel,
GridView gridView,
GridController gridController,
SearchState searchState) {

this.searchState = searchState;
this.searchState.setCurrentState(CurrentState.IDLE);

this.labelPathCost.setStyle("-fx-background-color: white;" +
"-fx-font-size: 13px;");

this.labelPathCost.setPrefWidth(PIXELS_WIDTH);

this.labelVisitedCount.setStyle("-fx-background-color: white;" +
"-fx-font-size: 13px;");

this.labelVisitedCount.setPrefWidth(PIXELS_WIDTH);

this.labelOpenedCount.setStyle("-fx-background-color: white;" +
"-fx-font-size: 13px;");

this.labelOpenedCount.setPrefWidth(PIXELS_WIDTH);

this.labelTracedCount.setStyle("-fx-background-color: white;" +
"-fx-font-size: 13px;");

this.labelTracedCount.setPrefWidth(PIXELS_WIDTH);

this.labelRejectedCount.setStyle("-fx-background-color: white;"  +
"-fx-font-size: 13px;");

this.labelRejectedCount.setPrefWidth(PIXELS_WIDTH);

this.vboxDiagonalSettings
.getChildren()
.addAll(checkBoxAllowDiagonals,
checkBoxDontCrossCorners);

this.titledPaneDiagonalSettings =
new TitledPane(
"Diagonal settings",
this.vboxDiagonalSettings);

this.textFieldCutoffValue.setTextFormatter(TEXT_FOMATTER);

setPrefSize(PIXELS_WIDTH,
PIXELS_HEIGHT);

setMinSize(PIXELS_WIDTH,
PIXELS_HEIGHT);

setMaxSize(PIXELS_WIDTH,
PIXELS_HEIGHT);

Rectangle2D screenRectangle = Screen.getPrimary().getBounds();

setLayoutX(screenRectangle.getWidth() - PIXELS_WIDTH - PIXELS_MARGIN);
setLayoutY(PIXELS_MARGIN);

VBox mainVBox = new VBox();

mainVBox.setPrefSize(PIXELS_WIDTH,
PIXELS_HEIGHT);

mainVBox.setMinSize(PIXELS_WIDTH,
PIXELS_HEIGHT);

mainVBox.setMaxSize(PIXELS_WIDTH,
PIXELS_HEIGHT);

for (int beamWidth = 1; beamWidth   {
if (!searchState.getCurrentState().equals(CurrentState.IDLE)) {
return;
}

gridModel.drawRandomMaze();
previouslyReset = false;
});

buttonStartPause.setOnAction(event -> {

PathfindingSettings pathfindingSettings =
computePathfindingSettings();

if (searchState.getCurrentState().equals(CurrentState.IDLE)) {
// Once here, start search:
searchState.setCurrentState(CurrentState.SEARCHING);
gridView.clearPath(path); // Clear the possible previous path!
gridController.disableUserInteraction();
gridModel.clearStateCells();
gridView.clearView();
gridView.drawBorders();
gridView.drawAllCels();
buttonStartPause.setText("Pause");
previouslyReset = false;

finder = pathfindingSettings.getFinder();
gridNodeExpander = new GridNodeExpander(gridModel,
pathfindingSettings);

SearchStatistics searchStatistics = computeSearchStatistics();

Task task = new Task() {

@Override
protected List call() throws Exception {
Platform.runLater(() -> {
labelPathCost.setText("Path cost: N/A");
});

searchIsRunning = true;

List path = finder.findPath(
gridModel,
new GridCellNeighbourIterable(
gridModel,
gridNodeExpander,
pathfindingSettings),
pathfindingSettings,
searchState,
searchStatistics);

searchIsRunning = false;

searchState.setCurrentState(CurrentState.IDLE);
return path;
}
};

task.setOnSucceeded(e -> {
try {
this.path.clear();
this.path.addAll(task.get());
} catch (InterruptedException | ExecutionException ex) {
System.getLogger(
SettingsPane.class.getName()).log(
System.Logger.Level.ERROR,
(String) null,
ex);
Platform.exit();
}

gridView.drawPath(this.path);
gridController.enableUserInteraction();
searchState.setCurrentState(CurrentState.IDLE);
buttonStartPause.setText("Search");
searchState.resetState();

if (this.path.isEmpty()) {
labelPathCost.setText("Path cost: N/A");
} else {
labelPathCost.setText(
"Path cost: " + computePathCost(
this.path,
pathfindingSettings));
}
});

new Thread(task).start();

} else if (searchState
.getCurrentState()
.equals(CurrentState.SEARCHING)) {

// Once here, we need to pause the search:
searchState.requestPause();
searchState.setCurrentState(CurrentState.PAUSED);
buttonStartPause.setText("Continue");
previouslyReset = false;
} else if (searchState.getCurrentState()
.equals(CurrentState.PAUSED)) {

searchState.resetState();
searchState.setCurrentState(CurrentState.SEARCHING);
buttonStartPause.setText("Pause");
previouslyReset = false;
}
});

buttonClearWalls.setOnAction(event -> {
previouslyReset = false;

if (!searchState.getCurrentState().equals(CurrentState.IDLE)) {
return;
}

gridModel.clearWalls();
});

buttonReset.setOnAction(event -> {
if (previouslyReset) {
return;
}

if (searchState.getCurrentState().equals(CurrentState.IDLE)) {

gridModel.clearStateCells();
gridView.clearView();
gridView.drawBorders();
gridView.drawAllCels();
//                gridView.clearView();
//                gridModel.clearStateCells();
//                gridView.drawAllCels();
//                gridView.drawBorders();
previouslyReset = true;
return;
}

searchState.requestHalt(); // Ask the current finder to halt
// immediately.

while (searchIsRunning) {
try {
Thread.sleep(10L);
} catch (InterruptedException ex) {

}
}

buttonStartPause.setText("Search");
gridModel.clearStateCells();
gridView.clearView();
gridView.drawBorders();
gridView.drawAllCels();
previouslyReset = true;
searchState.setCurrentState(CurrentState.IDLE);
});

buttonVBox.getChildren().addAll(buttonStartPause,
buttonReset,
buttonClearWalls,
buttonDrawMaze);

mainVBox.getChildren().add(buttonVBox);

setOnMousePressed(event -> {
offset[0] = event.getSceneX() - getLayoutX();
offset[1] = event.getSceneY() - getLayoutY();
});

setOnMouseDragged(event -> {
setLayoutX(event.getSceneX() - offset[0]);
setLayoutY(event.getSceneY() - offset[1]);
});

Label emptyLabel = new Label("");
emptyLabel.setPrefSize(PIXELS_WIDTH, 40.0);
mainVBox.getChildren().add(emptyLabel);

// after: VBox mainVBox = new VBox();
mainVBox.setFillWidth(true);
mainVBox.prefWidthProperty().bind(widthProperty());
mainVBox.prefHeightProperty().bind(heightProperty());  // optional

// Make children take full width of the VBox:
accordion.setMaxWidth(Double.MAX_VALUE);
buttonStartPause.setMaxWidth(Double.MAX_VALUE);
buttonClearWalls.setMaxWidth(Double.MAX_VALUE);

// If you keep Pane as the root, explicitly place the VBox at (0,0):
mainVBox.relocate(0, 0);
}

public SearchState getSearchState() {
return searchState;
}

@Override
public boolean isResizable() {
return false;
}

private PathfindingSettings computePathfindingSettings() {
PathfindingSettings ps = new PathfindingSettings();

ps.setAllowDiagonals(checkBoxAllowDiagonals.isSelected());
ps.setDontCrossCorners(checkBoxDontCrossCorners.isSelected());
ps.setBeamWidth(Integer.parseInt(comboBoxBeamWidth.getValue()));
ps.setDiagonalWeight(
DiagonalWeight.convert(comboBoxDiagonalWeight.getValue()));

ps.setHeuristicFunction(
HEURISTIC_MAP.get(comboBoxHeuristic.getValue()));

ps.setFinder(FINDER_MAP.get(comboBoxFinder.getValue()));
ps.setCutoff(Double.parseDouble(textFieldCutoffValue.getText()));

return ps;
}

private SearchStatistics computeSearchStatistics() {
switch (finder.getClass().getSimpleName()) {
case "AStarFinder":
case "BFSFinder":
case "BeamSearchFinder":
case "BeamStackSearchFinder":
case "BestFirstSearchFinder":
case "BidirectionalBFSFinder":
case "BidirectionalBeamSearchFinder":
case "BidirectionalBestFirstSearchFinder":
case "BidirectionalDijkstraFinder":
case "DijkstraFinder":
case "PEAStarFinder":
return new SearchStatistics(
labelVisitedCount,
labelOpenedCount,
labelTracedCount,
labelRejectedCount,
SearchStatistics.LabelSelector.OPENED,
SearchStatistics.LabelSelector.VISITED);

case "IDAStarFinder":
return new SearchStatistics(
labelVisitedCount,
labelOpenedCount,
labelTracedCount,
labelRejectedCount,
SearchStatistics.LabelSelector.TRACED);

case "NBAStarFinder":
return new SearchStatistics(
labelVisitedCount,
labelOpenedCount,
labelTracedCount,
labelRejectedCount,
SearchStatistics.LabelSelector.OPENED,
SearchStatistics.LabelSelector.VISITED,
SearchStatistics.LabelSelector.REJECTED);

case "IDDFSFinder":
return new SearchStatistics(
labelVisitedCount,
labelOpenedCount,
labelTracedCount,
labelRejectedCount,
SearchStatistics.LabelSelector.VISITED,
SearchStatistics.LabelSelector.TRACED);

case "JumpPointSearchFinder":
return new SearchStatistics(
labelVisitedCount,
labelOpenedCount,
labelTracedCount,
labelRejectedCount,
SearchStatistics.LabelSelector.OPENED,
SearchStatistics.LabelSelector.VISITED,
SearchStatistics.LabelSelector.TRACED);

default:
throw new IllegalStateException("Should not get here ever");
}
}
}
Визуальное описание ошибки
Обычно пользовательский интерфейс должен выглядеть так:
Изображение
Однако, когда я нажимаю Старт (запускает анимацию), я получаю:
Изображение
(Обратите внимание выше, что цвет полей и границ изменился на красный по какой-то неизвестной мне причине.)
(Если вам нужна более подробная информация, оставьте комментарий, и я постараюсь это организовать.)

Подробнее здесь: https://stackoverflow.com/questions/797 ... algorithms
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»