0

I really do my best to not ask for help here unless i am desperate to the point of school assignment failure, being a new coder. That being said, i have spent the last 3 days trying to figure out the issue with threading. I am trying to instantiate a javafx class thats in a separate package, and keep running into the dreaded "java.lang.IllegalStateException: This operation is permitted on the event thread only; currentThread = main" exception.

I have tried calling theGamePreBoard.start(new Stage()), which doesnt work, and i have also tried calling its start method during construction of that object with a new Stage() passed in during construction. Please help!!! 

How can i instantiate this PreBoard() class and get it's start method to run without throwing this?

main class:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package battleship.model;
import battleship.viewcon.*;
import javafx.stage.Stage;

/**
 *
 * @author foolishklown
 */
public class MainApp {
    Player player1;
    Player player2;
    Board board1;
    Board board2;
    BattleshipGame theGame;
    PreBoard theGamePreBoard;     

    public void go() {                
        theGame = new BattleshipGame();        
        theGamePreBoard = new PreBoard();
        theGamePreBoard.start(new Stage());
        System.out.println(theGamePreBoard);
        theGamePreBoard.setBattleshipGame(theGame);         
    }

    public static void main(String[] args) {
        MainApp app = new MainApp();
        app.go();        
    }
}

PreBoard class:

/*
 * PreBoard object. This is the starter class for the different JavaFX stages (different windows - username screen,
 *  and each players window)
 * After first username input, this class hides and calls on a new P1Board object
 */
package battleship.viewcon;
import battleship.model.*;

import javafx.geometry.Insets;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;

/**
 * 
 *
 * @author c-dub
 */
public class PreBoard extends Application {
    private boolean turn; // field to determine which players name to put into which board
    private String player;       
    private Button hideBtn;
    private Button showBtn;
    private TextField userText;
    private ViewCon controller;    
    private P1Board p1B;
    private P2Board p2B;
    private BattleshipGame game;
    private Stage theStage;    


    @Override
    public void start(Stage primaryStage) {
        turn = false;       
        p1B = new P1Board();
        p2B = new P2Board();
        controller = new ViewCon();
        controller.setp1(p1B);
        controller.setp2(p2B);
        controller.setPreB(this);
        this.game = controller.getBattleshipGame();

        primaryStage.setTitle("Battleship setup"); //Main stage (window container)      
        //Gridpane for using rows/columns for child node placement
        GridPane grid = new GridPane();
        grid.setAlignment(Pos.CENTER_LEFT);
        grid.setHgap(10);
        grid.setVgap(5);
        grid.setPadding(new Insets(100, 25, 25, 25));

        // label in window
        Text sceneTitle = new Text("Setup");
        sceneTitle.setId("setup-text");
        grid.add(sceneTitle, 0, 0, 2, 1);

        // label and textfield
        Label userName = new Label("Enter UserName:");
        userName.setId("user-name");
        grid.add(userName, 0, 1);        
        TextField userTextField = new TextField();
        userTextField.setId("text-field");
        grid.add(userTextField, 0, 2);

        // button for setup, with actionListener to save player name or default if its left blank
        Button setupBtn = new Button("Setup Board");        
        HBox hbBtn = new HBox(10);
        hbBtn.setAlignment(Pos.BOTTOM_LEFT);
        hbBtn.getChildren().add(setupBtn);
        grid.add(hbBtn, 0, 3);

        setupBtn.setOnAction(new EventHandler<ActionEvent>() { 
            @Override
            public void handle(ActionEvent e) {
                // determine which player name to use to pass into which player board
                if(turn == false) {            
                    String temp1 = userTextField.getText();
                        if(temp1.equals("")) {
                            player = "Player1";
                        } else {
                            player = temp1;
                        }
                        controller.setPlayer1(player);                        
                        game.setPlayer1(player);
                        turn = true;
                        Stage stage = new Stage();
                        p1B.start(stage);
                        grid.getChildren().remove(userTextField);
                        userText = new TextField();
                        userText.setId("text-field2");
                        grid.add(userText, 0, 2);
                        hideBtn.fire();                        
                } else {

                    String temp2 = userText.getText();
                        if(temp2.equals("")) {
                            player = "Player2";
                        } else {
                            player = temp2;
                        }                        
                        controller.setPlayer2(player);
                        game.setPlayer2(player);
                        Stage stage2 = new Stage();
                        p2B.start(stage2);
                        hideBtn.fire();
                }                        
            }
        });


        hideBtn = new Button();        
        hideBtn.setId("hideBtn");
        hideBtn.setOnAction(new EventHandler<ActionEvent>() { 
            @Override
            public void handle(ActionEvent e) {
                primaryStage.hide();
            }
        });

        showBtn = new Button();
        showBtn.setId("showBtn");
        showBtn.setOnAction(new EventHandler<ActionEvent>() { 
            @Override
            public void handle(ActionEvent e) {
                primaryStage.show();
            }
        });

        controller.setPreShowBtn(showBtn);
        controller.setPreHideBtn(hideBtn);
        // Add the entire scene into the main window(stage) after setting the scene dimensions
        Scene scene = new Scene(grid, 580, 200);
        primaryStage.setScene(scene);
        // Attach css stylesheet
        scene.getStylesheets().add(PreBoard.class.getResource("styles/PreBoardStyle.css").toExternalForm());
        // Show this window(stage) upon instantiation
        primaryStage.show();        
    }

