I'm trying to implement an application, which has a simple navigation. One Main Menu, 3 Submenus, with another 3 Submenus each.
I need the application open every submenu recursively in the same Window with the Mainmenu as the root screen. I must be able to return to that menu by going via the "Back" Button on each Submenu.
I implemented a Main class, a Controller Class and a FXML-file for EACH (!) Menu and Submenu.
E.g. my Main Menu
package application;
import org.apache.log4j.Logger;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
public class Main extends Application {
// Initialize Logger
private static final Logger logger = Logger.getLogger(Main.class);
#Override
public void start(Stage primaryStage)
{
try
{
AnchorPane root = (AnchorPane)FXMLLoader.load(getClass().getResource("MainFrame.fxml"));
Scene scene = new Scene(root,1000,500);
primaryStage.setScene(scene);
primaryStage.show();
}
catch(Exception e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
logger.info("Starting application.");
launch(args);
}
}
My MainController
package application;
import org.apache.log4j.Logger;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class MainFrameController
{
private static final Logger logger = Logger.getLogger(MainFrameController.class);
#FXML
private Button btn_random1;
#FXML
private Button btn_random2;
#FXML
private Button btn_random3;
#FXML
private Button btn_random4;
public void initialize()
{
//mainService = new MainService();
}
#FXML
private void onRandomButton1() throws Exception
{
logger.info("onRandomButton1Clicked");
Stage stage = new Stage();
AnchorPane root;
root = (AnchorPane)FXMLLoader.load(getClass().getResource("RandomFXML1.fxml"));
Scene scene = new Scene(root,1000,500);
stage.setScene(scene);
stage.show();
}
#FXML
private void onRandomButton2()
{
logger.info("onRandomButton1");
}
#FXML
private void onRandomButton3()
{
logger.info("onRandomButton2");
}
#FXML
private void onRandomButton4()
{
Platform.exit();
logger.info("onRandomButton3");
}
}
Is there a way to simply change my code, so it does open in the same window?
I took a look at several tutorials with relatively complex ways of solving this, I'd like to stick to my code and not changing too much, otherwise I'd have to start all over again.
Pls note, that this is only one of many Main/Controller/FXML combinations, I have about 10 screens and "subscreens", which are being navigated like this (by java opening a new window).
Ideas anyone? Or maybe a relatively simple tutorial (for which I dont have to change my whole code)?
Thanks!
Have an empty controller at the root (or perhaps with a single empty anchorpane) and have it open the other controllers and add it to the current pane?
I currently have a similar setup but with a tab pane: each module is loaded into a separate tab. Each module itself has an fxml file, a controller etc. The core code dynamically creates new tabs etc for each module and loads them.
Related
This question already has an answer here:
How do I determine the correct path for FXML files, CSS files, Images, and other resources needed by my JavaFX Application?
(1 answer)
Closed 2 years ago.
I have two packages p1 and p2.
P1 contains the main class, controller class and one fxml file.
P2 contains the controller class and one fxml file.
I want to switch from p1 fxml to p2 fxml file.
here is the code I tried. this is in P1 package.
public void btncontinue(ActionEvent event)throws IOException {
String filepath = "file:///D:/Programs/InteliJProjects/C/src/p1/sample2.fxml";
Parent nextScene = FXMLLoader.load(getClass().getClassLoader().getResource(filepath));
Scene scene = new Scene(nextScene);
Stage stage = (Stage)((Node)event.getSource()).getScene().getWindow();
stage.setScene(scene);
stage.show();
}
The error i am getting is Location is required.
Well I've checked this is the code from scene1 to scene2
package sample;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.control.PasswordField;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import java.io.IOException;
public class sample
{
#FXML
RadioButton male;
#FXML
AnchorPane rootPane;
public void add() throws IOException
{
AnchorPane pane = FXMLLoader.load(getClass().getResource("two.fxml"));
rootPane.getChildren().setAll(pane);
}
}
And this is how to return from scene2 to scene1
package sample;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import java.io.IOException;
public class Two
{
#FXML
Button back;
#FXML
AnchorPane secPane;
public void returnBack() throws IOException
{
AnchorPane pane = FXMLLoader.load(getClass().getResource("sample.fxml"));
secPane.getChildren().setAll(pane);
}
}
I've tried this and it is working fine hope it will help you
I am trying to create a program to teach people about GNU/Linux and the command line, I have my main.java
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
Stage window;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
window = primaryStage;
Parent root = FXMLLoader.load(getClass().getResource("login.fxml"));
primaryStage.setTitle("Learnix");
primaryStage.setScene(new Scene(root, 800, 500));
primaryStage.show();
}
}
And the controller to go with it.
package sample;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import java.io.IOException;
public class loginController {
public Button loginBtn;
public void loginBtnClick() throws IOException {
System.out.println("You are logged in");
}
}
I have tried things such as:
FXMLLoader.load(getClass().getResource("lessons.fxml"));
But I can't figure out how to get it to swap scenes. I have seen many tutorials on YouTube and it Stack Overflow but many of them have all of the JavaFX on the main.java and not in separate files as I am using scenebuilder.
Thank you.
You can either call Stage.setScene() to change the whole scene or just substitute a root to the new one by Scene.setRoot():
Parent newRoot = FXMLLoader.load(getClass().getResource("lessons.fxml"));
primaryStage.getScene().setRoot(newRoot);
Why does the following code always show null in the console when I want to get the controller ?
RenewCardFXML2_controller controller=loader.getController();
and the console prints null when i press the button.
I have two controllers and want to use textfield from the main app(membershipcards)-txt_numberOfCard_GENERAL inside the second fxml file whick has its own controller.
txt_numberOfCard_GENERAL.getText command from seccond controller and use its value.
/*
* 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 membershipcards;
import java.io.IOException;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.SplitPane;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import membershipcards.RenewCardFXML2_controller;
/**
*
* #author Primary
*/
public class mainGUIController implements Initializable {
#FXML
private ImageView logoimg;
#FXML
private SplitPane splitMenuContent;
#FXML
private Button btnCards;
#FXML
private Button btnRenewCard;
#FXML
private Button bntNewClient;
#FXML
private Button btnEditCard;
#FXML
private Button btnStatistics;
#FXML
private AnchorPane detailsPane;
#FXML
private Button btnCardN;
#FXML
public TextField txt_numberOfCard_GENERAL;
#FXML
public TextField txt_memberName_GENERAL;
#Override
public void initialize(URL url, ResourceBundle rb) {
}
#FXML
private void loadCardsFXML1(ActionEvent event) {
try {
detailsPane = (AnchorPane) FXMLLoader.load(getClass().getResource("CardsFXML1.fxml"));
} catch (IOException ex) {
Logger.getLogger(mainGUIController.class.getName()).log(Level.SEVERE, null, ex);
}
splitMenuContent.getItems().set(1, detailsPane);
}
#FXML
private void loadRenewCardFXML2(ActionEvent event)throws IOException {
FXMLLoader loader = new FXMLLoader();
detailsPane = (AnchorPane) loader.load(getClass().getResource("RenewCardFXML2.fxml"));
splitMenuContent.getItems().set(1, detailsPane);
RenewCardFXML2_controller controller=loader.getController();
controller.setMGC(this);
System.out.println(controller);
}
}
The FXMLLoader.load(URL) method you are calling is a static method. Consequently, you have not called load on the FXMLLoader instance you created, and since that instance hasn't loaded the FXML, it has not initialized its controller field.
(A good IDE will give you a warning on your loader.load(...) line about calling a static method from a non-static context, or something similar. Eclipse, for example, says "The static method load(URL) should be accessed in a static way.")
The following will work:
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("RenewCardFXML2.fxml"));
detailsPane = loader.load();
splitMenuContent.getItems().set(1, detailsPane);
RenewCardFXML2_controller controller=loader.getController();
Note that you can reduce the first two lines of that code block to a single line
FXMLLoader loader = new FXMLLoader(getClass().getResource("RenewCardFXML2.fxml"));
detailsPane = loader.load();
I have just started learning java fx and I am trying to get user input from two text field. Once they click the button this will be displayed on a console.
However, I am keep getting an error and cannot figure out why.
I have assigned the 'handle' function using Scenebuilder, the error is pointing at the method.
Main Class:
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Controller:
package sample;
import javafx.event.ActionEvent;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
public class Controller {
public TextField userField;
public TextField passField;
public Button logButton;
public void handle(ActionEvent event) {
String username = userField.getText();
String passw = passField.getText();
System.out.printf("Logged in as %s %s", username, passw);
}
}
although you didn't show the error, but i think it's because you didn't annotate the fields userField and passwordField with #FXML annotation
by this annotation you tie the fields in the controller with fields in the fxml
so to solve this problem let's do the following simple steps
public class Controller implements Initializable{
#FXML
private TextField userField;
#FXML
private TextField passField;
#FXML
private Button logButton;
private void handle(ActionEvent event)
{
System.out.println(userField.getText());
}
#Override
public void initialize(URL url, ResourceBundle rb)
{
logButton.setOnAction(this::handle);
}}
and in the scene builder follow this image
try this,and if you still have problems just let a comment (:
As you are using Scene Builder, you should use the sample controller skeleton: Under View, select Use Sample Controller Skeleton. Also, specify the "On Action" for the text field. Scene Builder will dot the i's and cross the t's for you.
I'm trying to learn JavaFX. To do so I've been attempting to make a text editor that includes multiple line text box support, as well as the possibility of having syntax highlighting down the road.
Currently, the biggest problem I've been facing is that the ScrollPane I've been encapsulating all my FlowPanes in won't resize according to the size of the Pane it's in. I've been researching this problem for about half a week now and simply cannot get the ScrollPane to just fill the window it's in. The code below displays a JavaFX stage that has working keyboard input and the ScrollPane is always the same size no matter what. Thanks to all in advance!
Here's my Main:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Launcher extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setScene(new Scene(new DynamicTextBox(),500,500));
primaryStage.show();
}
}
TextBox class:
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
import javafx.geometry.Orientation;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.Pane;
import javafx.scene.text.Text;
public class DynamicTextBox extends Pane {
//currentLinePane is made to handle all the direct user inputs
//multiLinePane, while not really used yet will create a new line when the enter key is struck.
private FlowPane currentLinePane, multiLinePane;
private ScrollPane editorScroller;
public DynamicTextBox() {
super();
currentLinePane = new FlowPane(Orientation.HORIZONTAL);
multiLinePane = new FlowPane(Orientation.VERTICAL);
multiLinePane.getChildren().add(currentLinePane);
editorScroller = new ScrollPane(multiLinePane);
editorScroller.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
editorScroller.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
editorScroller.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
configureInput(event);
}
});
super.getChildren().add(editorScroller);
editorScroller.requestFocus();
}
private void configureInput(KeyEvent event) {
currentLinePane.getChildren().add(new Text(event.getText()));
}
}
You're using
ScrollPane.ScrollBarPolicy.AS_NEEDED
which, according to the docs at Oracle, "Indicates that a scroll bar should be shown when required." Instead, use
ScrollPane.ScrollBarPolicy.ALWAYS
alternatively, recall these are constants. you can get the height of the parent using boundsInParent: https://docs.oracle.com/javafx/2/api/javafx/scene/Node.html#boundsInParentProperty
alternatively, you can use getParent() to get the parent and then get its height using computeMinWidth() https://docs.oracle.com/javafx/2/api/javafx/scene/Node.html#getParent()