我正在尝试创建一个程序来模拟使用Java和JavaFX解决Rubik’s Cube的问题。该场景具有一个文本框,该文本框将以正确的方式显示计算机所做的每一步。文本框旁边有一个展开的多维数据集,其中 应 显示该多维数据集的当前状态。
问题在于,GUI只会更新以显示移动列表,并且在所有进程的最后都显示多维数据集的状态。我已经浏览了文档,该站点上的其他问题,其他站点上的其他问题,但找不到任何能够解决该问题的方法。我尝试使用PauseTransition,然后尝试使用稍后运行。这两种方法似乎都过于复杂,无法获得简单的结果。
public class Main extends Application { @Override public void start(Stage Stage) { try { Parent root = FXMLLoader.load(getClass().getResource("RubiksFXML.fxml")); Scene scene = new Scene(root, 675, 450); scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm()); Stage.setScene(scene); Stage.show(); } catch (Exception e) { e.printStackTrace(); } } @FXML private Button SolveButton; @FXML private ImageView s100, s101, s102, s110, s111, s112, s120, s121, s122; @FXML private ImageView s200, s201, s202, s210, s211, s212, s220, s221, s222; @FXML private ImageView s300, s301, s302, s310, s311, s312, s320, s321, s322; @FXML private ImageView s400, s401, s402, s410, s411, s412, s420, s421, s422; @FXML private ImageView s500, s501, s502, s510, s511, s512, s520, s521, s522; @FXML private ImageView s600, s601, s602, s610, s611, s612, s620, s621, s622; @FXML private TextArea MoveRecord; private char side1[][] = { { 'y', 'y', 'y' }, { 'y', 'y', 'y' }, { 'y', 'y', 'y' } }; private char side2[][] = { { 'o', 'o', 'o' }, { 'o', 'o', 'o' }, { 'o', 'o', 'o' } }; private char side3[][] = { { 'b', 'b', 'b' }, { 'b', 'b', 'b' }, { 'b', 'b', 'b' } }; private char side4[][] = { { 'r', 'r', 'r' }, { 'r', 'r', 'r' }, { 'r', 'r', 'r' } }; private char side5[][] = { { 'w', 'w', 'w' }, { 'w', 'w', 'w' }, { 'w', 'w', 'w' } }; private char side6[][] = { { 'g', 'g', 'g' }, { 'g', 'g', 'g' }, { 'g', 'g', 'g' } }; private char cen = side3[1][1]; private String MoveList = ""; public static void main(String[] args) { launch(args); } @FXML protected void SolveClicked(ActionEvent event) { L(); R(); F(); B(); //Refresh does not happen until this point. //I want it to happen every time the cube is moved //Hence the OutputCube() function }
该代码是顺时针“旋转”左脸的代码,每种“旋转”的可能性还有11个功能,还有“ Clockwise()”可“旋转”实际的脸
private void L() { OutputCube(); MoveRecord.appendText("L"); char temp; Clockwise(2); temp = side5[0][0]; side5[0][0] = side3[0][0]; side3[0][0] = side1[0][0]; side1[0][0] = side6[0][0]; side6[0][0] = temp; temp = side5[2][0]; side5[2][0] = side3[2][0]; side3[2][0] = side1[2][0]; side1[2][0] = side6[2][0]; side6[2][0] = temp; temp = side5[1][0]; side5[1][0] = side3[1][0]; side3[1][0] = side1[1][0]; side1[1][0] = side6[1][0]; side6[1][0] = temp; }
以下功能未完成,如果块为黄色,则仅更新立方体的第一面。实际上,该过程将再执行5次以检查每种颜色,然后再对所有六种颜色(带有for循环)执行五次以更新每一侧。完整的代码会产生所需的结果,但是,尽管在每次移动开始时都调用了此函数,但直到进行了所有移动之后,才更新ImageView。
@FXML private void OutputCube() { int imageview = 0; for (int row = 0; row < 3; row++) { for (int col = 0; col < 3; col++) { switch (side1[row][col]) { case 'y': switch (imageview) { case 0: s100.setImage(new Image("yellow.png")); break; case 1: s101.setImage(new Image("yellow.png")); break; case 2: s102.setImage(new Image("yellow.png")); break; case 3: s110.setImage(new Image("yellow.png")); break; case 4: s111.setImage(new Image("yellow.png")); break; case 5: s112.setImage(new Image("yellow.png")); break; case 6: s120.setImage(new Image("yellow.png")); break; case 7: s121.setImage(new Image("yellow.png")); break; case 8: s122.setImage(new Image("yellow.png")); break; } break; } imageview++; } } }
直到最后您都看不到效果,因为您正在FX Application Thread上执行所有操作。这是负责呈现UI的同一线程,因此,如果对该线程执行了某些操作(例如SolveClicked[sic:请使用正确的命名约定 ]方法),则在操作完成之前无法呈现UI。
SolveClicked
如果您以正确的方式思考,那么您真正要做的就是创建动画。(您不仅要显示解决方案,还想向用户显示多个“动画帧”,每个动画帧代表解决方案中的一个步骤。)因此,您应该使用animation API。最简单的方法可能是Timeline:
Timeline
@FXML protected void solveClicked(ActionEvent event) { Timeline timeline = new Timeline( new KeyFrame(Duration.millis(500), e -> L()), new KeyFrame(Duration.millis(1000), e -> R()), new KeyFrame(Duration.millis(1500), e -> F()), new KeyFrame(Duration.millis(2000), e -> B())); timeline.play(); }
如果您需要一种更“自动化”的方式来生成时间轴,则可以执行以下操作(有趣):
@FXML protected void solveClicked(ActionEvent event) { Runnable[] steps = new Runnable[] {this::L, this::R, this::F, this::B}; createTimeline(steps, 500).play(); } private Timeline createTimeline(Runnable[] steps, int delay) { Duration frameTime = Duration.millis(delay); Duration increment = Duration.millis(delay); Timeline timeline = new Timeline() ; for (Runnable step : steps) { timeline.getKeyFrames().add(new KeyFrame(frameTime, e -> step.run())); frameTime = frameTime.add(increment); } return timeline ; }
一种更复杂的方法可能是通过动画(显示实际旋转)来表示一张脸的每一个动作,然后将它们全部组合成一个SequentialTransition。
SequentialTransition