Changing scene in another class method JavaFX - javafx

I'm new to JavaFX. I'm trying to change scene in my first project and I'm wondering if I can do it like that:
public class A {
...
public void start(Stage primaryStage) throws Exception {
...
B ObjectB = new B();
Scene scene = new Scene();
primaryStage.setScene(scene);
...
if (...) {
ObjectB.anotherFunction(primaryStage);
}
primaryStage.show();
}
}
public class B {
...
public void anotherFunction(Stage stage) {
...
Scene NewScene = new Scene();
stage.setScene(NewScene);
stage.show();
}
}
Code above is shortened version of what I wrote.
I want to change scene from one class that is like menu class (A) in other class (B) and display new scene on the screen. It seems like it's not possible in the way I did it and I'm curious what are good practices in that kind of things.

It`s works. For example just try simply call
ObjectB.anotherFunction(primaryStage);
after or before your
primaryStage.show();
method. Your problem here is that you check this "if" once, even before showing this stage and it false at the start, and then, when it comes true - this piece of code already passed. You just need to run ObjectB.anotherFunction(primaryStage);, when set condition of your if to true.
PS. and pls, start name of your variables from a small letter, objectB instead of ObjectB - it`s just a Java Naming Convention.

Related

JavaFX keyboard input stops working after adding buttons

I am building a game engine as a school project. When I add button to the same group as where I have my canvas, I can't control my player anymore with keyboard. Buttons and everything else still works like normal.
My code is pretty huge, so this is a simplified code of the problem:
public abstract class GEngine extends Application {
public void start(Stage theStage) throws Exception {
try {
this.stage = theStage;
Group root = new Group();
Scene theScene = new Scene(root);
stage.setScene(theScene);
Canvas canvas = new Canvas(windowWidth, windowHeight);
root.getChildren().add(canvas);
Button btn = new Button("new");
btn.setOnMousePressed(e->System.out.println("press"));
root.getChildren().add(btn);
Timeline gameLoop = new Timeline();
gameLoop.setCycleCount(Timeline.INDEFINITE);
// Handle input
theScene.setOnKeyPressed(Input::handlePressed);
theScene.setOnKeyReleased(Input::handleReleased);
// Control game loop and it's speed
KeyFrame kf = new KeyFrame(
Duration.seconds(0.017), // 60 FPS
(e)->this.controlGameLoop());
gameLoop.getKeyFrames().add( kf );
gameLoop.play();
stage.show();
} catch (Exception e) {
e.printStackTrace();
stop();
}
}
}
There is probably something happening on the background which I just don't understand. I can show my Input class code too if somebody wants to see it, but in my understanding it's not necessary.
I have tried using AnchorPane as main root and make a separate groups for buttons and canvas which I add the to the AnchorPane, but that did not help at all. That was pretty much the only offered solution I could find from google.
Adding btn.setFocusTraversable(false); fixed the problem, thanks to Luxusproblem for providing the answer!

Add JavaFX Label - (Using Only Java / JavaFX Code) - To Existing GUI Created With Scenebuilder / FXML

I Created a complete GUI using ONLY Scenebuilder FXML Techniques
Something Like This :-
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception{
Parent root=FXMLLoader.load(getClass().getResource("backupmenu.fxml"));
primaryStage.setTitle("Backup Affected Files And Folders Only");
primaryStage.setScene(new Scene( root, 800, 400));
primaryStage.show();
}
}
However I want to add a label to that SAME EXISTING GUI but this time using ONLY Java Code / JavaFX Label Techniques ?
I.E Using Traditional Methods such as this Example Below :-
// launch the application
public void start(Stage s)
{
// set title for the stage
s.setTitle("creating label");
// create a label
Label b = new Label("This is a label");
// create a Stack pane
StackPane rootpane = new StackPane();
// add password field
rootpane.getChildren().add(b);
// create a scene
Scene sc = new Scene(rootpane, 200, 200);
// set the scene
s.setScene(sc);
s.show();
}
public static void main(String args[])
{
// launch the application
launch(args);
}
}
I cannot find a web search result that even comes close to matching my very specific question .
Can i combine the 2 techniques - Is it Possible ?
Yes, this is possible.
You need a reference to the Parent (some kind of container Pane or Node) you want to add the Label to in your controller class.
For example, suppose your FXML defines a VBox with an id of "root":
<VBox fx:id="root">
In your controller, define a reference to that VBox:
#FXML
private VBox root;
Then you can add anything you want to the VBox:
root.getChildren().add(new Label("Hi, I'm a new Label!"));

