I have 3 fxml files:
Main.fxml
Menu.fxml
Manager.fxml
and controller for each.
I need to controll BorderPane center of Main.fxmlfrom both remaining, so I fx:include'd them, gave them fx:id and also set included element Manager.fxml visible = false (only menu button set Manager to center of BorderPane ) but now I'am lost and dont understand how to set included fxml visible when button in Menu.fxmlis pressed. Easy when its about simple element but dont work same with included fxml file.
At the beginning I had only menu inlcuded in Main.fxml and method setCenter in its controller that i used to switch center element using MenuController.java but then i couldn't find way to set main center using manager (so manager could be swithched with other one) becouse FXMLloader only loaded Main and Menu so couldnt set proper MainController instance in ManagerController.
My code before change:
public class MainAdminController {
#FXML
private AdminMenuController adminMenuController;
#FXML
private BorderPane adminBorderPane;
#FXML
public void initialize(){
adminMenuController.setMainController(this);
}
public void setView(String fxmlPatch){
adminBorderPane.setCenter(Fxml.loadFXML(fxmlPatch));
}
}
AdminMenuController
public class AdminMenuController {
public static final String MANAGE_ACCOUNTS = "/fxml/admin/ManageAccounts.fxml";
public static final String MANAGE_ADMINS = "/fxml/admin/ManageAdmins.fxml";
public static final String CHANGE_PASSWORD = "/fxml/ChangePassword.fxml";
#FXML
private MainAdminController mainAdminController;
public void setMainController(MainAdminController mainAdminController) {
this.mainAdminController = mainAdminController;
}
#FXML
private ToggleGroup adminButtons;
#FXML
public void viewManageAccounts() {
mainAdminController.setView(MANAGE_ACCOUNTS);
}
#FXML
public void viewManageAdmins() {
mainAdminController.setView(MANAGE_ADMINS);
}
#FXML
public void viewChangePassword() {
mainAdminController.setView(CHANGE_PASSWORD);
}
}
Related
public class ProjectxController implements Initializable {
#FXML
private AnchorPane LandingPane;
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
#FXML
private void onLoad(ActionEvent event) throws IOException{
pane = FXMLLoader.load(getClass().getResource("connectedPage.fxml"));
LandingPane.getChildren().setAll(pane);
}
Note: Having two fxml files Frontpage.fxml and ConnectedPage.fxml with one controller projectxController i.e coded above
Frontpage.fxml has one button that will load connectedPage.fxml.
Connectedpage.fxml has one label
Now I want to set the Label text after connectedpage.fxml is loaded
public class ProjectX extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FrontPage.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setResizable(false);
stage.show();
}
When you create you fxml document you have to give a unique id for you Label:
The same you have done for the AnchorPane.
Example
#FXML
private Label myLabel;
Then inside the initialize method of your fxml controller class you can modify it as you want.
If you problem is how to access the Label from another controller you can use a get method or pass an instance of the controller you need . All that after the fxml has successfully loaded .
I recommend also that you use different controllers for different fxml files , cause it is more clear .
Have a search on fxml loading techniques and how to connect different controllers over the web and you will find what you need .
i'm trying to add an ActionListener to a label whitch pop out whenever user types wrong password or login.
Here is my Login Controller
public class LoginController implements Initializable {
#FXML
private Label label;
#FXML
private TextField LoginField;
#FXML
private PasswordField PasswdField;
#FXML
private Button LogInButton;
#FXML
private Label IncorrectDataLabel;
//private String uri = "http://google.com";
#FXML
private void LogIn(ActionEvent event) throws IOException {
if(LoginField.getText().equals("MKARK")&&PasswdField.getText().equals("KACZOR1"))
{
Parent parent = FXMLLoader.load(getClass().getResource("/fxmlFiles/MainScreen.fxml"));
Scene MainScene = new Scene(parent);
Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
stage.setScene(MainScene);
stage.show();
}
else
{
IncorrectDataLabel.setVisible(true);
// <------------------- Here I want to bind hyperlink to a label with would open the google site, whenever user clicks it.
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
How am i able to fix that issue? I've tried many times (setOnAction, addMouseListener) but nothing worked :(.
If You dont mind i would also ask about the public void initialize function. What is it for? It pop out automatically when i created the class.
Thanks in advance
Labels do not fire action events. You could use a listener for mouse clicked events, e.g:
#FXML
private void gotoGoogle() {
// open url etc
}
and in the FXML file
<Label fx:id="IncorrectDataLabel" onMouseClicked="#gotoGoogle" ... />
However, it probably makes more sense to use a Hyperlink for this, which would give the user better visual feedback that it was something on which they were expected to click. Just replace the label with
<Hyperlink fx:id="IncorrectDataLabel" onAction="#gotoGoogle" text="..." ... />
and update the type in the controller accordingly:
#FXML
private Hyperlink IncorrectDataLabel ;
You need the appropriate import for javafx.control.Hyperlink in both the FXML file and in the controller.
Off-topic note: use proper Java naming conventions for your variable and method names.
I am creating tabs dinamically and i am using the same fxml file for all of them. So, all type of controls that I've included has de same "fx:id". I use this: "#FXML TextField textField". How could I use the TextField of the second tab, the TextField of the first tab, etc?
#Controller
public class MascotaTabControllerImpl implements MascotaTabController
{
private AnchorPane anchorPane;
private Tab tab;
private Mascota mascota;
#FXML
private ComboBox<String> comboMascota;
#FXML
private ComboBox<String> comboTamano;
#FXML
private TextField fieldNombreMascota;
#FXML
private RadioButton radioAlergiaSi;
#FXML
private RadioButton radioAlergiaNo;
#FXML
private TextField fieldRaza;
#FXML
private TextField fieldPeso;
#FXML
private ComboBox<String> comboSexo;
#FXML
private ComboBox<String> comboAgresividad;
#FXML
private TextArea areaObservaciones;
#FXML
private Button buttonEditar;
#FXML
private Button buttonCancelar;
#Override
public void inicializacionFxmlFile(TabPane tabPane, Collection<Mascota> mascotas)
{
try
{
for(Mascota mascota : mascotas)
{
anchorPane = new AnchorPane();
FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/mascotaTab.fxml"));
loader.setController(this);
anchorPane.getChildren().setAll(loader.load());
tab = new Tab();
tab.setContent(anchorPane);
tabPane.getTabs().add(tab);
tab.setText(mascota.getNombre());
fieldNombreMascota.setText(mascota.getNombre());
fieldRaza.setText(mascota.getRaza());
comboSexo.setValue(mascota.getSexo());
fieldPeso.setText(String.valueOf(mascota.getPeso()));
comboTamano.setValue(mascota.getTamano());
comboAgresividad.setValue(mascota.getAgresividad());
areaObservaciones.setText(mascota.getObservaciones());
mascota.setNombre(fieldNombreMascota.getText());
}
tabSelected(tabPane, mascotas);
buttonEditar.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent event)
{
mascota.setNombre(fieldNombreMascota.getText());
mascota.setRaza(fieldRaza.getText());
mascota.setSexo(comboSexo.getValue());
mascota.setPeso(Float.parseFloat(fieldPeso.getText()));
mascota.setTamano(comboTamano.getValue());
mascota.setAgresividad(comboAgresividad.getValue());
mascota.setObservaciones(areaObservaciones.getText());
clienteService.actualizarMascota(mascota);;
}
});
buttonCancelar.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent event)
{
return;
}
});
}
catch(IOException ioe)
{
System.out.println(ioe.getMessage());
}
}
Edit: imagine "for" statement runs twice. How could call controls (TextFields, ComboBoxes, etc.) of the first tab?
For example, when "for" statement runs the first time "fieldNombreMascota" reference is "id=110" but when "for" statement runs the second time, the same TextField reference is "id=113". So how can I call them with annotation #FXML?
Because you call
loader.setController(this);
inside your loop, every time you call loader.load() you will reuse the same object as the controller for the FXML you are loading. This means each time you go through that for loop, the #FXML-injected fields will get redefined. So by doing this, you essentially make it impossible to access any FXML fields except the ones from the last iteration of the loop.
You must not call loader.setController(this). The "standard" way to combine FXML files and controllers is to use an fx:controller attribute in the root element of the FXML file, specifying a class name. This will cause the FXMLLoader to create a new instance of that class every time you call loader.load(). If there is some other problem you are trying to solve by attempting the non-standard way you are doing things, then the solution you are attempting is not the right approach.
If you organize your code well, the FXML creates a controller instance, and there should be no need whatsoever to access that controller externally. You may need some of your controllers to access a shared data model of some kind, but this is certainly not the right approach to achieve that.
This question already has an answer here:
javafx 8 compatibility issues - FXML static fields
(1 answer)
Closed 8 years ago.
I'm introducing in javafx and i found it very interesting. But I have got a problem that i can't solve.
In the simplest case of a Hello World I can't put a #FXML public static var like this:
public class FXMLDocumentController implements Initializable
{
#FXML
public static Label label;
#FXML
private void handleButtonAction(ActionEvent event)
{
System.out.println("You clicked me!");
label.setText("Hello World!");
}
}
If I change it to private it works.
The cause of that I want to made this vars publics is because I'm using diferents controllers for diferents views (in my real app) and i want to communicate between theirs.
PS: Sorry for my bad english
You should not use a static field here. Your controller belongs to one view and every time the view is created by the FXML Loader new instances of all nodes in the view will be created. SO by calling the FXML Loader 2 times you will receive 2 instances of the view. In addition a new instance of your controller class will be created whenever you load the view by using the FXML viewer. By using a static field you will override values of old controller instances and this will end in horrible bugs. Here is a short introduction to the static keyword: What does the 'static' keyword do in a class?
If you just remove "static" it will work.
Instead of using public fields you should add getter and setter methods to your controller class and mark the field as private: Why use getters and setters?
I want to do something similar like this:
I'm working with tabs and i have this two controllers:
FXML_Tab1Controller.java:
public class FXML_Tab1Controller implements Initializable {
FXML_Tab2Controller tab2controller;
#FXML public Label Label1;
#FXML public TextField TextField1;
#FXML public Button Button1;
/**
* Initializes the controller class.
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
#FXML private void actionButton1(ActionEvent event)
{
Label1.setText(tab2controller.TextField2.getText());
}
}
FXML_Tab2Controller.java:
public class FXML_Tab2Controller implements Initializable {
FXML_Tab1Controller tab1controller;
#FXML public Label Label2;
#FXML public TextField TextField2;
#FXML public Button Button2;
/**
* Initializes the controller class.
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
#FXML private void actionButton2(ActionEvent event){
Label2.setText(tab1controller.TextField1.getText());
}
}
something similar like that video:
https://www.youtube.com/watch?v=XLVx46ycxco
I have a borderpane where I'm loading an fxml (alias FirstPanel) with relative controller inside of it and positioned in the center. The fxml contains a TableView and a button which should load another fxml (alias SecondPanel) and relative controller instead the first panel. Basically, the SecondPanel needs to show some details about the data selected in the table.
Is it possible to do it? How can I get the parent of my FirstPanel and use it for the SecondPanel instead of the first?
UPDATE
I've tried many solutions but without reach my goal. The application load the UsersMainPageController which contains only an AnchorPane like parent control, so this is the relative code:
[UsersMainPageController]
public class UsersMainPageController implements Initializable {
private PostOffice application;
#FXML
private AnchorPane ParentControl;
public void setApp(PostOffice application){
this.application = application;
}
public void loadPage(String pageName) {
try {
URL url = getClass().getResource(pageName);
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(url);
fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
AnchorPane page = (AnchorPane) fxmlLoader.load(url.openStream());
ParentControl.getChildren().clear();///name of pane where you want to put the fxml.
ParentControl.getChildren().add(page);
}
catch (IOException e) {
e.printStackTrace();
}
}
public void loadManageUsers () {
loadPage("UsersManage.fxml");
}
public void loadListUsers () {
loadPage("UsersList.fxml");
}
/**
* Initializes the controller class.
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
loadListUsers();
}
}
loadListUsers calls UsersList.fxml with the relative controller UsersListController that contains a TableView with some records and some buttons. When I click a specific button, it should call loadManageUsers with relative controller UsersManageController which contains some fields for editing data and inserting new users. When users are edited or inserted, it should be able to return to the previous page with the TableView and clear the current page (in this case UsersManageController).
[UsersListController]
public class UsersListController implements Initializable {
private UsersMainPageController mainController;
#FXML
private void handleButtonEditAction(ActionEvent event) throws IOException {
mainController.loadManageUsers();
}
}
[UsersManageController]
public class UsersManageController implements Initializable {
private UsersMainPageController mainController;
#FXML
private void handleButtonBackAction(ActionEvent event) throws IOException {
mainController.loadListUsers();
}
}
When I click from the UsersListController the ButtonEdit to load the UsersManageController, I get this error:
Caused by: java.lang.NullPointerException
at postoffice.multiuser.UsersListController.handleButtonAggiornaAction(UsersListController.java:210)
... 50 more
you can add your child fxml into parent controller..
1.first just take a anchor pane and set its bounds where you want to put your FXML code.
now try this...
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
openNewWindow("Example.fxml");
}
});
you can pass fxml name into function...
public void openNewWindow(String FXMLFile)
{
//ChildNode child;
try {
URL url = getClass().getResource(FXMLFile);
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(url);
fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
AnchorPane page = (AnchorPane) fxmlLoader.load(url.openStream());
anchor.getChildren().clear();///name of pane where you want to put the fxml.
anchor.getChildren().add(page);
}
catch (IOException e) {
e.printStackTrace();
}
}