Was marked as duplicate, but still: my question does not refer to override annotations in general, but specifically in fxml controllers.
I am pretty new to java and trying to build a fxml application. I want to add an #Override annotation to a java fxml controller, but I am getting the error message "error: method does not override or implement a method from a supertype", and I cannot figure the origin of the mistake.
The same annotation can be used without any problem to the main java document, so I don't why it is not possible in the controller. The function only is effective once used with the #Override annotation, so commenting it out makes the function useless.
Is is impossible to use additional #Overrides in the controller, or is it a matter of handling them correctly?
public class Main_FXMLController implements Initializable {
private Button button;
#FXML
private void handleButtonAction(ActionEvent event) throws IOException {
System.out.println("You clicked me!");
Platform.exit();
}
// I am trying to add to #Override annotation here, but it returns " method does not override or implement a method from a supertype"
#Override
private static void test () {
System.out.println("Test");
}
#Override
public void initialize(URL url, ResourceBundle rb) {
}
Related
I am trying to build my first 'real' application with java using JavaFX. I'm using FXML to design the whole thing and so I decided to divide up some parts into different .fxml files and link those to different controllers. I'm using one MainController linked to main.fxml, and within main.fxml I call some other fxml files using fx:include. All includes have their own controller.
The issue is that the controllers don't operate 100% independently, sometimes you want to press a button linked to one controller and have that so something to another controller. I have a solution that works, but I'm not sure if it is the best way to do it.
My solution is this: Have one abstract SubController class, which has protected static fields for each of the subcontrollers. Upon initialization MainController fills all of these fields with the controller classes it gets from main.fxml, as well as one field for MainController itself. Each of the sub-controllers inherit from SubController so that they can access the static fields and call the public methods of the other controllers.
public abstract class SubController implements Initializable {
protected static MainController mainController;
protected static MenuBarController menuBarController;
protected static VideoPanelController videoPanelController;
public static void setMainController(MainController mainController) {
SubController.mainController = mainController;
}
public static void setMenuBarController(MenuBarController menuBarController) {
SubController.menuBarController = menuBarController;
}
public static void setVideoPanelController(VideoPanelController videoPanelController) {
SubController.videoPanelController = videoPanelController;
}
}
public class MainController implements Initializable {
#FXML private MenuBarController menuBarController;
#FXML private VideoPanelController videoPanelController;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
SubController.setMainController(this);
SubController.setMenuBarController(menuBarController);
SubController.setVideoPanelController(videoPanelController);
}
This way when a button is clicked in the menu bar, it can use a public method of the video panel controller:
public class MenuBarController extends SubController {
public void openVideo() {
File selectedFile = chooseFiles(VIDEO_EXTENSIONS);
if (selectedFile == null) return;
videoPanelController.loadVideo(selectedFile);
}
}
This works quite well, but I still feel like there's probably an easier way to do it. Is this a good way to go about it and if not, how else should I do it?
My Application class looks like this:
public class Test extends Application {
private static Logger logger = LogManager.getRootLogger();
#Override
public void start(Stage primaryStage) throws Exception {
String resourcePath = "/resources/fxml/MainView.fxml";
URL location = getClass().getResource(resourcePath);
FXMLLoader fxmlLoader = new FXMLLoader(location);
Scene scene = new Scene(fxmlLoader.load(), 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The FXMLLoader creates an instance of the corresponding controller (given in the FXML file via fx:controller) by invoking first the default constructor and then the initialize method:
public class MainViewController {
public MainViewController() {
System.out.println("first");
}
#FXML
public void initialize() {
System.out.println("second");
}
}
The output is:
first
second
So, why does the initialize method exist? What is the difference between using a constructor or the initialize method to initialize the controller required things?
Thanks for your suggestions!
In a few words: The constructor is called first, then any #FXML annotated fields are populated, then initialize() is called.
This means the constructor does not have access to #FXML fields referring to components defined in the .fxml file, while initialize() does have access to them.
Quoting from the Introduction to FXML:
[...] the controller can define an initialize() method, which will be called once on an implementing controller when the contents of its associated document have been completely loaded [...] This allows the implementing class to perform any necessary post-processing on the content.
The initialize method is called after all #FXML annotated members have been injected. Suppose you have a table view you want to populate with data:
class MyController {
#FXML
TableView<MyModel> tableView;
public MyController() {
tableView.getItems().addAll(getDataFromSource()); // results in NullPointerException, as tableView is null at this point.
}
#FXML
public void initialize() {
tableView.getItems().addAll(getDataFromSource()); // Perfectly Ok here, as FXMLLoader already populated all #FXML annotated members.
}
}
In Addition to the above answers, there probably should be noted that there is a legacy way to implement the initialization. There is an interface called Initializable from the fxml library.
import javafx.fxml.Initializable;
class MyController implements Initializable {
#FXML private TableView<MyModel> tableView;
#Override
public void initialize(URL location, ResourceBundle resources) {
tableView.getItems().addAll(getDataFromSource());
}
}
Parameters:
location - The location used to resolve relative paths for the root object, or null if the location is not known.
resources - The resources used to localize the root object, or null if the root object was not localized.
And the note of the docs why the simple way of using #FXML public void initialize() works:
NOTE This interface has been superseded by automatic injection of location and resources properties into the controller. FXMLLoader will now automatically call any suitably annotated no-arg initialize() method defined by the controller. It is recommended that the injection approach be used whenever possible.
My Application class looks like this:
public class Test extends Application {
private static Logger logger = LogManager.getRootLogger();
#Override
public void start(Stage primaryStage) throws Exception {
String resourcePath = "/resources/fxml/MainView.fxml";
URL location = getClass().getResource(resourcePath);
FXMLLoader fxmlLoader = new FXMLLoader(location);
Scene scene = new Scene(fxmlLoader.load(), 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The FXMLLoader creates an instance of the corresponding controller (given in the FXML file via fx:controller) by invoking first the default constructor and then the initialize method:
public class MainViewController {
public MainViewController() {
System.out.println("first");
}
#FXML
public void initialize() {
System.out.println("second");
}
}
The output is:
first
second
So, why does the initialize method exist? What is the difference between using a constructor or the initialize method to initialize the controller required things?
Thanks for your suggestions!
In a few words: The constructor is called first, then any #FXML annotated fields are populated, then initialize() is called.
This means the constructor does not have access to #FXML fields referring to components defined in the .fxml file, while initialize() does have access to them.
Quoting from the Introduction to FXML:
[...] the controller can define an initialize() method, which will be called once on an implementing controller when the contents of its associated document have been completely loaded [...] This allows the implementing class to perform any necessary post-processing on the content.
The initialize method is called after all #FXML annotated members have been injected. Suppose you have a table view you want to populate with data:
class MyController {
#FXML
TableView<MyModel> tableView;
public MyController() {
tableView.getItems().addAll(getDataFromSource()); // results in NullPointerException, as tableView is null at this point.
}
#FXML
public void initialize() {
tableView.getItems().addAll(getDataFromSource()); // Perfectly Ok here, as FXMLLoader already populated all #FXML annotated members.
}
}
In Addition to the above answers, there probably should be noted that there is a legacy way to implement the initialization. There is an interface called Initializable from the fxml library.
import javafx.fxml.Initializable;
class MyController implements Initializable {
#FXML private TableView<MyModel> tableView;
#Override
public void initialize(URL location, ResourceBundle resources) {
tableView.getItems().addAll(getDataFromSource());
}
}
Parameters:
location - The location used to resolve relative paths for the root object, or null if the location is not known.
resources - The resources used to localize the root object, or null if the root object was not localized.
And the note of the docs why the simple way of using #FXML public void initialize() works:
NOTE This interface has been superseded by automatic injection of location and resources properties into the controller. FXMLLoader will now automatically call any suitably annotated no-arg initialize() method defined by the controller. It is recommended that the injection approach be used whenever possible.
Given a Play controller MyController with an action myAction, is it possible to call another action without triggering a redirect? Let's say I have another controller:
public class MyController2 extends Controller {
public static void myAction2() throws Exception {
MyController.myAction(); //this will cause a redirect.
}
}
Is it possible to call myAction without triggering a redirect. Note that I am using Play 1.2.x and not Play 2.x.
You can call myAction and not have it redirect. Just change the access level of myAction to anything except public. However, you will not be able to route to myAction directly any more.
If you still need myAction to be routable in it's own right, then I would suggest moving any common functionality into a separate method/class and then calling that method from myAction2 and myAction, like so:
public class Application extends Controller {
public static void myAction() {
commonActionStuff("myAction");
}
public static void myAction2() {
commonActionStuff("myAction2");
}
protected static void commonActionStuff(String whoCalledMe) {
// your common functionality implemented here
renderText(whoCalledMe);
}
}
NOTE: This issue may or may not be Vaadin related, depending on wether there is a "better" solution to "resetting" the bean or not.
Background scenario
I am building a wizard for entering some values that, when finished, is sent to a table (using Vaadin and the add-on "Wizards for Vaadin").
The add-on does not provide a way to reset the Wizard (i.e. go back to step 1) without a forced call to the current steps (overridden) onAdvance() and onBack() methods, which will return false in some of my steps because I'm using logic in those methods in case the use for example haven't filled in all required data.
I cannot simple create a new instance of the Wizard, because I'm using Spring to manage this #Component.
So, this leaves me with actually resetting the bean in order to reset the wizard correctly.
My question is
How do I "reset" a Spring managed Bean (#Component)? I should add that this Bean also has some dependencies injected to it.
or... (for the Vaadin people):
Is there another way of resetting this wizard other than creating a new Wizard?
Some code
#Component
#Scope("session")
public class MyWizard extends Wizard {
#Inject
private MyWizardContainer myWizardContainer;
#Inject
private MyService myService;
#Inject
private MyWizardStep1 myWizardStep1;
#Inject
private MyWizardStep2 myWizardStep2;
#Inject
private MyWizardStep3 myWizardStep3;
#Inject
private MyMainTableContainer myMainTableContainer;
final static Logger logger = LoggerFactory.getLogger(MyWizard.class);
private static final long serialVersionUID = 1L;
public MyWizard() {
setupListener();
}
public void addSteps() {
this.addStep(myWizardStep1);
this.addStep(myWizardStep2);
this.addStep(myWizardStep3);
this.mainLayout.setComponentAlignment(this.footer, Alignment.BOTTOM_LEFT);
}
private void setupListener() {
this.addListener(new WizardProgressListener() {
#Override
public void wizardCompleted(WizardCompletedEvent event) {
endWizard("Wizard Finished Successfully!");
}
#Override
public void wizardCancelled(WizardCancelledEvent event) {
endWizard("Wizard Cancelled!");
}
#Override
public void stepSetChanged(WizardStepSetChangedEvent event) {
// TODO Auto-generated method stub
}
#Override
public void activeStepChanged(WizardStepActivationEvent event) {
// TODO Auto-generated method stub
}
});
}
private void resetWizard() {
myWizardContainer.removeAll(); //here I'm simply resetting all data that the user generated thus far in the wizard
this.activateStep(myWizardStep1); //this will not work, as some steps will not always return true on onBack() and/or onAdvance()
}
private void endWizard(String message) {
resetWizard();
this.setVisible(false);
Notification.show(message);
}
}
SpringVaadinIntegration, that you probably use, does not require all elements to be #Components, only UI has to be annotated.
Your wizard and it's steps should not be components in this case, if you really need to inject dependencies into them you can use #Configurable annotation, which allowes to inject dependencies to classes not managed by Spring (some more configuration needed to make it work). Just create wizard and steps as new objects when you need them.