How can I use .setText on a non-Static Label from a different Class [duplicate]

I have written a controller for two windows /stages.
The first window is opened in the MainClass. The second in the Controller, if the user clicks onto a button.
How can I get the TextFields from second.fxml in the applyFor()-method?
Thanks.
#FXML
protected void requestNewAccount(ActionEvent event) {
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("second.fxml")); // TextFields in there
Parent root = (Parent) fxmlLoader.load();
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.setTitle("Second Window");
Scene scene = new Scene(root);
String css = MainOnlineCustomer.class.getResource("/style.css").toExternalForm();
scene.getStylesheets().clear();
scene.getStylesheets().add(css);
stage.setScene(scene);
stage.show();
} catch (IOException e) {
logger.error(e);
}
}
/**
* closes the "second"-Window
* #param event
*/
#FXML
protected void cancel(ActionEvent event) {
final Node source = (Node) event.getSource();
final Stage stage = (Stage) source.getScene().getWindow();
stage.close();
}
#FXML
protected void applyFor(ActionEvent event) {
// get values from TextField in second.fxml here!!!
}
It's not good to share controllers between fxmls unless they serve the same purpose. Here both fxml seem to serve a different purpose (account management, login or something similar for one of them and creating a new account for the other). What is even worse is that those classes do not share the same controller instance, which means the small (and probably only) benefit you could get from using the same controller, is not used here. You should better use different controllers.
Since you use Modality.APPLICATION_MODAL as modality, I'd recommend using showAndWait instead of show to open the new stage. This will enter a nested event loop, which allows the UI to remain responsive and continues after the invocation of showAndWait once the stage is closed.
Furthermore add a method to the controller of second.fxml that allows you to retrieve the result.
Example
This creates a Person object with given name and family name.
"primary window (opening the "inner" stage)
FXMLLoader loader = new FXMLLoader(getClass().getResource("second.fxml"));
Stage subStage = new Stage();
subStage.initModality(Modality.APPLICATION_MODAL);
subStage.setTitle("Second Window");
Scene scene = new Scene(loader.load());
subStage.setScene(scene);
subStage.showAndWait();
Optional<Person> result = loader.<Supplier<Optional<Person>>>getController().get();
if (result.isPresent()) {
// do something with the result
}
controller for "inner" content
public class SecondController implements Supplier<Optional<Person>> {
#FXML
private TextField givenName;
#FXML
private TextField familyName;
private boolean submitted = false;
// handler for submit action
#FXML
private void submit() {
submitted = true;
givenName.getScene().getWindow().hide();
}
// handler for cancel action
#FXML
private void cancel() {
givenName.getScene().getWindow().hide();
}
#Override
public Optional<Person> get() {
return submitted ? Optional.of(new Person(givenName.getText(), familyName.getText())) : Optional.empty();
}
}
Note that you can gain access to any data available to the controller this way. I wouldn't recommend accessing any nodes (like TextFields) directly though, since this makes changing the UI harder.
Using the Supplier interface here is not necessary, but I chose to do this to achieve a loose coupling between SecondController and the main window.

Embedding a JavaFX application in a second application [duplicate]

