我用javafx做棋盘游戏,偶然发现一个问题。我的应用程序具有客户端/服务器连接。每当服务器发送有关玩家将棋子移动到何处的数据时,我都会调用一个函数pawnPawn()来移动棋子,并调用另一个函数refresh()来重新绘制棋盘和棋子。不幸的是,我收到错误消息,说该函数是从不是FX的线程调用的,因此无法继续执行。我尝试了任务和Platform.runLater,但要么做错了,要么不起作用。有人可以帮忙吗?
如果您需要其他任何类代码,也可以在这里发布控制器代码:
package Client;
import javafx.application.Platform;
import javafx.concurrent.*;
import javafx.event.ActionEvent;
import javafx.fxml.*;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.effect.Lighting;
import javafx.scene.image.Image;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Polygon;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
/*
* TODO: Finish implementing movement
* TODO: Write startTurn()
*/
public class Controller implements Initializable
{
private Game game;
private Client client;
private List<Circle> pawnsGUI = new ArrayList();
private int playerNum = -1;
private int currentX;
private int currentY;
@FXML MenuItem twoPlayers;
@FXML MenuItem threePlayers;
@FXML MenuItem fourPlayers;
@FXML MenuItem sixPlayers;
@FXML MenuItem startGame;
@FXML AnchorPane mainPane;
@FXML GridPane boardGrid;
@FXML MenuItem exitMI;
@FXML Button endTurnB;
@FXML Label redPoints, bluePoints, greenPoints, yellowPoints, blackPoints, whitePoints;
@Override // Initializer for our GUI Controller
public void initialize(URL location, ResourceBundle resources)
{
connectToServer();
boardGrid.setAlignment(Pos.CENTER);
}
public void connectToServer()
{
client = new Client(this);
client.start();
}
// Refreshing board
private void refresh()
{
boardGrid.getChildren().clear();
for(int i = 0; i <= 18; i++)
{
for(int j = 0; j <= 14; j++)
{
if(game.getBoard().getField(i, j).getClass() == AccessibleField.class)
{
if(i % 2 == 1)
{
boardFill(i, j, false);
}
else
{
boardFill(i, j, true);
}
}
else if(game.getBoard().getField(i, j).getClass() == WinningField.class)
{
if(i % 2 == 1)
{
boardFill(i, j, false);
}
else
{
boardFill(i, j, true);
}
}
}
}
fillPawns();
}
// Filling board with proper colored pawns and fields
private void boardFill(int i, int j, boolean shifted)
{
Polygon poly = new Polygon(27*(1), 27*(0),
27*(0.5), 27*(0.86602540378),
27*(-0.5), 27*(0.86602540378),
27*(-1), 27*(0),
27*(-0.5), 27*(-0.86602540378),
27*(0.5), 27*(-0.86602540378));
if(shifted)
{
poly.translateYProperty().set(-23);
}
poly.setOnMouseClicked(e -> fieldClicked(i, j));
if(game.getBoard().getField(i, j).getClass() == WinningField.class)
{
for(int var = 0; var < game.getPlayers().length; var++)
{
if(game.getBoard().getField(i, j).getOwner() != null){
if(game.getBoard().getField(i, j).getOwner().equals(game.getPlayers()[var]))
{
switch (var) {
case 0:
poly.setFill(Paint.valueOf("RED"));
break;
case 1:
poly.setFill(Paint.valueOf("BLUE"));
break;
case 2:
poly.setFill(Paint.valueOf("GREEN"));
break;
case 3:
poly.setFill(Paint.valueOf("YELLOW"));
break;
case 4:
poly.setFill(Paint.valueOf("#4f4f4f"));
break;
case 5:
poly.setFill(Paint.valueOf("WHITE"));
break;
}
}
}
}
}
else
{
poly.setFill(Paint.valueOf("#d6d6d6"));
}
poly.setStroke(Paint.valueOf("BLACK"));
boardGrid.add(poly, i, j);
}
private void fieldClicked(int x, int y)
{
for(int i = 0; i < pawnsGUI.size(); i++)
{
if (pawnsGUI.get(i).getEffect() != null)
{
movePawn(currentX, currentY, x, y);
client.sendMessage("M "+currentX+" "+currentY+" "+x+" "+y+" "+playerNum);
endTurn();
}
}
}
private void fillPawns()
{
for(int i = 0; i < game.getPlayers().length ; i++)
{
for(int j = 0; j < 10; j++)
{
int x = game.getPlayers()[i].getPawns().get(j).getCoordinateX();
int y = game.getPlayers()[i].getPawns().get(j).getCoordinateY();
Circle circle = new Circle(15);
if(x % 2 != 1)
{
circle.translateYProperty().set(-23);
}
circle.translateXProperty().set(14);
pawnsGUI.add(circle);
circle.setOnMouseClicked(event -> pawnClicked(circle, x, y));
switch (i) {
case 0:
circle.setFill(Paint.valueOf("RED"));
break;
case 1:
circle.setFill(Paint.valueOf("BLUE"));
break;
case 2:
circle.setFill(Paint.valueOf("GREEN"));
break;
case 3:
circle.setFill(Paint.valueOf("YELLOW"));
break;
case 4:
circle.setFill(Paint.valueOf("BLACK"));
break;
case 5:
circle.setFill(Paint.valueOf("WHITE"));
break;
}
circle.setStroke(Paint.valueOf("BLACK"));
boardGrid.add(circle, x, y);
}
}
}
private void pawnClicked(Circle circle, int x, int y)
{
if(game.getBoard().getField(x, y).getPawn().getOwner().equals(game.getPlayers()[playerNum]))
{
// Clear effects for other pawns
for(int i = 0; i < pawnsGUI.size(); i++)
{
pawnsGUI.get(i).setEffect(null);
}
currentX = x;
currentY = y;
// Set effect for this pawn
Lighting lighting = new Lighting();
circle.setEffect(lighting);
}
}
public void startTurn()
{
mainPane.setDisable(false);
}
public void setPlayerNum(int playerNum)
{
this.playerNum = playerNum;
}
public void movePawn(int x1, int y1, int x2, int y2)
{
Pawn pawnTemp = game.getBoard().getField(x1, y1).getPawn();
game.getBoard().getField(x1, y1).setPawn(null);
game.getBoard().getField(x2, y2).setPawn(pawnTemp);
refresh();
}
@FXML
public void newGame(ActionEvent e)
{
GameDirector director = new GameDirector();
GameBuilder builder;
if(e.getSource().equals(twoPlayers))
{
builder = new CCBoard2P();
client.sendMessage("I 2");
}
else if(e.getSource().equals(threePlayers))
{
builder = new CCBoard3P();
client.sendMessage("I 3");
}
else if(e.getSource().equals(fourPlayers))
{
builder = new CCBoard4P();
client.sendMessage("I 4");
}
else
{
builder = new CCBoard6P();
client.sendMessage("I 6");
}
director.setBuilder(builder);
director.createGame();
game = builder.setupGame();
startGame.setDisable(true);
mainPane.setDisable(true);
refresh();
}
@FXML // EXIT menu item handler (exits game)
public void exitHandler()
{
if(client.isAlive())
{
client.sendMessage("END");
}
System.exit(0);
}
@FXML // END TURN button handler (increments all score values)
public void endTurn()
{
System.out.println("Turn passed... \n");
if(!boardGrid.getChildren().isEmpty())
{
refresh();
mainPane.setDisable(true);
}
}
@FXML // RULES manu item handler (creates dialog window with rules)
public void rulesHandler()
{
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/FXML/Rules.fxml"));
Parent root = null;
try
{
root = fxmlLoader.load();
}
catch (IOException e)
{
e.printStackTrace();
}
Stage rulesDialog = new Stage();
rulesDialog.setTitle("Rules");
rulesDialog.getIcons().add(new Image(getClass().getResourceAsStream("icon.jpg")));
rulesDialog.initModality(Modality.APPLICATION_MODAL);
rulesDialog.setScene(new Scene(root));
rulesDialog.setResizable(false);
rulesDialog.show();
}
@FXML // AUTHOR manu item handler (creates dialog window with authors)
public void authorsHandler()
{
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/FXML/Authors.fxml"));
Parent root = null;
try
{
root = fxmlLoader.load();
}
catch (IOException e)
{
e.printStackTrace();
}
Stage authorsDialog = new Stage();
authorsDialog.setTitle("Authors");
authorsDialog.getIcons().add(new Image(getClass().getResourceAsStream("icon.jpg")));
authorsDialog.initModality(Modality.APPLICATION_MODAL);
authorsDialog.setScene(new Scene(root));
authorsDialog.setResizable(false);
authorsDialog.show();
}
}
这是错误:
Exception in thread "Thread-3" java.lang.IllegalStateException: Not on FX
application thread; currentThread = Thread-3
at javafx.graphics/com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:291)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.graphics/javafx.scene.Parent$3.onProposedChange(Parent.java:493)
at javafx.base/com.sun.javafx.collections.VetoableListDecorator.clear(VetoableListDecorator.java:294)
at Client.Controller.refresh(Controller.java:72)
at Client.Controller.movePawn(Controller.java:251)
at Client.Client.getMessage(Client.java:80)
at Client.Client.run(Client.java:45)
显然Client.run()
是在后台线程上执行,并调用Controller.movePawn()
(通过refresh()
)更新UI。您无法在后台线程上更新UI。您需要在中包装用于更新UI的代码Platform.runLater()
。因此,如果没有完整的示例,很难说清楚,但是以该方法调用的特定顺序为例,看来您需要
public void movePawn(int x1, int y1, int x2, int y2) {
Platform.runLater(() -> {
Pawn pawnTemp = game.getBoard().getField(x1, y1).getPawn();
game.getBoard().getField(x1, y1).setPawn(null);
game.getBoard().getField(x2, y2).setPawn(pawnTemp);
refresh();
});
}
整个代码中可能存在类似的问题,但最重要的是您:
问题内容: 您好,我想知道从swingworkerthread向jtextarea添加文本的最佳方法是什么,我创建了另一个类,Threadsclass()。execute()调用了jbutton。并且线程与此代码并行运行 现在id要做的是将x的值添加到主gui上的文本区域,任何想法都值得赞赏。 问题答案: JavaDocs有一个很好的例子 看一下发布和处理 潜在的意图是,您仅需要从事件调度线程中更
我有一个带有一些线程的简单应用程序,我需要从一些线程更新SWING GUI(我正在使用Netbean)。 这是我需要更新的主要表单: 现在我有一些线程: 在其他班级,我有: 代码的每个部分都位于不同的文件(类)中。我如何在这里实现 Swing 工作人员,以便能够在我的主 GUI 窗体上显示文本?
问题内容: 在此代码中,addRemote方法使用新按钮更新controlPnl GUI。dmc.moveTo方法中最多包含两个Thread.sleep调用,我认为在controlPnl GUI更新之前已调用了它们。我已经注释了dmc.moveTo之后的两个方法调用,这些方法将GUI恢复为调用之前的状态,并且controlPnl直到moveTo完成执行后才完成更新。我需要GUI在moveTo方法开
问题内容: 我研究了一段时间,以查找有关 如何使用PyQT执行多线程程序的 信息 ,并更新了GUI以显示结果 。 我习惯于通过示例学习,但我找不到(是的,我找了好几个星期)使用多线程执行此简单任务的程序的任何简单示例,例如连接到www网站列表(5个线程)并只是打印处理带有响应代码的网址。 任何人都可以共享代码或让我进入解释此类程序的出色教程吗? 问题答案: 这里有一些非常基本的例子。 您可以将对G
所以我有这样的东西: 一切都很好,直到我不得不等待其他事情完成,然后才能继续运行,所以我这样修改了它: 后来我做了这样的事情: 现在,我的gui在切换场景时开始滞后 - 这意味着 - 整个thread1自行处理,然后gui加载所有内容。经过一些研究,我认为发生这种情况是因为主线程正在处理runLater“请求”,并且由于wait(),主线程必须等到第一个辅助线程来到CountDown()。 我的问
我有一个主要的方法,它应该从一个乐高机器人的数据绘制一个地图,主线程应该处理它从机器人获得的数据: } 如何从线程获取数据来更新GUI?