How would you implement a full screen feature that can be toggled by pressing F11?
You can add an EventHandler to the primaryStage where you specify the functionality like:
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("View.fxml"));
AnchorPane pane = loader.load();
primaryStage.setScene(new Scene(pane, 400, 400));
primaryStage.addEventHandler(KeyEvent.KEY_PRESSED, event -> {
if (KeyCode.F11.equals(event.getCode())) {
primaryStage.setFullScreen(!primaryStage.isFullScreen());
}
});
primaryStage.show();
}
}
Just to be complete:
View.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="stackoverflow.testfullscreen.Controller">
</AnchorPane>
Controller:
public class Controller implements Initializable {
#Override
public void initialize(URL location, ResourceBundle resources) {
}
}
I didn't implement a webview, but it should work with any scene.
Related
Somehow, I cannot add items to my ComboBox variable from another class as it always says either the value of variable is null or the return value of its getter is null.
I use Scene Builder to build Sample.fxml, with controller as Controller class, luanch the whole thing form UserInterface class
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controller">
<center>
<ComboBox fx:id="myBox" prefWidth="150.0" BorderPane.alignment="CENTER" />
</center>
</BorderPane>
Controller
public class Controller {
#FXML
private ComboBox<String> myBox;
public ComboBox<String> getMyBox() {
return myBox;
}
public void initialize() {
ObservableList<String> defaultTicker = FXCollections.observableArrayList("Something");
myBox.getItems().addAll(defaultTicker);
}
}
UserInterface
public class UserInterface extends Application {
#Override
public void start(Stage primaryStage) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("Sample.fxml"));
Parent root = loader.load();
Controller controller = new Controller();
primaryStage.setTitle("Title");
primaryStage.setScene(new Scene(root));
primaryStage.show();
List<String> addStuff = new ArrayList<String>();
addStuff.add("a");
addStuff.add("b");
addStuff.add("c");
controller.getMyBox().getItems().addAll(addStuff);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
After running, the interface appears, with only the option "Something" in it. So I guess it initialize fine?
The interface after launch
What did I do wrong? I couldn't seem to find any solutions so far.
Thanks in advance.
My code:
Main class:
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("sample.fxml"));
Scene scene = new Scene(fxmlLoader.load());
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Base.java
#DefaultProperty("children")
public class Base extends HBox {
public final ObservableList<Node> children;
public final VBox foundation;
public Base() {
foundation = new VBox();
children = foundation.getChildren();
super.getChildren().add(foundation);
}
public final ObservableList<Node> getChildren() {
return children;
}
}
sample.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import sample.Base?>
<?import javafx.scene.control.Button?>
<Base xmlns:fx="gui" fx:controller="sample.Controller">
<children>
<Button text="test"/>
</children>
</Base>
The Scene object in the Main class is not null. Controller.java is empty.
Why doesn't my button show up? Any ideas?
BTW. The stage (window) is being sized like there IS some button, but it is not visible (maybe it's under some node? but how come?)
I'm using OpenJDK & OpenJFX (14.0.1)
Created custom design using FXML with two files CustomToggleSwitch.fxml and CustomToggleSwitch.java.
CustomToggleSwitch.fxml has following code
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.shape.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<fx:root type="Pane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Button mnemonicParsing="false" onAction="#click" text="Button" />
</children>
</fx:root>
CustomToggleSwitch.java has code
package com.custom;
import java.io.IOException;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.Pane;
public class CustomToggleSwitch extends Pane{
int tick;
public CustomToggleSwitch() {
FXMLLoader loader=new FXMLLoader(getClass().getResource("CustomToggleSwitch.fxml"));
loader.setRoot(this);
loader.setController(this);
try {
loader.load();
} catch (IOException e) {
e.printStackTrace();
}
}
#FXML
public void click(ActionEvent actionEvent){
System.out.println(tick++);
}
}
Created jar file from these and used this jar file inside application project. Application has test.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import com.custom.*?>
<?import com.custom.CustomToggleSwitch?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="- Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<CustomToggleSwitch layoutX="29.0" layoutY="48.0" />
</children>
</AnchorPane>
Controller class(TestController.java) has following
public class TestController implements Initializable{
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
}
#FXML
public void click(){
System.out.println("Test");
}
}
Button is shown successfully on GUI and Button click is also get detected.Button is showing 0,1,2,3..etc on output console. But Test is not getting printed on screen.
How can i detect button press in application controller class? Can someone help me to resolve this issue.
Thanks a lot to all.
add listener property with getter and setter in your component
controller.
The example of Jai is correct, but inconsistent with the other components of javafx. For proper implementation, it is appropriate to use properties that can be manipulated in both FXML and manual mode.
This is the user component controller that has an onMyAction property added. This property is used for event notification.
public class CustomToggleSwitch extends Pane {
private ObjectProperty<EventHandler<ActionEvent>> onMyAction = new SimpleObjectProperty<EventHandler<ActionEvent>>();
public CustomToggleSwitch() {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/sample/CustomToggleSwitch.fxml"));
loader.setRoot(this);
loader.setController(this);
try {
loader.load();
}
catch (IOException e) {
e.printStackTrace();
}
}
#FXML
private void initialize() {
}
#FXML
private void click(ActionEvent event) {
if(onMyAction.get() != null) {
onMyAction.get().handle(event);
}
}
public EventHandler<ActionEvent> getOnMyAction() {
return onMyAction.get();
}
public ObjectProperty<EventHandler<ActionEvent>> onMyActionProperty() {
return onMyAction;
}
public void setOnMyAction(EventHandler<ActionEvent> onMyAction) {
this.onMyAction.set(onMyAction);
}
}
With such a structured component, the onMyAction property can be added by FXML for example
<AnchorPane fx:controller="sample.Controller" xmlns:fx="http://javafx.com/fxml" >
<CustomToggleSwitch onMyAction="#testHandler"/>
</AnchorPane>
public class Controller {
#FXML
private void testHandler(ActionEvent event) {
}
}
or manually
<AnchorPane fx:controller="sample.Controller" xmlns:fx="http://javafx.com/fxml" >
<CustomToggleSwitch fx:id="customToggleSwitch"/>
</AnchorPane>
public class Controller {
#FXML
private CustomToggleSwitch customToggleSwitch;
#FXML
private void initialize() {
customToggleSwitch.setOnMyAction(event -> {
});
}
}
Update
You don't need to use a property. Making the getter and setter available should be sufficient to use it from fxml. (I didn't encountered a case where I would add a listerner to a event handler property yet.)
This is a conversion without the use of Property
public class CustomToggleSwitch extends Pane {
private EventHandler<ActionEvent> myEventHandler;
public CustomToggleSwitch() {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/sample/CustomToggleSwitch.fxml"));
loader.setRoot(this);
loader.setController(this);
try {
loader.load();
}
catch (IOException e) {
e.printStackTrace();
}
}
#FXML
private void initialize() {
}
#FXML
private void click(ActionEvent event) {
if(myEventHandler != null) {
myEventHandler.handle(event);
}
}
public EventHandler<ActionEvent> getOnMyAction() {
return myEventHandler;
}
public void setOnMyAction(EventHandler<ActionEvent> onMyAction) {
myEventHandler = onMyAction;
}
}
This is happening because onAction="#click" is declared in CustomToggleSwitch.fxml, so FXMLLoader will look for the click() in CustomToggleSwitch.java.
Adding a click() in TestController class is not going to do anything, because you do not have any node with onAction="#click" in test.fxml.
One way for the Button in CustomToggleSwitch to communicate with TestController class is to relay the event out.
public class CustomToggleSwitch extends Pane {
// Same stuff
private List<Runnable> onClickRunnables = new ArrayList<>();
public final void addButtonOnClickRunnable(Runnable runnable) {
Objects.requireNonNull(runnable);
onClickRunnables.add(runnable);
}
#FXML
private void click(ActionEvent actionEvent){
System.out.println(tick++);
if (!onClickRunnables.isEmpty()) {
onClickRunnables.forEach(r -> r.run());
}
}
}
public class TestController implements Initializable {
// Give CustomToggleSwitch control an fx:id in FXML
#FXML private CustomToggleSwitch customSwitch;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
customSwitch.addButtonOnClickRunnable(this::click);
}
}
Another way is to expose the Button in CustomToggleSwitch out. Personally, I would suggest against this because it's neater to keep implementation of a "control" hidden.
testFX.java :
public class testFX extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
try{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/testFX/view/test.fxml"));
System.out.println("after set location");
//PROBLEM
AnchorPane root = (AnchorPane)loader.load();
System.out.println("Does not happen");
testFXController listController = loader.getController();
listController.start();
Scene scene = new Scene(root, 200, 300);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
catch (Exception ex){
System.out.println("Error");
}
}
public static void main(String[] args) {
launch(args);
}
}
testFXController.java :
package testFX.view;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.ListView;
public class testFXController {
#FXML ListView<String> listView;
private ObservableList<String> obsList;
public void start() {
// create an ObservableList
// from an ArrayList
obsList = FXCollections.observableArrayList("Giants", "Patriots", "Jaguars");
listView.setItems(obsList);
}
}
test.fxml :
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.control.ListView?>
<AnchorPane xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="view.testFXController">
<ListView fx:id="listView"
AnchorPane.topAnchor="10"
AnchorPane.leftAnchor="10"
AnchorPane.rightAnchor="10"
AnchorPane.bottomAnchor="10" />
</AnchorPane>
When I run the testFX.java, the system prints:
after set location
Error
This is the professor's code and I cannot seem to get it running. I realized that the main problem is in the line of code AnchorPane root = (AnchorPane)loader.load(); but I have no idea how to fix this, can someone help?
The value fx:controller attribute is most likely wrong (unless you have a different controller class than the one posted)
The controller you want to use: testFX.view.testFXController
Attribute value in the fxml: view.testFXController != testFX.view.testFXController
Assuming there is no other error that cannot be reproduced with the information in the question, fixing the attribute value should work.
The fx:controller attribute within the fxml file is the culprit here.
fx:controller="application.Controller" worked for me.
Therefore, fx:controller="testFX.view.testFXController" should work for you.
In my Java Fx application I create a two stages. The first stage is the default in the main controller class, HomeController. The second, AddNewEmailController, is created by calling a method, showNewComposeNewEmail(), in the AddNewEmailController class.
The new stage gets created fine, but none of the methods I try to call, like closing the AddNewEmailController stage, will work on the AddNewEmailController stage.
How can I get the methods to work?
I'd also like to have the HomeController stage inaccessible once the AddNewEmailController stage gets open, like how pop-up windows do.
I can't even get the AddNewEmailController stage to iconify?
Thank you all in advance.
The HomeController class:
public class HomeController implements Initializable {
// Initializes the controller class.
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
#FXML
public void windowClose() {
Platform.exit();
}
#FXML
public void showNewComposeNewEmail() throws Exception {
new AddNewEmailController().newnewcomposeNewEmailStage();
}
}
The AddNewEmailController class:
public class AddNewEmailController implements Initializable {
public void setScreenParent(ScreensController screenParent) {
myController = screenParent;
}
// Initializes the controller class.
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
public Stage newComposeNewEmail;
public void newnewcomposeNewEmailStage() throws IOException {
newComposeNewEmail = new Stage();
newComposeNewEmail.initStyle(StageStyle.UNDECORATED);
newComposeNewEmail.initStyle(StageStyle.TRANSPARENT);
Parent newComposeNewEmailRoot = FXMLLoader.load(getClass().getResource("/wakiliproject/Forms/AddNew/NewEmail/NewEmail.fxml"));
StageDraggable.stageDraggable(newComposeNewEmailRoot, newComposeNewEmail);
Scene newComposeNewEmailScene = new Scene(newComposeNewEmailRoot, 590, 670);
newComposeNewEmail.setScene(newComposeNewEmailScene);
newComposeNewEmail.show();
}
#FXML
private void newComposeNewEmailClose() {
newComposeNewEmail.close();
}
#FXML
private void newComposeNewEmailIconify() {
newComposeNewEmail.setIconified(true);
}
}
UPDATE:
The NewEmail FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="wakiliproject.Forms.AddNew.NewEmail.TryEMailController">
<children>
<Label layoutX="190.0" layoutY="61.0" onMouseClicked="#newComposeNewEmailStageIconify" text="Minimise Window" />
<Label layoutX="300.0" layoutY="61.0" onMouseClicked="#newComposeNewEmailStageClose" text="Close Window" />
</children>
</AnchorPane>
In your fxml, your controller is
fx:controller="wakiliproject.Forms.AddNew.NewEmail.TryEMailController"
while in your code, the class name is
AddNewEmailController
Please make them same and recheck, your method will be called.
For making the new Stage as child of the Parent, please use
newStage.initModality(Modality.WINDOW_MODAL);
newStage.initOwner(PrimaryStage);