Reputation: 135
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;
}
}
Upvotes: 0
Views: 3904
Reputation: 209330
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).
Upvotes: 1