2016-06-23 12 views
1

Ich erstelle eine GUI für ein Brettspiel mit javaFX über RMI. Ich habe eine Menge Probleme, denn nachdem ich einen Weg gefunden habe, meine GUI zu aktualisieren, kann ich die GUI nicht wirklich aktualisieren, wenn ich keinen Toggle Breakpoint in einer bestimmten Zeile platziere.JavaFX aktualisiert Grafik nur mit Debug und Haltepunkten

Wenn ich meine Clients nicht im Debug-Modus starte, scheinen die Grafiken das Update nicht zu machen, sie erscheinen einfach und nichts passiert mehr.

Auch wenn ich den Schalter nicht in eine bestimmte Zeile meines Codes, und ich lege es in eine andere Zeile (tiefer in der Methode Aufrufsequenz), passiert nichts. Also hört der Client-Thread nicht auf; als ob es nicht die Methode ruft, die es mit dem Haltepunkt tut. Ich starte meine Klienten alle in der gleichen Maschine und nur eine (mit Toggle Break Points) wird aktualisiert.

Jetzt zeige ich Ihnen meinen Code.

javafx beginnt hier in einer cla genannt RMIGUIView.java

@Override 
public synchronized void run() { 
    waiting = true; 
    pause(); 
    guiDisplayer = new GUIDisplayer(); 
    (new Thread(() -> guiDisplayer.startGUI())).start(); 
    waiting = false; 
    do { 
     state.acceptView(this); 
    } while(!endGame); 
} 

