How to minimize(iconify) FXML app? - java

How can i assign a handler to minimize(iconify) app to a #FXML private HBox minBtn; (custom button made with Shape) button from Controller's public void initialize(URL, ResourceBundle) method? setIconified(boolean) method is in Stage class and i can't get him in my Controller class.

You can access to the Stage by
minBtn.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent arg0) {
((Stage) ((Node) arg0.getSource()).getScene().getWindow()).setIconified(true);
// OR
((Stage) minBtn.getScene().getWindow()).setIconified(true);
}
});

Related

How to change width of button when application is not fullscreen?

I'm making an application with JavaFX and Scene Builder.
I have Main class and controller that is called from main class.
I have a button in the controller that has width - 45 and height - 90
Toggle button is wrapped in StackPane and StackPane is wrapped in AnchorPane
How can I change buttonPrefWidth to 25 when application is not fullscreen and change button's prefWidth again to 45 when application is fullscreen?
Or can I change prefWidth of a button according to size of application?
Main Class:
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
try {
Parent root =
FXMLLoader.load(getClass().getResource("/card/resources/fxml/card.fxml"));
Scene scene = new Scene(root, 1600, 600);
primaryStage.setScene(scene);
scene.getStylesheets().add(getClass().getResource("style.css")
.toExternalForm());
primaryStage.initStyle(StageStyle.UNDECORATED);
primaryStage.setMaximized(true);
primaryStage.setResizable(true);
primaryStage.getIcons().add(new Image("card/resources/logo-icon.png"));
primaryStage.show();
//adding resize and drag primary stage
ResizeHelper.addResizeListener(primaryStage);
//assign ALT+ENTER to maximize window
final KeyCombination kb = new KeyCodeCombination(KeyCode.ENTER, KeyCombination.CONTROL_DOWN);
scene.addEventHandler(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if (kb.match(event)) {
primaryStage.setMaximized(!primaryStage.isMaximized());
primaryStage.setResizable(true);
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
Controller:
public class Controller implements Initializable {
#FXML private AnchorPane anchorRow;
#FXML private StackPane hBoxCat0;
#FXML private Button btnPalette;
#FXML
public void initialize(URL location, ResourceBundle resources) {
}
}
EDIT:
#Slaw it doesn't work
If you just want to change the prefWidth between two numbers based on whether or not the window is full screen, then you can listen to the fullScreen property of the Stage the Button belongs to.
import javafx.beans.binding.Bindings;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
public class Controller {
#FXML private Button btnPallet;
#FXML
private void initialize() {
btnPallet.prefWidthProperty().bind(
Bindings.when(Bindings.selectBoolean(btnPallet.sceneProperty(), "window", "fullScreen"))
.then(45)
.otherwise(25)
);
}
}
This will give you warnings at first since the Button won't be part of a Scene or Window at this point of the application. While these warnings are annoying the code should still work.

How to send and apply text from label of one Controller to label in other Controller?

I'm making an application with JavaFX and Scene Builder.
I have two controllers:Controller and FontController
I have Main class that launch my program and open Stage with first fontroller (Controller)
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
try {
Parent root = FXMLLoader.load(getClass().getResource("/card/card.fxml"));
Scene scene = new Scene(root, 1600, 600);
primaryStage.setScene(scene);
scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
primaryStage.initStyle(StageStyle.UNDECORATED);
primaryStage.setMaximized(true);
primaryStage.setResizable(true);
primaryStage.getIcons().add(new Image("card/resources/logo-icon.png"));
primaryStage.show();
//adding resize and drag primary stage
ResizeHelper.addResizeListener(primaryStage);
//assign ALT+ENTER to maximize window
final KeyCombination kb = new KeyCodeCombination(KeyCode.ENTER, KeyCombination.CONTROL_DOWN);
scene.addEventHandler(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if (kb.match(event)) {
primaryStage.setMaximized(!primaryStage.isMaximized());
primaryStage.setResizable(true);
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
There is a label and a button in Controller. When I click on the button a method is called and new window with second controller appears(FontController):
#FXML private Button btnFont;
#FXML private Label category1
#FXML
void changeFont(ActionEvent event) {
try {
FXMLLoader fxmlLoader = new
FXMLLoader(getClass().getResource("font.fxml"));
Parent rootFont = (Parent) fxmlLoader.load();
Stage stage = new Stage();
stage.setTitle("Select Font");
stage.setScene(new Scene(rootFont));
stage.show();
} catch (Exception e) {
System.out.println("can't load new window");
}
}
There is the button "OK" and label in FontCOntroller:
#FXML private Label fontLabel;
#FXML private Button btnFontOk;
Please tell me, what should I do to send and apply text from label in FontController when I click on the burtton "OK" to label in Controller?
SOLUTION FOUND:
I created class "Context" in my project directory to make all controllers communicate each other. You can add as many controllers as you want there.
Here it looks like:
package card;
public class Context {
private final static Context instance = new Context();
public static Context getInstance() {
return instance;
}
private Controller controller;
public void setController(Controller controller) {
this.controller=controller;
}
public Controller getController() {
return controller;
}
private FontController fontController;
public void setFontController(FontController fontController) {
this.fontController=fontController;
}
public FontController getFontController() {
return fontController;
}
}
Controller:
I created getters and setters (ALT + Insert in IDEA) for Label that I wanna change
public Label getCategory1() {
return category1;
}
public void setCategory1(Label category1) {
this.category1 = category1;
}
To get FontController variables and methods through Context class I placed line of code
//getting FontController through Context Class
FontController fontCont = Context.getInstance().getFontController();
I registered Controller in Context class through my initialize method (my class implements Initializable)
#FXML
public void initialize(URL location, ResourceBundle resources) {
//register Controller in Context Class
Context.getInstance().setController(this);
}
FontController:
to get Controller variables and methods I placed this code:
//getting Controller variables and methods through Context class
Controller cont = Context.getInstance().getController();
I also registered FontController in Context class through initialize method:
#Override
public void initialize(URL location, ResourceBundle resources) {
//register FontController in Context Class
Context.getInstance().setFontController(this);
}
Method that send text and text color from label in this FontController to label in Controller when I click on button:
#FXML
void applyFont(ActionEvent event) {
cont.getCategory1().setText(fontLabel.getText());
cont.getCategory1().setTextFill(fontLabel.getTextFill());
}
*By creating Context class you can make controllers communicate each other and create as many controllers as you want there. Controllers see variables and methods of each other

JavaFX LoadException while loading FXML file

Every time I ran JavaFX app I encounter the error below.
15:11:52.778 [JavaFX Application Thread] ERROR org.fhl.Manifesto - javafx.fxml.LoadException:
/C:/ManGenFX/target/classes/dataController.fxml
/C:/ManGenFX/target/classes/ManifestoMain.fxml:7
But it only happens if I add the initialize method on Main Controller.
public class MainController{
#FXML
GenerateController genCont;
#FXML
private Pane generatePane;
#FXML
AnchorPane mainFx;
private Node source;
//Other Button, TextFields and Labels declaration
#FXML
private void browseFile(ActionEvent x) {
//Browse file definition
}
#FXML
private void savePath(ActionEvent x) {
//Save file definition
}
//Problem with this method
#FXML
public void initialize() {
System.out.println("Initialize generate controller panel");
logger.info("Initialize generate controller panel");
genCont.init(this);
}
}
If I remove the initialize method on MainController class it will not throw any error but nothing happens either if I click on the generate button which is defined in GenerateController class below.
public class GenerateController {
#FXML
Button btnGenerate;
#FXML
Pane paneGen;
#FXML
public void generateMan(ActionEvent event) {
//generateMan body when Generate button is clicked
}
public void init(MainController mc) {
System.out.println("Init mainControl");
mainControl = mc;
}
public void validate() {
//Definition of method body here
}
}
This is the main Class
public class Man extends Application {
private Stage mainStage;
#Override
public void start(Stage primaryStage) {
this.mainStage = primaryStage;
this.mainStage.setTitle("Manifest");
try{
Parent root = FXMLLoader.load(getClass().getResource("/ManifestoMain.fxml"));
Scene sMain = new Scene(root);
mainStage.setScene(sMain);
mainStage.show();
}catch(IOException ioE) {
logger.error(ioE);
}
}
public static void main(String[] args) {
launch(args);
}
}
Also, I placed my dataController.fxml, ManifestoMain.fxml, and generateView.fxml under resources folder but it don't have any problem accessing the files. Appreciate help on this.

Null FXML variables

I have an application in JavaFX FXML by using Model View Controller. I want to move some sliders with keyboard. To do this in the main class I put a KeyEvent to hear what happens on the keyboard. In the controller class FXMLDocumentController where are FXML variables. These variables are passed to a third class. Where there sliders are changed when you click any.
The problem is that when I pass the variables of the sliders in the third class are perfectly stored but when you run the code to modify sliders coming past the main class when clicked are FXML variables are null.
Here you have the code:
Main class:
public class OpenPilot extends Application {
Movements Movements = new Movements();
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent Key) {
Movements.GetKeys(Key);
}
});
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Controller:
public class FXMLDocumentController implements Initializable {
Movements Movements = new Movements();
#FXML public Slider SpeedSlider;
#FXML public Slider TurnsSlider;
#Override
public void initialize(URL url, ResourceBundle rb) {
//Send GUI Information
Movements.GetSliders(SpeedSlider, TurnsSlider);
}
}
Movements:
public class Movements {
//Define Data Variables
public double SpeedValue;
public double TurnsValue;
//Define GUI Variables
private Slider SpeedSlider;
private Slider TurnsSlider;
public void GetSliders(Slider SpeedSlider, Slider TurnsSlider) {
this.SpeedSlider = SpeedSlider;
this.TurnsSlider = TurnsSlider;
}
//Get Sliders
public void GetKeys(KeyEvent Key) {
System.out.println(Key.getCode());
System.out.println(SpeedSlider);
Platform.runLater(new Runnable() {
#Override public void run() {
TurnsSlider.setValue(10);
}
});
}
}
You use 2 different instances of the Movements class (Movements Movements = new Movements(); in OpenPilot and FXMLDocumentController). Since you don't use static fields / methods, you won't get any data from one instance to the other. You have to get the Movements object from the controller:
Controller:
public class FXMLDocumentController implements Initializable {
Movements movements = new Movements();
public Movements getMovements() {
return movements;
}
#FXML public Slider SpeedSlider;
#FXML public Slider TurnsSlider;
#Override
public void initialize(URL url, ResourceBundle rb) {
//Send GUI Information
movements.GetSliders(SpeedSlider, TurnsSlider);
}
}
Use a instance of the FXMLLoader instead of the static method to get the Movements field from the controller:
Main class:
public class OpenPilot extends Application {
Movements movements;
#Override
public void start(Stage stage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader();
// use non-static load method here
Parent root = fxmlLoader.load(getClass().getResource("FXMLDocument.fxml").openStream());
// get movements from via controller
FXMLDocumentController controller = fxmlLoader.<FXMLDocumentController>getController();
movements = controller.getMovements();
Scene scene = new Scene(root);
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent Key) {
movements.GetKeys(Key);
}
});
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}

close fxml window by code, javafx

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

Categories

Resources