我正嘗試在JavaFX中創建一個項目 - 由點表示的機器人 - 在基於某種通信協議的畫布上移動。到目前爲止,我已經發現,遵循MVC方法,我應該將相關數據(機器人)保存在ObservableList類型的對象中,然後控制器可以使用它來更新畫布。JavaFX - 通過更改畫布上的屬性(位置)繪製對象
運行Controller.java的test()方法我得到以下錯誤,我無法解決。我已經評論了Controller.java中的相關行 - 刪除它也解決了錯誤信息。
我意識到這種方法可能遠離最佳實踐。對於如何解決此問題或更好地使用Observable提供任何提示,我將非常感謝,允許控制器在更改後在畫布上繪製機器人位置。
Main.java
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import java.io.IOException;
public class Main extends Application {
public Stage primaryStage;
private BorderPane rootLayout;
private final Model model = new Model();
@Override
public void start(Stage primaryStage) throws Exception{
// this.model = new Model();
this.primaryStage = primaryStage;
this.primaryStage.setTitle("");
initRootLayout();
}
public void initRootLayout(){
try {
// Load root layout from fxml file.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("Overview.fxml"));
rootLayout = (BorderPane) loader.load();
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.setHeight(500);
primaryStage.setWidth(500);
// Give the controller access to the main app.
Controller controller = loader.getController();
controller.initModel(model);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Model.java
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class Model {
private final ObservableList<Robot> robots = FXCollections.observableArrayList();
public ObservableList<Robot> getRobots(){ return robots;}
}
Robot.java
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import java.util.Random;
public class Robot implements Runnable {
private IntegerProperty id = new SimpleIntegerProperty();
public void setID(int id){this.id.set(id);}
public int getId(){ return this.id.get();};
private Memory memory;
private DoubleProperty positionX = new SimpleDoubleProperty();
public double getPositionX() {return positionX.get();};
public DoubleProperty positionXProperty(){ return positionX;}
private DoubleProperty positionY = new SimpleDoubleProperty();
public double getPositionY() {return positionY.get();};
public DoubleProperty positionYProperty(){ return positionY;}
public void setPosition (double x, double y){
this.positionX.set(x);
this.positionY.set(y);
this.memory.setPosition(x,y);
}
// Constructor
public Robot(int id, double x, double y){
this.setID(id);
memory = new Memory();
this.setPosition(x, y);
}
public double[] getPosition(){
double [] ret = new double[2];
ret[0] = this.memory.getPosition()[0];
ret[1] = this.memory.getPosition()[1];
return ret;
}
public void move (double targetx, double targety){
System.out.println("Agent carrying " + this.getId + " has moved from " + this.getPositionX() + "/" + this.getPositionY() + " to " + targetx + "/" + targety + " .");
this.setPosition(targetx, targety);
}
public void run(){
while(true){
// the robot gets assigned a new position based on a communication
// protocoll used by the Robots which I have removed for convenience
Random r = new Random();
double nextX = 0 + (100) * r.nextDouble();
double nextY = 0 + (100) * r.nextDouble();
this.move(nextX, nextY);
try{
Thread.sleep(2000);
}
catch(InterruptedException e){
System.out.println(e);
}
}
}
}
Memory.java
public class Memory {
double[] position = new double[2];
double[] plast = new double[2];
// constructor
public Memory(){
double[] position = new double[2];
double[] plast = new double[2];
}
public double[] getPosition(){
return position;
}
public double[] getLastPosition(){
return plast;
}
public void setLastPosition(double x, double y){
plast[0] = x;
plast[1] = y;
}
public void setPosition(double x, double y){
position[0] = x;
position[1] = y;
}
}
Controller.java
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
public class Controller {
private Model model;
public void initModel(Model model) {
this.model = model ;
for (Robot robot : model.getRobots()){
robot.positionXProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
System.out.println("Observed change in value X of Robot carrying ID: " + robot.getId());
drawPoint(robot.getPositionX(), robot.getPositionY());
// if I comment out the above line I get no errors
}
});
robot.positionYProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
System.out.println("Observed change in value Y of Robot carrying ID: " + robot.getId());
drawPoint(robot.getPositionX(), robot.getPositionY());
// if I comment out the above line I get no errors
}
});
}
}
@FXML
Canvas canvas;
public void test(){
GraphicsContext gc =canvas.getGraphicsContext2D();
gc.strokeRect(0,0,100,100);
Robot a = new Robot(0,25,25);
Robot b = new Robot(1,50,50);
model.getRobots().add(a);
model.getRobots().add(b);
Thread ta = new Thread(a);
Thread tb = new Thread(b);
initModel(model);
System.out.println("Starting threads.");
ta.start();
tb.start();
}
public void drawPoint(double x, double y){
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setFill(Color.rgb(255, 0, 0));
gc.fillOval(x, y, 5, 5);
}
}
Overview.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.canvas.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controller">
<top>
<Button fx:id="buttonTest" mnemonicParsing="false" onAction="#test" text="test()" BorderPane.alignment="CENTER" />
</top>
<center>
<Canvas fx:id="canvas" height="200.0" width="200.0" BorderPane.alignment="CENTER" />
</center>
</BorderPane>
錯誤:
java.lang.InternalError: Unrecognized PGCanvas token: -96
at com.sun.javafx.sg.prism.NGCanvas.renderStream(NGCanvas.java:1146)
at com.sun.javafx.sg.prism.NGCanvas.renderContent(NGCanvas.java:595)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2067)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1959)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2067)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1959)
at com.sun.javafx.tk.quantum.ViewPainter.doPaint(ViewPainter.java:474)
at com.sun.javafx.tk.quantum.ViewPainter.paintImpl(ViewPainter.java:327)
at com.sun.javafx.tk.quantum.PresentingPainter.run(PresentingPainter.java:91)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:125)
at java.lang.Thread.run(Thread.java:745)
如果您詢問在運行時產生錯誤的代碼,您應該發佈一個實際編譯的示例。這裏有多個編譯錯誤。要創建[MCVE],您應該實際創建代碼,運行ti以驗證它演示您正在處理的問題,然後直接在此處複製代碼。這不是你運行的代碼。由於您使用的是JavaFX屬性,我還建議您遵循[Java FX屬性模式](http://www.oracle.com/pls/topic/lookup?ctx=javase80&id=JFXBD107)。 –
親愛的James_D,謝謝你的回覆。我很感激你的意見,並且遺憾的是沒有仔細檢查我提交的代碼。我修復了所有編譯錯誤,因此現在應該可以運行代碼。該錯誤消息與我之前提交的錯誤消息相同。正如你所建議的,我試着在Robot類中遵循_Java FX Properties pattern_。 – Hips