i am using javafxml and swing in a single program. when i click a button on swing i need a text to be displayed in javafx panel. how to obtain fxml controller's object so that i can use it to update the changes in FX panel? Can any one help to solve this please ? Thanks in advance !
We have tried to access swing from FX where we succeeded. But the other part is not possible.
sample.java :
public void actionPerformed(java.awt.event.ActionEvent e)
{
FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"FXMLDocument.fxml"
)
);
FXMLDocumentController controller =
loader.<FXMLDocumentController>getController();
controller.updatePage("hello boss");
}
FXMLDocument.fxml:
< GridPane fx:controller="com.comp.sweta.FXMLDocumentController" xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
< /HBox>
< Text fx:id="actiontarget" GridPane.columnIndex="1" GridPane.rowIndex="6"/>
< /GridPane>
FXMLDocumentController class:
public class FXMLDocumentController
{
#FXML public Text actiontarget;
public void updatePage(String data){
System.out.println("Testing phase");
this.actiontarget.setText(data);
}
}
we are getting NullPointerException. not able to set text in fxpanel this way.
I think you are missing a line between your first 2 statements in the actionPerformed method:
public void actionPerformed(java.awt.event.ActionEvent e)
{
FXMLLoader loader = ...;
Parent gridpane = (Parent) loader.load();
FXMLDocumentController controller = ....;
controller.updatePage("hello boss");
}
Related
I have multiple tabs and one of them is my console output. I am trying to redirect System.out/err to TextArea loggerPane in that console output Tab using JavaFX. My question is how can I do that in a different thread because while it's outputting I can't navigate to the console tab.
Main App:
public initRootLayout(){
FXMLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource(RootLayout.fxml))
rootLayout = (BorderPane) loader.load();
scene = new Scene (rootLayout);
primaryStage.setScene(scene);
rootLayoutController = loader.getController();
rootLayoutController.setMainApp(this);
primaryStage.show();
}
I included the ConsoleController in RootController where I have all the tabs
#FXML private ConsoleController consoleController
RootLayoutFXML: I included the consoleFXML that uses its own controller
<Tab text="Console">
<content>
fx:include fx:id="myConsolePane" source="console.fxml"
</content>
</Tab>
ConsoleController
public class ConsoleController implements Initializable {
#FXML
private TextArea loggerPane;
public void appendText(String valueOf){
Platform.runLater(()-> loggerPane.appendText(valueOf))
}
#Override
public void initialize (URL ur, ResourceBundle rb){
OutputStream out = new OutputStream(){
#Override
public void write(int b) throws IOException{
appendText(String.valueOf((char)b));
}
};
System.setOut(out, true);
System.setErr(out, true);
}
Background Thread:
It's calling background class that interacts with a Rest API to
preform a function, sometime it outputs a long string as part of
the validation which I want to capture in the console tab.
I have an fxml that describes my gui. I want to change text of the gui and start a task on any key press anywhere.
FXML
<Text fx:id="barcodeText"/>
Controller
#FXML
Text barcodeText;
public void start(Stage primaryStage) throws IOException {
this.primaryStage=primaryStage;
Scene mainScene =new Scene(root);
primaryStage.setScene(mainScene);
primaryStage.setResizable(false);
primaryStage.show();
Parent root = FXMLLoader.load(getClass().getResource("/view/foo.fxml"));
mainScene.addEventHandler(KeyEvent.KEY_PRESSED,new KeyboardEventHandler(){
#Override
public void handle(KeyEvent event) {
barcodeText.setText("foo");
}
});
This gives me a NullPointerException(inside JavaFX Application Thread) for the barcodeText pointer when I fire the event.
Am I doing something wrong?
The examples I looked at were using this approach without fxml, do I have to use an annotation to define the handler? where would I put "onAction" for the scene in the fxml?
(Aside: it looks like you are trying to use the same class for the controller, and for the application. Don't do that.)
Define a method in the controller class for setting the barcode text:
public void setBarcodeText(String barcode) {
barcodeText.setText(barcode);
}
Then call that method from your handler:
FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/foo.fxml"));
Parent root = loader.load();
MyControllerClass controller = loader.getController();
Scene mainScene = new Scene(root);
mainScene.addEventHandler(KeyEvent.KEY_PRESSED, new KeyboardEventHandler(){
#Override
public void handle(KeyEvent event) {
controller.setBarcodeText("foo");
}
});
Obviously, replace MyControllerClass with the actual name of the controller class.
im trying to add some text to a textfield, but when i click the button it shows nullpointerexception , why is this happening?
MainWindowController.java
#FXML
public TextField konsumatoriPunetField = new TextField();
#FXML
private void initialize()
{
FXMLLoader loader5 = new FXMLLoader();
loader5.setLocation(getClass().getResource("ZgjedhKonsumatorinFXML.fxml"));
BorderPane border5 = new BorderPane();
border5 = loader5.load();
Scene scene5 = new Scene(border5);
zgjedhkonsumatorinstage.setScene(scene5);
zgjedhkonsumatorinstage.setTitle("Pit Stop");
zgjedhkonsumatorinstage.initModality(Modality.WINDOW_MODAL);
zgjedhkonsumatorinstage.initOwner(MainFXMLController.mainFXMLStage);
}
#FXML
public void zgjedhKonsumatorin()
{
zgjedhkonsumatorinstage.showAndWait();
}
MainWindowFXML.fxml
<TextField fx:id="konsumatoriPunetField" editable="false" onMouseClicked="#zgjedhKonsumatorin" promptText="Kliko per te zgjedhur" GridPane.columnIndex="1" GridPane.rowIndex="1" />
ZgjedhKonsumatorinController.java
#FXML
public void zgjedhKonsumatorin()
{
FXMLLoader loader = new FXMLLoader(getClass().getResource("MainWindowFXML.fxml"));
MainWindowController c = (MainWindowController) loader.getController();
c.konsumatoriPunetField.textProperty().setValue("ertani");
main.zgjedhkonsumatorinstage.close();
}
ZgjedhKonsumatorinFXML.fxml
<Button mnemonicParsing="false" onAction="#zgjedhKonsumatorin" prefWidth="150.0" text="Zgjedh Konsumatorin" />
Output:
Caused by: java.lang.NullPointerException
at main.ZgjedhKonsumatorinController.zgjedhKonsumatorin(ZgjedhKonsumatorinController.java:193)
... 102 more
p.s. this is the line 193 in ZgjedhKonsumatorinController (exception)
c.konsumatoriPunetField.textProperty().setValue("ertani");
The controller is created by the FXMLLoader when you load the FXML file (the controller class is specified by the FXML file, so this is the only time it could be created). So if you call loader.getController() before calling load(), the value returned will be null. Hence in your code c is null and you get a null pointer exception.
Note that it won't actually help to call loader.load() here. It would fix the null pointer exception, but of course you would load a new instance of the UI defined by the FXML file, and a new instance of the controller. Hence the text field whose text you are setting would not be the text field that is displayed, and nothing would happen.
Since you are using showAndWait() on the window you create, the easiest way to set the text is just to do it back in the MainWindowController, after the showAndWait() call completes. showAndWait() blocks execution until the window is closed, so the text field won't change until the window is closed.
First define a method in ZgjedhKonsumatorinController for retrieving the text:
public class ZgjedhKonsumatorinController {
#FXML
public void zgjedhKonsumatorin()
{
main.zgjedhkonsumatorinstage.close();
}
public String getText() {
// in real life you can get text from the controls in ZgjedhKonsumatorinFXML.fxml
return "ertani" ;
}
}
and now back in MainWindowController you can do:
public class MainWindowController {
#FXML
// Note: it is ALWAYS a mistake to initialize #FXML-injected fields.
// Just declare them and let the FXMLLoader initialize them
// (that is the whole point of #FXML)
private TextField konsumatoriPunetField ;
private ZgjedhKonsumatorinController zgjedhKonsumatorinController ;
#FXML
private void initialize()
{
FXMLLoader loader5 = new FXMLLoader();
loader5.setLocation(getClass().getResource("ZgjedhKonsumatorinFXML.fxml"));
BorderPane border5 = new BorderPane();
border5 = loader5.load();
zgjedhKonsumatorinController = loader.getController();
Scene scene5 = new Scene(border5);
zgjedhkonsumatorinstage.setScene(scene5);
zgjedhkonsumatorinstage.setTitle("Pit Stop");
zgjedhkonsumatorinstage.initModality(Modality.WINDOW_MODAL);
zgjedhkonsumatorinstage.initOwner(MainFXMLController.mainFXMLStage);
}
#FXML
public void zgjedhKonsumatorin()
{
zgjedhkonsumatorinstage.showAndWait();
konsumatoriPunetField.setText(zgjedhKonsumatorinController.getText());
}
}
I am new to JavaFX and trying to create an Confirmation Dialogbox.
I know already that there is no real build in dialogbox in JavaFX so I created one myself like this:
#FXML
public void delBox() {
try {
Stage dialogStage = new Stage();
AnchorPane root = FXMLLoader.load(getClass().getResource("Dialog.fxml"));
Scene scene = new Scene(root);
dialogStage.setScene(scene);
dialogStage.showAndWait();
} catch(Exception e) {
e.printStackTrace();
}
}
It looks pretty good already, but what I dont understand is, how those two Stages can communicate with each other? I want to pass a String to the dialog which is than shown in the message, also when one of the buttons in the dialog window is clicked I wanna react to this in the accordingly.
Can anyone explain me how communication between the stages works?
btw: I use .FXML files and controller classes.
You need a reference to the controller for the dialog. To do this, create an instance of FXMLLoader instead of using the static FXMLLoader.load(URL) method.
For example, suppose you have a class DialogController, so your Dialog.fxml looks like:
<AnchorPane xmlns:fx="..." fx:controller="DialogController.fxml">
...
</AnchorPane>
Then you can access the DialogController in the delBox() method above with
Stage dialogStage = new Stage();
FXMLLoader loader = new FXMLLoader(getClass().getResource("Dialog.fxml"));
AnchorPane root = (AnchorPane)loader.load();
DialogController controller = (DialogController) loader.getController();
Scene scene = new Scene(root);
dialogStage.setScene(scene);
dialogStage.showAndWait();
And now you can communicate between the two controllers. For example, in DialogController you could define a message property, and bind it to a Label :
public class DialogController {
private final StringProperty message = new SimpleStringProperty("");
public void setMessage(String message) {
this.message.set(message);
}
public String getMessage() {
return message.get();
}
public StringProperty messageProperty() {
return message ;
}
#FXML
private Label label ;
public void initialize() {
label.textProperty().bind(message);
// ...
}
}
And then back in your delBox() method:
//... as before:
AnchorPane root = (AnchorPane)loader.load();
DialogController controller = (DialogController) loader.getController();
controller.setMessage("Hello World");
// ...
Similarly, you can define properties which are set when controls are pressed in the dialog itself, and either observe them or query them after the showAndWait() call.
There are a bunch of other similar techniques. Some examples:
https://github.com/james-d/Shared-Data-Controller/tree/master/src
https://github.com/james-d/Dialog-FXML-Example/tree/master/src
https://github.com/james-d/Nested-Controller-Example/tree/master/src/nestedcontrollerexample
<AnchorPane xmlns:fx="..." fx:controller="DialogController.fxml">
...
</AnchorPane>
FX Controller is a java file, so it has to be DialogController and the Controller's path should be included i.e, fx:controller="applicationPackageName.DialogController"
The above mentioned fxml code does not work. It results in
javafx.fxml.LoadException
java.lang.InstantiationException
java.lang.NoSuchMethodException
Reason: The jvm looks for a class constructor with 0 parameters to build an instance. To overcome the error, the controller file needs to be loaded in the function coded in java:
loader.setController(new ControllerName(""));
To sum up (Working code):
FXML file:
<BorderPane id="background" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="240.0" prefWidth="320.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" >
<bottom>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
<children>
<Button onAction="#close" text="OK" />
</children>
</HBox>
</bottom>
<center>
<Label fx:id="messageLabel" />
</center>
</BorderPane>
Controller file:
public class PiPreferenceController {
private final String message ;
#FXML
private Label messageLabel ;
#FXML
void initialize() {
messageLabel.setText(message);
}
public PiPreferenceController(String message) {
this.message = message ;
}
#FXML
public void close() {
messageLabel.getScene().getWindow().hide();
}
}
Function:
void dialogPreferences() throws IOException {
Stage dialogStage = new Stage();
FXMLLoader loader = new FXMLLoader(getClass().getResource(
"PiPreference.fxml"));
loader.setController(new PiPreferenceController(""));
BorderPane root = (BorderPane) loader.load();
Scene scene = new Scene(root);
dialogStage.setScene(scene);
dialogStage.showAndWait();
}
I need to close the current fxml window by code in the controller
I know stage.close() or stage.hide() do this in fx
how to implement this in fxml? I tried
private void on_btnClose_clicked(ActionEvent actionEvent) {
Parent root = FXMLLoader.load(getClass().getResource("currentWindow.fxml"));
Scene scene = new Scene(root);
Stage stage = new Stage();
stage.setScene(scene);
stage.show();
}
but it doesn't work!
All help will be greatly appreciated. Thanks!
give your close button an fx:id, if you haven't yet: <Button fx:id="closeButton" onAction="#closeButtonAction">
In your controller class:
#FXML private javafx.scene.control.Button closeButton;
#FXML
private void closeButtonAction(){
// get a handle to the stage
Stage stage = (Stage) closeButton.getScene().getWindow();
// do what you have to do
stage.close();
}
If you have a window which extends javafx.application.Application; you can use the following method.
(This will close the whole application, not just the window. I misinterpreted the OP, thanks to the commenters for pointing it out).
Platform.exit();
Example:
public class MainGUI extends Application {
.........
Button exitButton = new Button("Exit");
exitButton.setOnAction(new ExitButtonListener());
.........
public class ExitButtonListener implements EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent arg0) {
Platform.exit();
}
}
Edit for the beauty of Java 8:
public class MainGUI extends Application {
.........
Button exitButton = new Button("Exit");
exitButton.setOnAction(actionEvent -> Platform.exit());
}
I implemented this in the following way after receiving a NullPointerException from the accepted answer.
In my FXML:
<Button onMouseClicked="#onMouseClickedCancelBtn" text="Cancel">
In my Controller class:
#FXML public void onMouseClickedCancelBtn(InputEvent e) {
final Node source = (Node) e.getSource();
final Stage stage = (Stage) source.getScene().getWindow();
stage.close();
}
If you don't want to overspread your controller with fxml linked methods you can do something like this:
You have to give it a "fx:id", like "closeButton" for example. Should look like this in your FXML file:
<Button fx:id="closeButton" layoutX="876.0" layoutY="74.0" mnemonicParsing="false" textAlignment="CENTER">
Then you can just code the button in your initialize method or wherever you want:
#FXML
Button closeButton
public initialize(){
closeButton.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent e){
((Stage) closeButton.getScene().getWindow()).close();
}
});
}
I'm not sure if this is the best way (or if it works), but you could try:
private void on_btnClose_clicked(ActionEvent actionEvent) {
Window window = getScene().getWindow();
if (window instanceof Stage){
((Stage) window).close();
}
}
(Assuming your controller is a Node. Otherwise you have to get the node first (getScene() is a method of Node)
I found a nice solution which does not need an event to be triggered:
#FXML
private Button cancelButton;
close(new Event(cancelButton, stage, null));
#FXML
private void close(Event event) {
((Node)(event.getSource())).getScene().getWindow().hide();
}
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
public void handle(WindowEvent we) {
Platform.setImplicitExit(false);
stage.close();
}
});
It is equivalent to hide. So when you are going to open it next time, you just check if the stage object is exited or not. If it is exited, you just show() i.e. (stage.show()) call. Otherwise, you have to start the stage.
finally, I found a solution
Window window = ((Node)(event.getSource())).getScene().getWindow();
if (window instanceof Stage){
((Stage) window).close();
}
Hide doesn't close the window, just put in visible mode.
The best solution was:
#FXML
private void exitButtonOnAction(ActionEvent event){
((Stage)(((Button)event.getSource()).getScene().getWindow())).close();
}