dann mache ich den Start der GUI (während des Starts Methode, die ich von der Bühne auf dem Controller speichern, wie es hier vorgeschlagen wirdPassing Parameters JavaFX FXML

public class GUIDisplayer extends Application { 

private StartTurnState currentState; 
private Stage stage; 

public void start(Stage stage) throws Exception { 
    GUIController controller = new GUIController(); 
    FXMLLoader fxmlLoader = new FXMLLoader(); 
    Parent root = fxmlLoader.load(getClass().getResource("sceneMap.fxml")); 
    stage.setTitle("Council of Four"); 
    Scene newScene = new Scene(root); 
    stage.setScene(newScene); 
    stage.show(); 
    controller.setStage(stage); 
} 

public static void startGUI() { 
    Application.launch(); 
} } 

nach dem Start des gui ich in meinem RMIGUIView.java zurückkehren, und ich tue dies

@Override 
public void visit(StartTurnState currentState) { 
    GUIController guiController = new GUIController(); 
    guiController.updateGUI(currentState); 
} 

und hier ist meine Controller-Klasse, wo ich die Breakpoint setzen, wenn ich somethig (lesen Sie bitte in der Klasse Kommentare) passieren soll

public class GUIController { 

@FXML 
ArrayList<ImageView> citiesImagesList; 
@FXML 
Group group; 
@FXML 
TableView<Player> players; 
@FXML 
TableColumn<Player, String> playerName; 
@FXML 
TableColumn<Player, String> victoryPoints; 
@FXML 
TableColumn<Player, String> coins; 
@FXML 
TableColumn<Player, String> assistants; 
@FXML 
TableColumn<Player, String> nobilityPoints; 
@FXML 
ImageView A; 
@FXML 
ImageView B; 
@FXML 
ImageView C; 
@FXML 
ImageView D; 
@FXML 
ImageView E; 
@FXML 
ImageView F; 
@FXML 
ImageView G; 
@FXML 
ImageView H; 
@FXML 
ImageView I; 
@FXML 
ImageView J; 
@FXML 
ImageView K; 
@FXML 
ImageView L; 
@FXML 
ImageView M; 
@FXML 
ImageView N; 
@FXML 
ImageView O; 
@FXML 
ImageView king; 

private static StartTurnState currentState; 
private static GUIController self = null; 
private static Stage stage; 

public GUIController() { 
    self = this; 
} 

private void placeRewardToken(Group group, List<ImageView> citiesImagesList) { 
    Map<String, City> citiesMap = GUIController.currentState.getGameMap().getCitiesMap(); 
    for (ImageView imageView : citiesImagesList) { 
     City city = citiesMap.get(imageView.getId().toString()); 
     if (city instanceof NormalCity) { 
      RewardToken rewardToken = ((NormalCity) city).getRewardToken(); 
      Text text = new Text(); 
      text.setText(rewardToken.toString()); 
      text.setX(imageView.getLayoutX() + 5.00); 
      text.setY(imageView.getLayoutY()); 
      text.toFront(); 
      text.setFont(Font.font("Verdana", 12)); 
      text.setFill(Color.MAGENTA); 
      group.getChildren().add(text); 
     } 

    } 

} 

private void setPlayerSet() { 
    Platform.setImplicitExit(false); 
    Scene scene = stage.getScene(); 
    ObservableList<Player> playersList = FXCollections.observableArrayList(); 
    playersList.addAll(GUIController.currentState.getPlayerSet().getPlayers()); 
    TableView<Player> playerTable = (TableView<Player>) scene.lookup("#players"); 
    TableColumn<Player, String> playersName = ((TableColumn<Player, String>) playerTable.getColumns().get(0)); 
    playersName.setCellValueFactory(new PropertyValueFactory<Player, String>("name")); 
    TableColumn<Player, String> victoryPoints = ((TableColumn<Player, String>) playerTable.getColumns().get(1)); 
    victoryPoints.setCellValueFactory(new PropertyValueFactory<Player, String>("victoryPoints")); 
    TableColumn<Player, String> coins = ((TableColumn<Player, String>) playerTable.getColumns().get(2)); 
    coins.setCellValueFactory(new PropertyValueFactory<Player, String>("coins")); 
    TableColumn<Player, String> assistants = ((TableColumn<Player, String>) playerTable.getColumns().get(3)); 
    assistants.setCellValueFactory(new PropertyValueFactory<Player, String>("assistants")); 
    TableColumn<Player, String> nobilityPoints = ((TableColumn<Player, String>) playerTable.getColumns().get(4)); 
    nobilityPoints.setCellValueFactory(new PropertyValueFactory<Player, String>("nobilityTrackPoints")); 
    playerTable.setItems(playersList); 
} 

private void placeKing(ImageView king, List<ImageView> citiesImagesList) { 
    for (ImageView imageView : citiesImagesList) { 
     if (imageView.getId().toString().equals(GUIController.currentState.getKing().getPosition().getName())) { 
      king.setX(imageView.getLayoutX()); 
      king.setY(imageView.getLayoutY()); 
     } 
    } 
} 

@FXML 
public void initialize() { 
    self = this; 
} 

public void setStage(Stage stage) { 
    this.stage = stage; 
} 

public void updateGUI(StartTurnState state) { 
    GUIController.currentState = state; 
    updateMap(); //here I should set my toggle breakpoint 
} 

private void updateMap() { 
    Scene scene = stage.getScene(); 
    List<ImageView> citiesImagesList = new ArrayList<>(); 
    citiesImagesList.add((ImageView) scene.lookup("#A")); 
    citiesImagesList.add((ImageView) scene.lookup("#B")); 
    citiesImagesList.add((ImageView) scene.lookup("#C")); 
    citiesImagesList.add((ImageView) scene.lookup("#D")); 
    citiesImagesList.add((ImageView) scene.lookup("#E")); 
    citiesImagesList.add((ImageView) scene.lookup("#F")); 
    citiesImagesList.add((ImageView) scene.lookup("#G")); 
    citiesImagesList.add((ImageView) scene.lookup("#H")); 
    citiesImagesList.add((ImageView) scene.lookup("#I")); 
    citiesImagesList.add((ImageView) scene.lookup("#J")); 
    citiesImagesList.add((ImageView) scene.lookup("#K")); 
    citiesImagesList.add((ImageView) scene.lookup("#L")); 
    citiesImagesList.add((ImageView) scene.lookup("#M")); 
    citiesImagesList.add((ImageView) scene.lookup("#N")); 
    citiesImagesList.add((ImageView) scene.lookup("#O")); 
    ImageView king = (ImageView) scene.lookup("#king"); 
    Group group = (Group) scene.lookup("#group"); 
    setPlayerSet(); //if I try setting here my toggle the thread doesent stop as the method updateGui() is never called 
    placeKing(king, citiesImagesList); 
    placeRewardToken(group, citiesImagesList); 
} } 

Ich hoffe, Sie verstehen meine Frage. Ich werde meine Frage bearbeiten, wenn Sie etwas nicht verstehen. Ich habe so etwas bei Stackoverflow nicht gefunden.

Vielen Dank im Voraus für Ihre Hilfe.

EDIT: Ich habe tryed den Code neu zu schreiben, wie durch James_D dies ist mein neuer Aufruf der Update GUI vorgeschlagen.

@Override 
public void visit(StartTurnState currentState) { 
    guiDisplayer.setState(currentState); 
    Platform.runLater(()-> guiDisplayer.run()); 
} 

Ich habe modifiziert auch die GUIDisplayer Klasse

public class GUIDisplayer extends Application implements Runnable{ 

private StartTurnState currentState; 
private Stage stage; 
static GUIController guiController; 

public void start(Stage stage) throws Exception { 
    GUIController controller = new GUIController(); 
    FXMLLoader fxmlLoader = new FXMLLoader(); 
    Parent root = fxmlLoader.load(getClass().getResource("sceneMap.fxml")); 
    stage.setTitle("Council of Four"); 
    Scene newScene = new Scene(root); 
    stage.setScene(newScene); 
    stage.show(); 
    controller.setStage(stage); 
    setController(controller); 
} 

public static void startGUI() { 
    Application.launch(); 
} 

public void setState(State state) { 
    currentState = (StartTurnState) state; 
} 

public static void setController(GUIController controller) { 
    guiController = controller; 
} 

@Override 
public void run() { 
    guiController.doUpdateGUI(currentState); 

} } 

Die runLater Methodenaufruf ignoriert zu werden scheint, vielleicht habe ich in diesem Fall bin durch die javadoc descibed

Wenn diese Methode ist Nachdem die JavaFX-Laufzeit heruntergefahren wurde, wird der Aufruf ignoriert: Das Runnable wird nicht ausgeführt und es wird keine Ausnahme ausgelöst.

Wenn ich den runLater entferne und toggle brackpoints hinzufüge, kann ich die GUI noch ändern.

+0

Ihr Brettspiel muss schnell aktualisieren? – GOXR3PLUS

+0

Es muss zu Beginn jedes Spielzuges aktualisiert werden, mindestens alle 5 Minuten. – axoaxel

+0

Generell in Ihrem Code folgen Sie dieser Anweisung: Vermeiden Sie javaFX SceneGraph außerhalb des javaFX-Threads zu ändern (wenn Sie nicht sicher sind, in welchem ​​Thread Sie platform.isFxApplicationThread verwenden()) Andernfalls müssen Sie Platform.runLater() verwenden, aber nicht übermäßig verwenden, da die App verzögert wird. Um Code in anderen Threads auszuführen, überprüfen Sie http://docs.oracle.com/javafx/2/threads/jfxpub-threads. htm. Ich fragte, wie schnell es aktualisiert, falls Sie javaFX AnimationTimer für die schnelle Aktualisierung verwenden wollten http://download.java.net/jdk8/jfxdocs/javafx/animation/AnimationTimer.html – GOXR3PLUS

Antwort

2

Beim Versuch, GUI von anderen Threads (außer javafx-Anwendungsthread) zu aktualisieren, sollten Sie Paltform.runLater(() -> doUpdateGUI()); verwenden, als Sie GUI wird ordnungsgemäß aktualisiert. überprüfen javafx concurrency

+0

Ich habe meinen Besuch geändert Aufruf der RunLater wie Dies. @Override \t öffentlicher void visit (StartTurnState currentState) { \t \t GUIController guiController = neuer GUIController(); \t \t Platform.runLater (() -> guiController.doUpdateGUI (currentState)); \t} und ich habe auch die Methode doUpdateGUI in der Steuerung erstellt, die updateGUI (currentState) aufruft, aber nichts passiert, wenn es meine GUI aktualisieren soll? – axoaxel

+0

'Platform.runLater (...)' wird so schnell wie möglich auf dem FX-Anwendungs-Thread ausgeführt. Machen Sie sich keine Gedanken über den Namen der Methode, es zeigt lediglich an, dass der Code innerhalb dieses Blocks nicht unbedingt vor dem Code unmittelbar nach dem 'runLater (...)' Aufruf abgeschlossen wird. Ich denke, @guleryuz ist richtig: Das hört sich definitiv nach einem Threading-Problem an und es scheint, als ob du den FX Application Thread irgendwo blockierst. –

+0

Ich habe Platform.setImplicitExit (false) vor dem Aufruf von runLater() versucht, um die runLater() zu erzwingen, jetzt gibt es in updateGUI() ein, aber der Verweis auf stage ist null und ich bekomme eine nullPointerException. Warum verliere ich diese Referenz? – axoaxel