I'm having an issue, I've put an exception around part of my code and it returns
"Caught expection :
/Users/delorszimi/Documents/Documents/Java%20CW/JavaFXbasics/bin/Main.fxml:8"
It seems there's a problem with the anchorPane section in my fxml file that's stopping it from launching. Most of my code is below...
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
public class Main extends Application {
static Stage window = new Stage();
#Override
public void start(Stage window) throws Exception {
try{
window.setTitle("Sprite Editor");
BorderPane pane = new BorderPane();
Scene sc = new Scene(pane,300,300);
Parent content = FXMLLoader.load(getClass().getClassLoader().getResource("Main.fxml"));
pane.setCenter(content);
window.setScene(sc);
window.show();
window.setOnCloseRequest(e -> closeWindow());
}
catch(Exception e){
System.err.println("Caught expection : " + e.getMessage());
}
}
private void closeWindow() {
Boolean decision = ConfirmBox.display("Are you sure you want to exit?", "Title");
if(decision)
window.close();
}
public static void main(String[] args) {
launch(args);
}
}
FXML file
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.canvas.Canvas?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="432.0" prefWidth="498.0"
xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="MainController">
<children>
<Canvas fx:id="Canvas1" height="240.0" layoutX="81.0" layoutY="39.0"
width="308.0" />
</children>
</AnchorPane>
package application;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.ColorPicker;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
public class MainController {
#FXML
public void initialize(){
Button botao = new Button("Browse Files");
Button exit = new Button("Exit");
exit.setOnAction(e -> System.exit(0));
StackPane layout = new StackPane();
layout.getChildren().addAll(botao,exit);
final Canvas canvas1 = new Canvas(500,300);
GraphicsContext gc = canvas1.getGraphicsContext2D();
gc.setStroke(Color.BLACK);
gc.setLineWidth(1);
ColorPicker cp = new ColorPicker();
layout.getChildren().addAll(canvas1,cp);
Scene sc = new Scene(cp);
sc.setOnMousePressed(e->{
gc.beginPath();
gc.lineTo(e.getSceneX(), e.getSceneY());
gc.stroke();
});
sc.setOnMouseDragged(e->{
gc.lineTo(e.getSceneX(), e.getSceneY());
gc.stroke();
});
}
public void size(){
double width,height;
}
public void fileSelection(ActionEvent evento){
}
}
In FXML file you take a AnchorPane but in code section you create a borderpane instance, don't understand this part. And remove getClassLoader() and try once. I am not sure but you can check for once.
Related
I am having a JFXNodeList
<JFXNodesList fx:id="algorithmList" layoutX="285.0" layoutY="215.0" prefHeight="1.0" prefWidth="10.0" />
How can I close (blend the JFXNodeList), from my controller java code, if a user click one button ?
Environment:
JavaFX , Java 8, jfoenix:8.0.3
To close (collapse) JFXNodeList you can use this method:
nodesList.animateList(false);
Complete example:
// src/toumi_jfoenix/Controller.java:
package toumi_jfoenix;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXNodesList;
import javafx.fxml.FXML;
import javafx.scene.control.Tooltip;
public class Controller {
#FXML
public JFXNodesList nodesList;
#FXML
private void initialize() {
JFXButton btnMenu = new JFXButton("Menu");
JFXButton btnOption1 = new JFXButton("Option 1");
JFXButton btnOption2 = new JFXButton("Option 2");
JFXButton btnCollapse = new JFXButton("<<");
btnCollapse.setTooltip(new Tooltip("Collapse menu"));
btnCollapse.setOnAction(e->nodesList.animateList(false));
nodesList.addAnimatedNode(btnMenu);
nodesList.addAnimatedNode(btnOption1);
nodesList.addAnimatedNode(btnOption2);
nodesList.addAnimatedNode(btnCollapse);
}
}
// src/toumi_jfoenix/sample.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.Pane?>
<?import com.jfoenix.controls.JFXNodesList?>
<Pane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="toumi_jfoenix.Controller">
<JFXNodesList fx:id="nodesList" layoutX="20.0" layoutY="10.0" rotate="-90" spacing="50"/>
</Pane>
// src/toumi_jfoenix/Main.java:
package toumi_jfoenix;
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 {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
Scene scene = new Scene(root, 430, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
}
I am trying to create an alert box type window that is like a user registration panel. Now when I close the window using the top-right button (I do not have a cancel/close button implemented) and re-open it there's this error that pops up:
Caused by: java.lang.IllegalStateException: Cannot set modality once stage has been set visible
at javafx.stage.Stage.initModality(Stage.java:525)
at elibraryserver.NewStudentController.initRegister(NewStudentController.java:150)
at elibraryserver.serverController.addStudentButtonAction(serverController.java:71)
... 53 more
I do not understand since I closed the window shouldn't it reset and open another one? What I can see from the error is that it thinks the window is still open. Or am I wrong?
Here is the code for the stage:
public void initRegister() throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("newStudent.fxml"));
Parent root = loader.load();
Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
registerStage.setX((screenBounds.getWidth() - registerStage.getWidth()) / 2);
registerStage.setY((screenBounds.getHeight() - registerStage.getHeight()) / 2);
Scene scene = new Scene(root);
registerStage.setScene(scene);
registerStage.setTitle("Register Student");
registerStage.initModality(Modality.APPLICATION_MODAL);
registerStage.showAndWait();
}
public void addStudentButtonAction(ActionEvent event) throws IOException {
NewStudentController nsc = new NewStudentController();
nsc.initRegister();
}
Not sure what exactly your issue is I think it is because you are not creating a new stage when you initialize your new window
Here is some example code
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
Button button = new Button("Open Test window");
VBox vbox = new VBox();
vbox.getChildren().addAll(button);
Scene scene = new Scene(vbox);
Stage stage = new Stage();
stage.setScene(scene);
stage.show();
button.setOnAction(event -> {
try {
openAction();
} catch (IOException e) {
e.printStackTrace();
}
});
}
private void openAction() throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("Test.fxml"));
Parent root = loader.load();
Stage stage = new Stage();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("Register Student");
stage.initModality(Modality.APPLICATION_MODAL);
stage.show();
}
public static void main(String[] args) { launch(args); }
}
testFXML Controller
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.scene.control.ColorPicker;
import javafx.scene.layout.*;
import javafx.scene.paint.Paint;
import java.net.URL;
import java.util.ResourceBundle;
public class TestFXMLController implements Initializable{
public ColorPicker colorPicker;
public VBox vBox;
#Override
public void initialize(URL location, ResourceBundle resources) {
colorPicker.setOnAction(event -> {
Paint fill = colorPicker.getValue();
BackgroundFill backgroundFill =
new BackgroundFill(fill,
CornerRadii.EMPTY,
Insets.EMPTY);
Background background = new Background(backgroundFill);
vBox.setBackground(background);
});
}
}
Test.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ColorPicker?>
<?import javafx.scene.layout.VBox?>
<VBox fx:id="vBox" alignment="CENTER" prefHeight="300.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="TestFXMLController">
<children>
<ColorPicker fx:id="colorPicker" opacity="0.5" VBox.vgrow="ALWAYS" />
</children>
</VBox>
I have a login stage (300 x 250), I want to open another main stage (fullscreen) if the credentials are correct.
I have figured out how to check the login credentials, but how can I close the login stage and open another stage?
If my application is supposed to work in one window I prefer using a GUI manager singleton class, which manages changing windows. Below I provided the complete code of a simple application which uses this mechanism. Let's assume all the files are in one package, called sample.
Main.java - you initialize the JavaFX components here:
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import java.io.IOException;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("/sample/root.fxml"));
try{
StackPane rootPane;
rootPane = loader.load();
GuiManager guiModel = GuiManager.getInstance();
guiModel.setRootPane(rootPane);
Scene scene = new Scene(rootPane);
primaryStage.setScene(scene);
primaryStage.show();
guiModel.changeWindow("/sample/firstwindow.fxml");
} catch (IOException exception) {
exception.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
root.fxml - all the windows are supposed to be based on it:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.StackPane?>
<StackPane fx:id="rootPane"
xmlns="http://javafx.com/javafx/8.0.60"
xmlns:fx="http://javafx.com/fxml/1"
prefWidth="1" prefHeight="1"/>
firstwindow.fxml - first actual window which will be displayed:
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="sample.FirstWindowController">
<Label text="First window"/>
<Button text="Change window" onAction="#changeWindow"/>
</VBox>
FirstWindowController.java - a controller class of the first window:
package sample;
import javafx.fxml.FXML;
public class FirstWindowController {
#FXML
private void changeWindow() {
GuiManager.getInstance().changeWindow("/sample/secondwindow.fxml");
}
}
secondwindow.fxml - it will be displayed after clicking the button of the first window:
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="sample.SecondWindowController" >
<Label text="Second window"/>
<Button text="Change window" onAction="#changeWindow"/>
</VBox>
SecondWindowController.java - a controller class of the second window:
package sample;
import javafx.fxml.FXML;
public class SecondWindowController {
#FXML
private void changeWindow() {
GuiManager.getInstance().changeWindow("/sample/firstwindow.fxml");
}
}
GuiManager.java - a class that manages changing windows based on the root:
package sample;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.stage.Window;
import java.io.IOException;
public class GuiManager {
private StackPane rootPane;
private static GuiManager instance;
public static GuiManager getInstance() {
if (instance == null) {
instance = new GuiManager();
}
return instance;
}
private GuiManager() {}
public void changeWindow(String path) {
changeWindow(rootPane, path, this);
rootPane.setPrefWidth(-1);
rootPane.setPrefHeight(-1);
}
public static void changeWindow(Pane pane, String newWindowPath, Object callingController) {
Window window = pane.getScene().getWindow();
double x = window.getX() + getHorizontalMidpoint(window);
double y = window.getY() + getVerticalMidpoint(window);
ObservableList<Node> childrenList = pane.getChildren();
removeAllIncludedChildren(childrenList);
FXMLLoader loader = new FXMLLoader(callingController.getClass().getResource(newWindowPath));
try {
pane.getChildren().add(loader.load());
Stage primaryStage = (Stage) window;
primaryStage.setMinHeight(0);
primaryStage.setMinWidth(0);
window.sizeToScene();
window.setX(x - getHorizontalMidpoint(window));
window.setY(y - getVerticalMidpoint(window));
primaryStage.setMinHeight(window.getHeight());
primaryStage.setMinWidth(window.getWidth());
} catch (IOException exception) {
exception.printStackTrace();
}
}
private static double getHorizontalMidpoint(Window window) {
int horizontalBisectionCoefficient = 2;
return window.getWidth() / horizontalBisectionCoefficient;
}
private static double getVerticalMidpoint(Window window) {
int verticalBisectionCoefficient = 2;
return window.getHeight() / verticalBisectionCoefficient;
}
private static void removeAllIncludedChildren(ObservableList<Node> childrenList) {
for (int childIndex = 0; childIndex < childrenList.size(); childIndex++) {
childrenList.remove(childIndex);
}
}
public void setRootPane(StackPane rootPane) {
this.rootPane = rootPane;
}
}
I just run in the same issue and this answer solved my issue perfectly while being short and clean.
#FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
label.setText("Hello World!");
//Here I want to swap the screen!
Stage stageTheEventSourceNodeBelongs = (Stage) ((Node)event.getSource()).getScene().getWindow();
// OR
Stage stageTheLabelBelongs = (Stage) label.getScene().getWindow();
// these two of them return the same stage
// Swap screen
stage.setScene(new Scene(new Pane()));
}
PS.: Remember to click the original answer and upvote it. The guy deserves...
PPS.: I am not sure just copying an answer is okay(instead of just share the link through a comment) but since this doesnt have a correct answer yet i decided to do it for visibility.
Main.class
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
// BorderPane root = new BorderPane();
Parent root = FXMLLoader.load(getClass().getResource("/application/MainWindow.fxml"));
Scene scene = new Scene(root, 400, 400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
package application;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class MainWindowController {
public void buttonAction(ActionEvent event) {
Stage dialog = new Stage();
dialog.initStyle(StageStyle.TRANSPARENT);
Scene scene = new Scene(new Group(new Text(260, 260, "Hello World!")));
// its Just for checking I want add .fxml here how can I do?
dialog.setScene(scene);
dialog.show();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="400.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainWindowController">
<children>
<Button fx:id="bt1" layoutX="154.0" layoutY="188.0" mnemonicParsing="false" onAction="#buttonAction" text="Login" />
</children>
</AnchorPane>
When I am clicking a login button one dialog is open which contain a form.
How I do this? And my dialog contain only close button on title bar, when my dialog is open then I am not doing any action in my main MAinWindow. It just displays without focus. How can I do this?
I am a newbie in JavaFX so I decided to make a simple web browser and it works fine but only with a predefined URL (http://google.com in this example). I did the following: created BrowserTop.fxml (which includes a TextField for URL and a button for getting this URL) and Browser.fxml which includes plain WebView. So, my problem is that I can't understand how can I pass a String URL to WebView (which uses Browser.fxml) by clicking the button in BrowserTop.fxml?
Browser.java
package browser;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class Browser extends Application {
private Stage stage;
private BorderPane rootLayout;
#Override
public void start(Stage stage) throws Exception {
this.stage = stage;
initBrowserTop();
initBrowserMain();
}
public void initBrowserTop() throws IOException{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Browser.class.getResource("BrowserTop.fxml"));
rootLayout = (BorderPane) loader.load();
Scene scene = new Scene(rootLayout);
stage.setScene(scene);
stage.show();
}
public void initBrowserMain() throws IOException{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Browser.class.getResource("Browser.fxml"));
WebView browserWebView = (WebView) loader.load();
WebEngine myWebEngine = browserWebView.getEngine();
myWebEngine.load("http://google.com");
rootLayout.setCenter(browserWebView);
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
BrowserTop.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHe
ight="728.0" prefWidth="1024.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="browser.BrowserTopController">
<top>
<AnchorPane>
<children>
<TextField fx:id="txtURL" layoutX="52.0" prefHeight="25.0" prefWidth="584.0" AnchorPane.leftAnchor="52.0" AnchorPane.rightAnchor="0.0" BorderPane.alignment="CENTER" />
<Button fx:id="btnGo" mnemonicParsing="false" onAction="#handleButtonAction" prefHeight="25.0" prefWidth="53.0" text="Go" AnchorPane.leftAnchor="0.0" />
</children>
</AnchorPane>
</top>
</BorderPane>
BrowserTopController.java
package browser;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TextField;
public class BrowserTopController implements Initializable {
#FXML TextField txtURL;
#FXML
public void handleButtonAction(ActionEvent event){
//something should be here
}
/**
* Initializes the controller class.
* #param url
* #param rb
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
I have actually used the techniques referred above by #James_D before. I made your code work by doing this:
package browser;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class Browser extends Application {
private Stage stage;
private BorderPane rootLayout;
#Override
public void start(Stage stage) throws Exception {
this.stage = stage;
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Browser.class.getResource("BrowserTop.fxml"));
rootLayout = (BorderPane) loader.load();
BrowserTopController browserTopController = (BrowserTopController) loader.getController();
WebView browserWebView = new WebView();
WebEngine myWebEngine = browserWebView.getEngine();
browserTopController.btnGo.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
myWebEngine.load(browserTopController.txtURL.getText());
}
});
rootLayout.setCenter(browserWebView);
Scene scene = new Scene(rootLayout);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
You also have to add
#FXML Button btnGo;
to your fxml document.