This seems like it should be easy, so I must be missing something obvious: I have 4 standalone applications in the same package, us.glenedwards.myPackage,
myClass1 extends Application
myClass2 extends Application
etc...
I need each class to act as its own standalone application. Yet I want to be able to start the other 3 classes from the one I'm in by clicking a link. Android allows me to do this using Intents:
Intent intent = new Intent(this, EditData.class);
overridePendingTransition(R.layout.edit_data_scrollview, R.layout.state);
startActivity(intent);
I've tried starting myClass2 from myClass1 using
myClass2.launch("");
But I get an error, "Application launch must not be called more than once". The only way I can get it to work is if I remove both "extends application" and the start() method from myClass2, which means that myClass2 is no longer a standalone application.
How can I start myClass2, myClass3, or myClass4 from myClass1 with all 4 of them being standalone applications?
You can make this work by calling start(...) directly on a new instance of one of the Application subclasses, but it kind of feels like a bit of a hack, and is contrary to the intended use of the start(...) method. (Just semantically: a method called start in a class called Application should be executed when your application starts, not at some arbitrary point after it is already running.)
You should really think of the start method as the replacement for the main method in a traditional Java application. If you had one application calling another application's main method, you would (hopefully) come to the conclusion that you had structured things incorrectly.
So I would recommend refactoring your design so that your individual components are not application subclasses, but just plain old regular classes:
public class FirstModule {
// can be any Parent subclass:
private BorderPane view ;
public FirstModule() {
// create view; you could also just load some FXML if you use FXML
view = new BorderPane();
// configure view, populate with controls, etc...
}
public Parent getView() {
return view ;
}
// other methods as needed...
}
and, similarly,
public class SecondModule {
private GridPane view ;
public SecondModule {
view = new GridPane();
// etc etc
}
public Parent getView() {
return view ;
}
}
Now you can just do things like
FirstModule firstModule = new FirstModule();
Scene scene = new Scene(firstModule.getView());
Stage stage = new Stage();
stage.setScene(scene);
stage.show();
anywhere you need to do them. So you can create standalone applications for each module:
public class FirstApplication extends Application {
#Override
public void start(Stage primaryStage) {
Scene scene = new Scene(new FirstModule().getView());
primaryStage.setScene(scene);
primaryStage.show();
}
}
or you can instantiate them as part of a bigger application:
public class CompositeModule {
private HBox view ;
public CompositeModule() {
Button first = new Button("First Module");
first.setOnAction(e -> {
Parent view = new FirstModule().getView();
Scene scene = new Scene(view);
Stage stage = new Stage();
stage.initOwner(first.getScene().getWindow());
stage.setScene(scene);
stage.show();
});
Button second = new Button("Second Module");
second.setOnAction(e -> {
Parent view = new SecondModule().getView();
Scene scene = new Scene(view);
Stage stage = new Stage();
stage.initOwner(second.getScene().getWindow());
stage.setScene(scene);
stage.show();
});
HBox view = new HBox(10, first, second);
view.setAlignment(Pos.CENTER);
}
public Parent getView() {
return view ;
}
}
and
public class CompositeApplication extends Application {
#Override
public void start(Stage primaryStage) {
Scene scene = new Scene(new CompositeModule().getView(), 360, 150);
primaryStage.setScene(scene);
primaryStage.show();
}
}
The way I think of this is that Application subclasses represent an entire running application. Consequently it makes sense only to ever instantiate one such class once per JVM, so you should consider these inherently not to be reusable. Move any code you want to reuse into a different class somewhere.
have you tried this?
Runtime.getRuntime().exec("myClass1 [args]"); //put all args as you used in command
Also, handle/catch the exceptions, as needed.
I was right; it was a no-brainer. That's what I get for writing code on 4 hours of sleep:
myClass2 class2 = new myClass2();
try {
class2.start(stage);
} catch (Exception e) { e.printStackTrace(); } }

JavaFX 2. How to stop or pause all animations?

I am working on creating a small game.
I use scene switching (scene with a main game's screen and scene with some Help information). So, I decided to use HashMap scenes and set all scenes there. And clicking the button "Help" causes the scene switching.
But I have an issue. I want to stop all animations on non-active scene and currently I just set scene as NULL. I know that it is very bad realization.
Could somebody help me and also explain how to pause or stop all animations on scene?
Setting scene on primaryStage:
public static void setSceneToStage(String sceneId, Stage stage) {
SceneCollection.instance().clearCurrentActiveScene();
SceneCollection.instance().setNewActiveScene(sceneId);
stage.setScene(SceneCollection.instance().getScene(sceneId));
stage.setTitle(sceneId);
}
Clearing non-active scene:
public void clearCurrentActiveScene() {
if(activeScene != null) {
scenes.get(activeScene).clearScene();
}
}
public void clearScene() {
scene = null;
}
Initialize new scene:
public void setNewActiveScene(String sceneId) {
activeScene = sceneId;
scenes.get(sceneId).init();
}
public void init() {
scene = new Scene(new Pane(), 300, 300);
}
I think your program has to have a structure that you can have access to all transitions at time, for example you can have ''TransitonManager Class'' and in that class you have a arraylist of transitions and then you can add this transitions to that in their constructors and then when ever you want , you can have access to all transitions and stop them.
class TransitionManger{
public static ArrayList<Transition> transitions = new ArrayList<>();
}
class CustomTransition extends Transition{
CustomTransition(){
TransitionManger.transitions.add(this);
}
#Override
protected void interpolate(double v) {
//todo do what you want
}
}
you can also use singleton design pattern for TransitionManger for better encapsulation.

Resources