    public void setLink(ViewCon v) {        
        this.controller = v;
    }    

    public static void main(String[] args) {
        Application.launch(args);
    }

    public void setBattleshipGame(BattleshipGame b) {
        this.game = b;        
    }



}
Chris Wilson
  • 135
  • 3
  • 16
  • try `theGamePreBoard.launch(null);` – Yannick Rot Nov 28 '15 at 00:17
  • slightly different issue. I then get a nullPointerException, I tried to actually instantiate a brand new Stage() object directly inside the start method of PreBoard, but that ends up throwing the same original exception – Chris Wilson Nov 28 '15 at 00:34
  • see [JavaFX Life-cycle](https://docs.oracle.com/javase/8/javafx/api/javafx/application/Application.html) – Kachna Nov 28 '15 at 00:42
  • Possible duplicate of [Launch JavaFX application from another class](http://stackoverflow.com/questions/25873769/launch-javafx-application-from-another-class) – fabian Nov 28 '15 at 01:35
  • Sigh..... i totally thought that i had a quick fix, and that this program would be fine, but now i realize that i really dont understand javaFX and the threading issues with the entire grid. Reading about Concurrency in JavaFX is helping to understand how much shit is really going on with the way ive designed my portion of this battleship assignment. Absolute EPIC fail..... – Chris Wilson Nov 30 '15 at 11:21

1 Answers1

1

I don't think this has anything at all to do with threading: I don't see any reason why you would ever create another thread in this application. The part you seem to be missing is the actual life-cycle of a JavaFX application. (There's a little you could need to know about how JavaFX manages threading, but it is a bit incidental here.)

The Application class represents an entire application. Your application should typically have just one Application subclass, and one instance of that class. The instance is created for you by JavaFX when you call the static Application.launch() method (or when you execute your Application subclass from the command line, which effectively calls launch for you).

When launch is invoked, the JavaFX toolkit (including the FX Application Thread) is started. An instance of theApplication subclass is created for you, and then start(...) is invoked on that instance on the FX Application Thread.

So what that means is that the start(...) method is the entry point (startup) for your JavaFX application. Since the most common thing to do here is to display something in a window, a window (Stage) is passed into this method for your convenience: however you can ignore it and just create your own if you like.

A typical start(...) method should be quite short, and will usually just create some UI (maybe defined in another class or in an FXML file), put that UI in a scene, and display the scene in a stage. In a more complex application, you will create an instance of your model class here, create some views and controllers, give the controllers references to the model, and assemble the views.

For a simple structural example, see my answer to Java: How do I start a standalone application from the current one when both are in the same package? (which is a similar question, I think).

Community
  • 1
  • 1
James_D
  • 201,275
  • 16
  • 291
  • 322
  • That absolutely explains everything i need to know to rewrite/restructure this app! Thank you so much, and i will post the before and after code for other people that have similar issues...... thanks a million! I will admit that lack of research, lack of understanding a new software platform, and a totally overcomplicated MVC is what screwed me up this time, i was calling start methods left and right in different classes. – Chris Wilson Dec 01 '15 at 19:55