Manage multiple screens JavaFX [duplicate] - java

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(); } }

Related

How to use JavaFX in Main

I am completly lost atm. I have been working with scenebuilder and javaFX in the past but I am stuck like 5 hours now and I didnt get a step further. Let me explain:
I have a working java Eclipse Project, using maven dependencies
The Main is where I want to use JavaFX or load a fxml into
The programm takes many many VCC Files and extracts the data to put it all together in an excel
The programm works but I cant load a FXML file into the main or even show a pane in there
Now does my Java Main class has to extend Application? I tried both ways - doenst work.
Some example code:
public void start(Stage primaryStage) {
try {
bpmain = new BorderPane(FXMLLoader.load(new File("src\\fxml\\UserInterface.fxml").toURI().toURL()));
primaryStage.setScene(new Scene(bpmain));
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
or this (from original Docs)
public void start(Stage stage) {
Circle circ = new Circle(40, 40, 30);
Group root = new Group(circ);
Scene scene = new Scene(root, 400, 300);
stage.setTitle("My JavaFX Application");
stage.setScene(scene);
stage.show();
}
but this start method is just not getting called... where do I put that?
What my Programm should look like is pretty simple actually. I want a small UI Windows that lets you pick a Folder where the VCC data lives in and a OK Button that basically should run the Main method.
So a TextField that when its picked a Path in the Main gets replaced (filepath) and just a simple OK Button that says: yeah run the main - because the main works perfectly it is just that I cant show that ui and I dont know how to really connect it to the Main.java
Any help is appreciated - Ty
Option 1
public class Launch extends Application {
public static Stage stage = null;
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/fxml/Main.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
this.stage = stage;
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Option 2:
public class SidebarController implements Initializable {
#Override
public void initialize(URL url, ResourceBundle rb) {
}
#FXML
void btnHome_OnMouseClicked(MouseEvent event) throws IOException {
BorderPane borderPane = (BorderPane) ((Node) event.getSource()).getScene().getRoot();
Parent sidebar = FXMLLoader.load(getClass().getResource("/fxml/ContentArea.fxml"));
borderPane.setCenter(sidebar);
}
}

JAVAFX secondary panels

Hi guys a little programmer java Swing and I'm trying a new technology like JavaFx just that I just can not figure out how to make operations for navigation between views, in particular.
How can I replace a main view on the stage? for example I have a view that I associate with the calback start method in the scene in the following way
#Override
public void start(Stage primaryStage) {
vistaPrincipale.load();
Scene scene = new Scene(vistaPrincipale.getRoot());
primaryStage.setScene(scene);
primaryStage.show();
}
and during the execution of the program I would like to change the view one with the view two, only that I could not really understand how I did not even find enough material to solve the problem, in swing it was enough to change the frame content bread
another problem that I have encountered is to launch a secondary panel like a jdialog in swing, I solved this problem by creating a new stage and using it in the following way, but to be honest it really seems like a very bad solution
public class InfoAutori {
private static final Logger LOGGER = LoggerFactory.getLogger(InfoAutori.class);
private Stage stage;
public void init(){
FXMLLoader load = new FXMLLoader();
Parent root = new AnchorPane();
try {
root = load.load(getClass().getResourceAsStream("InfoAutori.fxml"));
} catch (Exception e) {
LOGGER.error("Si e' verificato un errore del tipo: " +
e.getLocalizedMessage());
e.printStackTrace();
}
stage = new Stage();
Scene scene = new Scene(root);
stage.setScene(scene);
}
public void visualizza(){
stage.showAndWait();
}
}

How to run one of multiple distinct stages at application startup with javafx?

I'm starting with javafx and I'm having some trouble understanding how to correctly model the following situation:
Ideally I'd like to have a main() method that would somehow allow me to either open a LoginDialog or if there's already a user/password combination available on disk, to bypass login and directly show the MainDialog to the user.
My main issue is that when I run Application.launch() I'm expected to submit an Application instance, and when implementing one, I don't have any control over its Stage object creation, which creates a catch-22 for me here.
I could create a LoginScene and MainScene but then I'd have no control for things like the Stage's title, for instance.
What's the usual route to solve this kind of issues with javafx?
Thanks
Define a single Application subclass and put the logic to decide whether you need to show the login screen in the start() method (the proper place for startup logic is the aptly-named start() method, not the main method):
public class MyApplication extends Application {
private boolean loggedIn ;
#Override
public void start(Stage primaryStage) {
loggedIn = checkLoginFromDisk();
while (! loggedIn) {
FXMLLoader loginLoader = new FXMLLoader(getClass().getResource("path/to/login.fxml"));
Parent loginRoot = loginLoader.load();
LoginController loginController = loginLoader.getController();
Scene loginScene = new Scene(loginRoot);
primaryStage.setScene(loginScene);
primaryStage.setTitle("Login");
primaryStage.showAndWait();
// check login from controller and update loggedIn...
}
FXMLLoader mainLoader = new FXMLLoader(getClass().getResource("path/to/main.fxml"));
Parent mainRoot = mainLoader.load();
Scene mainScene = new Scene(mainRoot);
primaryStage.setScene(mainScene);
primaryStage.setTitle("My Application");
primaryStage.sizeToScene();
primaryStage.show();
}
private boolean checkLoginFromDisk() {
// ... etc
}
// for environments not supporting direct launch of JavaFX:
public static void main(String[] args) {
launch(args);
}
}
If you're not using FXML, you just define classes instead of FXML files + controllers for "login" and "main", but the structure stays the same:
public class LoginView {
private final GridPane /* for example */ view ;
public LoginView() {
// setup UI, etc...
}
public Pane getView() {
return view ;
}
public boolean checkLogin() {
// etc...
}
}
and
public class MainView {
private BorderPane /* for example */ view ;
public MainView() {
// set up UI etc...
}
public Pane getView() {
return view ;
}
}
and your start method then looks like
#Override
public void start(Stage primaryStage) {
loggedIn = checkLoginFromDisk();
while (! loggedIn) {
LoginView loginView = new LoginView();
Scene loginScene = new Scene(loginView.getView());
primaryStage.setScene(loginScene);
primaryStage.setTitle("Login");
primaryStage.showAndWait();
loggedIn = loginView.checkLogin();
}
MainView mainView = new MainView();
Scene mainScene = new Scene(mainView.getView());
primaryStage.setScene(mainScene);
primaryStage.setTitle("My Application");
primaryStage.sizeToScene();
primaryStage.show();
}
Obviously you can refactor this in many different ways (reuse the same login class or fxml instance, use a different stage for the main view, etc etc etc) as you need.
Note that there is no requirement to use the stage passed to the start() method. So if you wanted standalone classes to encapsulate the stage containing a login scene and a main scene, you could add the following classes:
public class LoginStage extends Stage {
private final LoginView loginView ;
public LoginStage() {
loginView = new LoginView();
setScene(new Scene(loginView.getView());
setTitle("Login");
}
public boolean checkLogin() {
return loginView.checkLogin();
}
}
and similarly make a MainStage class. (In the FXML-based version, the LoginStage holds a reference to the LoginController and just loads the FXML in the constructor instead of instantiating the LoginView class.) Then
public class MyApplication extends Application {
private boolean loggedIn ;
#Override
public void start(Stage ignored) {
loggedIn = checkLoginFromDisk();
while (! loggedIn) {
LoginStage login = new LoginStage();
loginStage.showAndWait();
loggedIn = loginStage.checkLogin();
}
new MainStage().show();
}
// ...
}
This seems to be remarkably similar to what I was looking for. It follows jns suggestion.
Not ideal but not terrible:
class LoginScene(stage: Stage) extends Scene(new VBox()) {
val vbox = this.getRoot.asInstanceOf[VBox]
...
}
class MainScene(stage: Stage) extends Scene(new VBox()) {
val vbox = this.getRoot.asInstanceOf[VBox]
...
}
class ApplicationStartup extends Application {
override def start(primaryStage: Stage): Unit = {
val scene = if (...) new LoginScene(primaryStage) else new MainScene(primaryStage)
primaryStage.setScene(scene)
primaryStage.show()
}
}
(code is presented in Scala)
Alternatively, as can be seen from the question's comments, one can just ignore the primaryStage and create our own ones at will, which it's just what I wanted from the outset:
class MainDialog extends Application {
override def start(primaryStage: Stage): Unit = {
val newStage = new Stage {
setTitle("abcdef")
setScene(new Scene(new Button("Hello World")))
}
newStage.show()
}
}

Java: How do I start a standalone application from the current one when both are in the same package?

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(); } }

Making Stage static in javaFX. is it a good idea?

I actually want to build a fx application that go from one fxml to another (with this process :fxml number 1 load then go with a click and another load).
I have made stage in my main class static and use it again and again.
according to Restriction of stack space in ram is it a good idea ?? or there is a better way?
these are parts of my code:
public class Main extends Application {
public static Stage stage;
#Override
public void start(Stage primaryStage) throws Exception{
stage=primaryStage;
Parent root = FXMLLoader.load(getClass().getResource("MainWidget.fxml"));
stage.setTitle("Welcome");
stage.setScene(new Scene(root, 300, 275));
stage.show();
}
and my controller is(loading another fxml!! )
public void someButtonController{
Parent root = FXMLLoader.load(getClass().getResource("/View/ShowWidget.fxml"));
Scene scene = new Scene(root,300,300);
Main.stage.setScene(scene);
Main.stage.show();}
I would not expose the Stage at all. Doing so couples your FXML-Controller pair to your Main class and prevents you ever using it without that class.
Instead, do something like
#FXML
private Button someButton ;
// ...
public void someButtonController{
Window window = someButton.getScene().getWindow();
if (window instanceof Stage) {
Parent root = FXMLLoader.load(getClass().getResource("/View/ShowWidget.fxml"));
Scene scene = new Scene(root,300,300);
Stage stage = (Stage) window ;
stage.setScene(scene);
stage.show(); // isn't it necessarily showing already?
}
}
Here I'm assuming that the controller is the controller for an FXML file representing Nodes that are displayed in the Stage you're trying to access. If that's not the case, you can still do something similar though it will be more complex.

Categories

Resources