i used scene builder to generate a layout, after exporting the fxml i imported into TextPad, the layout was sucessefuly imported however i cant handle the items by the id(if thats how it works). my question is how do handle the items that i added.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.fxml.FXMLLoader;
public class test2fx extends Application{
public static void main(String[] args){
Application.launch(args);
}
public void init(){
}
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("fxlayout.fxml"));
Scene scene = new Scene(root, 300, 275);
stage.setTitle("FXML Welcome");
stage.setScene(scene);
stage.show();
}
public void stop(){
System.exit(0);
}
fxml file content:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.Pane?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="284.0" prefWidth="314.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Button layoutX="31.0" layoutY="252.0" mnemonicParsing="false" prefHeight="25.0" prefWidth="50.0" text="Jogar" />
<Button layoutX="124.0" layoutY="252.0" mnemonicParsing="false" prefHeight="25.0" prefWidth="50.0" text="Novo" />
<Button layoutX="219.0" layoutY="252.0" mnemonicParsing="false" prefHeight="25.0" prefWidth="50.0" text="Sair" />
<TextField id="tf1" disable="true" layoutX="150.0" layoutY="60.0" />
<TextField id="tf1" disable="true" layoutX="150.0" layoutY="100.0" />
<TextField id="tf3" layoutX="150.0" layoutY="140.0" />
<TextField id="tf4" disable="true" layoutX="150.0" layoutY="180.0" />
<Label id="lb1" layoutX="38.0" layoutY="60.0" prefHeight="22.0" prefWidth="59.0" text="Inicio" />
<Label id="lb2" layoutX="38.0" layoutY="100.0" prefHeight="22.0" prefWidth="59.0" text="Fim" />
<Label id="lb3" layoutX="38.0" layoutY="139.0" prefHeight="22.0" prefWidth="59.0" text="Palpite" />
<Label id="lb4" layoutX="38.0" layoutY="180.0" prefHeight="22.0" prefWidth="59.0" text="Inicio" />
</children>
</Pane>
As #James_D said you most likely want:
A reference to the element in your FXMl you wish to access.
A controller class for your FXML.
Example:
/*
* Dean2191 Stackoverflow example
*/
package javafxapplication6;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
/**
*
* #author dean2191
*/
public class FXMLDocumentController implements Initializable {
#FXML
private Label label;
#FXML
private TextField tf1; // value will be injected by the FXMLLoader
#FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
label.setText("Hello World!");
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
Check the oracle examples here and also note that the netbeans IDE generates a default controller class as shown above however when a new element is added in scene builder you should add each #FXML annotation to the variable you wish to access and scene builder/netbeans have synchronization features to view which elements are referenced from your code.
Synchronizing With the Controller Source Code The NetBeans IDE's Make
Controller feature allows you to synchronize the modifications you
make in the FXML file that is currently opened in Scene Builder and
the controller source code opened in NetBeans IDE. To illustrate this
feature, do the following:
In Scene Builder, drag a Button control from the Library panel to the
Control panel. In the Code panel, assign a new value for the new
button's fx:id field and a new method name for the onAction method.
Select File in the main menu and then Save. In NetBeans IDE 7.4 or
later, right click the project node for the FXML file that you just
edited and select Edit from the contextual menu. From the main menu,
select Source and then Make Controller. The #FXML private variable and
the new onAction method for the button you just added in Scene Builder
are created in the controller source file. Use the Make Controller
command if you delete an element in the Control panel or update an
fx:id value or a method name in Scene Builder.
Source
Also note you should check in your FXMl for this line:
fx:controller="yourNamespace.fxlayout"
As your controller class must be specified somewhere in the FXML. Your controller will then be called something like fxlayout.java in your example code. This can be set/modified using scene builder too:
Related
I have a simple JavaFX application with main controller. In this main controller I dynamically add this component :
Added component:
FXML code of this component (paramValue.fxml) :
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.HBox?>
<HBox alignment="CENTER" prefHeight="40.0" prefWidth="833.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.demoSpreadsSheet.ParamValueController">
<children>
<Label prefHeight="95.0" prefWidth="83.0" text="Paramètre : " />
<TextField fx:id="paramName" prefHeight="32.0" prefWidth="300.0" />
<Label prefHeight="95.0" prefWidth="83.0" text="Valeur : ">
<HBox.margin>
<Insets left="40.0" />
</HBox.margin>
</Label>
<TextField fx:id="paramValue" prefHeight="32.0" prefWidth="300.0" />
<Button mnemonicParsing="false" prefHeight="25.0" prefWidth="12.0">
<HBox.margin>
<Insets left="20.0" />
</HBox.margin>
<graphic>
<ImageView fitHeight="26.0" fitWidth="21.0" onMouseClicked="#openSpreadSheet" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="#../../Images/spreadsheet.png" />
</image>
</ImageView>
</graphic>
</Button>
<Button mnemonicParsing="false" onAction="#removeParamValue" prefHeight="25.0" prefWidth="12.0">
<graphic>
<ImageView fitHeight="26.0" fitWidth="21.0" onMouseClicked="#openSpreadSheet" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="#../../Images/remove.png" />
</image>
</ImageView>
</graphic>
<HBox.margin>
<Insets left="10.0" />
</HBox.margin>
</Button>
</children>
</HBox>
Controller of the component :
package com.example.demoSpreadsSheet;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
public class ParamValueController extends HBox {
#FXML TextField paramName, paramValue;
public ParamValueController() {}
#FXML
public void openSpreadSheet(){
}
#FXML
private void removeParamValue(){
//I don't know if it's possible to remove it here
}
}
The controller where I add my custom component :
package com.example.demoSpreadsSheet;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import java.io.IOException;
public class DoublonController extends BorderPane {
#FXML VBox paramValueList;
public DoublonController(){}
#FXML
public void initialize() throws IOException {
paramValueList.getChildren().addAll(createParamValueComponent(), createParamValueComponent());
}
private HBox createParamValueComponent() throws IOException {
FXMLLoader paramValueLoader = new FXMLLoader(DoublonController.class.getResource("paramValue.fxml"));
return paramValueLoader.load();
}
#FXML
private void addParamValue() throws IOException {
this.paramValueList.getChildren().add(createParamValueComponent());
}
}
I want to remove this component when the user click on the red cross. The problem is that the redcross calls the function "removeParamValue()" within the class that I want to remove which i think is impossible..
Do you have a workaround ?
Thanks in advance.
There are at least two approaches you can use.
Get the Parent
As mentioned by #kleopatra in a question comment, you can get the parent of the root FXML node from within the "child" controller, check if it is an instance of Pane and, if it is, then modify the parent's children list.
For example:
#FXML
private void removeParamValue() {
var parent = container.getParent();
if (parent instanceof Pane pane) {
pane.getChildren().remove(container);
}
}
This requires you to inject the root FXML element into the controller. I made the name of the field container, whose type would be HBox, but you can name it anything you'd like (just make sure add the corresponding fx:id attribute to the FXML file). I also made use of pattern matching for instanceof, which was finalized in Java 16. If you are not using at least Java 16, then you'll need to manually cast parent to a Pane.
Problem With Your Code
Note you can't use this.getParent(), because the controller itself has never been added to the scene graph. In fact, with how your code is currently written, your controller class should not be extending HBox at all (and I assume a similar problem with your other controller class). Perhaps you meant to use fx:root, but that would involve changing both the root element of your FXML file and how you load the FXML file. Read the linked documentation for more information.
In other words, unless you want to use fx:root, remove the extends HBox and extends BorderPane from your controller classes.
Use a "Callback"
The other approach is to use a callback. Add a method to your ParamValueController which accepts some functional interface (e.g., Runnable):
public void setOnRemove(Runnable action) {
// also declare a field to store the Runnable in
this.action = action;
}
Then your "remove param value" method would look like:
#FXML
private void removeParamValue() {
if (action != null) {
action.run();
}
}
And you'd modify the code that loads the "child" FXML like so:
private HBox createParamValueComponent() throws IOException {
FXMLLoader paramValueLoader = new FXMLLoader(DoublonController.class.getResource("paramValue.fxml"));
HBox root = paramValueLoader.load();
// invoked *after* you load the FXML file
ParamValueController controller = paramValueLoader.getController();
controller.setOnRemove(() -> paramValueList.getChildren().remove(root));
return root;
}
Personally, I prefer this approach as it's safer, more flexible, and in my opinion clearer. But it is also more work than the first approach.
I have tried researching various pages regarding how to switch scenes or even stages with no luck to help my specific case. I am trying to create a program with a login form that manages a school library.
I have a login form that authenticates the user input with the method validateLogin(). If the login is successful (i.e. isLoginSuccess = true), I want my program to close primaryStage and open a new stage/window with the library management system.
Is it better to switch the scene on primaryStage or close primaryStage and open a new stage? How do you do that and should you do that from Main.java or is it fine to do it from LoginController.java? I'm having trouble switching scenes or even just creating a new stage from LoginController.java since primaryStage isn't recognized in that class.
Main.java
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class Main extends Application
{
#Override
public void start(Stage primaryStage) throws Exception
{
Parent root = FXMLLoader.load(getClass().getResource("login.fxml"));
primaryStage.initStyle(StageStyle.UNDECORATED);
primaryStage.setScene(new Scene(root, 520, 400));
primaryStage.setResizable(false);
primaryStage.show();
}
//main() method is ignored in correctly deployed JavaFX application.
public static void main(String[] args)
{
launch(args);
}
}
LoginController.java
package sample;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.event.ActionEvent;
import javafx.stage.StageStyle;
import java.io.File;
import java.util.ResourceBundle;
//Can be removed, StackOverflow import
import java.io.BufferedReader;
import java.io.FileReader;
import java.net.URL;
public class LoginController implements Initializable
{
#FXML
private Button cancelButton;
#FXML
private Label loginMessageLabel;
#FXML
private ImageView brandingImageView;
#FXML
private ImageView lockImageView;
#FXML
private TextField usernameTextField;
#FXML
private PasswordField enterPasswordField;
#Override
public void initialize(URL url, ResourceBundle resourceBundle)
{
File brandingFile = new File("Images/LibManager.png");
Image brandingImage = new Image(brandingFile.toURI().toString());
brandingImageView.setImage(brandingImage);
File lockFile = new File("Images/LoginLock.png");
Image lockImage = new Image(lockFile.toURI().toString());
lockImageView.setImage(lockImage);
}
//Activates validateLogin() if there is input in text fields.
public void loginButtonOnAction(ActionEvent event)
{
if (usernameTextField.getText().isBlank() == false && enterPasswordField.getText().isBlank() == false)
{
validateLogin();
}
else
{
loginMessageLabel.setText("Please enter username and password");
}
}
//Closes login window.
public void cancelButtonOnAction(ActionEvent event)
{
Stage stage = (Stage) cancelButton.getScene().getWindow();
stage.close();
}
//Compares user input to txt file contents to authenticate.
public void validateLogin() {
{
try {
String location = "userdatabase.txt";
String username = usernameTextField.getText();
String password = enterPasswordField.getText();
FileReader fr = new FileReader(location);
BufferedReader br = new BufferedReader(fr);
String line, user, pass;
boolean isLoginSuccess = false;
while ((line = br.readLine()) != null) {
user = line.split(" ")[1].toLowerCase();
pass = line.split(" ")[2].toLowerCase();
if (user.equals(usernameTextField.getText()) && pass.equals(enterPasswordField.getText())) {
isLoginSuccess = true;
break;
}
}
if (!isLoginSuccess)
{
/*
public void startLibManager(Stage primaryStage) {
FXMLLoader loader = new FXMLLoader(getClass().getResource("LibDatabase.fxml"));
Parent mainCallWindowFXML = loader.load();
secondaryStage.initStyle(StageStyle.UNDECORATED);
secondaryStage.setScene(new Scene(root, 520, 400));
secondaryStage.setResizable(false);
secondaryStage.show();
}
*/
/*
//use one of the components on your scene to get a reference to your scene object.
Stage stage = (Stage)tfCallerName.getScene.getWindow();//or use any other component in your controller
Scene mainCallWindow = new Scene (mainCallWindowFXML, 800, 600);
stage.setScene(newCallDetails);
stage.show(); //this line may be unnecessary since you are using the same stage.
*/
}
fr.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
login.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.PasswordField?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="520.0" style="-fx-background-color: #FFFFFF;" xmlns="http://javafx.com/javafx/15.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.LoginController">
<left>
<AnchorPane prefHeight="407.0" prefWidth="227.0" BorderPane.alignment="CENTER">
<children>
<ImageView fx:id="brandingImageView" fitHeight="400.0" fitWidth="226.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="#../../Images/LibManager.png" />
</image>
</ImageView>
</children></AnchorPane>
</left>
<right>
<AnchorPane prefHeight="400.0" prefWidth="332.0" style="-fx-background-color: FFFFFF;" BorderPane.alignment="CENTER">
<children>
<ImageView fx:id="lockImageView" fitHeight="32.0" fitWidth="46.0" layoutX="134.0" layoutY="65.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="#../../Images/LoginLock.png" />
</image>
</ImageView>
<Label layoutX="23.0" layoutY="157.0" prefHeight="17.0" prefWidth="60.0" text="Username" textFill="#01989e" />
<TextField fx:id="usernameTextField" layoutX="96.0" layoutY="152.0" prefWidth="173.0" promptText="Username" />
<Label layoutX="26.0" layoutY="205.0" text="Password" textFill="#01989e" />
<PasswordField fx:id="enterPasswordField" layoutX="96.0" layoutY="200.0" prefHeight="27.0" prefWidth="173.0" promptText="Password" />
<Button fx:id="loginButton" layoutX="22.0" layoutY="294.0" mnemonicParsing="false" onAction="#loginButtonOnAction" prefHeight="27.0" prefWidth="249.0" style="-fx-background-color: ff914d;" text="Login" textFill="WHITE" />
<Button fx:id="cancelButton" layoutX="22.0" layoutY="342.0" mnemonicParsing="false" onAction="#cancelButtonOnAction" prefHeight="27.0" prefWidth="249.0" style="-fx-background-color: ff914d;" text="Cancel" textFill="WHITE" />
<Label fx:id="loginMessageLabel" layoutX="26.0" layoutY="248.0" prefHeight="17.0" prefWidth="160.0" textFill="RED" />
</children></AnchorPane>
</right>
</BorderPane>
#Loritt I might be a bit late, but I use this method to change scenes when using JavaFX.
If you are going to be changing back and forth between scene, this method keeps you from having to write redundant code.
Stage stage;
Parent scene;
public void switchViews(ActionEvent event, String fileLocation) throws IOException {
stage = (Stage) ((Button) event.getSource()).getScene().getWindow();
scene = FXMLLoader.load(getClass().getResource(fileLocation));
stage.setScene(new Scene(scene));
stage.show();
}
I usually put this method inside the controller class which is completely acceptable as it has to do with the controlling of the visuals in the application and not any business logic.
Also, when I was originally learning how to do this myself and then pass information between the scenes I used this video and youtuber who has some good content on JavaFX/Scene Builder. (Link: https://www.youtube.com/watch?v=XCgcQTQCfJQ)
Hope this helps answer your question.
Happy coding! :)
So I made a basic application which normally looks like...
But if I add a reference to the FXML TextFlow component (fx:id="tofl") in the controller class, the GUI goes blank like...
Please explain why this is happening. My code is as follows:
main.FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.ChoiceBox?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.TextFlow?>
<fx:root prefHeight="389.0" prefWidth="732.0" styleClass="grey" stylesheets="#CSS.css" type="AnchorPane" xmlns:fx="http://javafx.com/fxml">
<TextFlow fx:id="tofl" layoutX="14.0" layoutY="14.0" prefHeight="299.0" prefWidth="703.0" />
<Button fx:id="addBtn" layoutX="596.0" layoutY="320.0" mnemonicParsing="false" text="Add new Text block" />
<TextField fx:id="txt" layoutX="14.0" layoutY="320.0" prefHeight="25.0" prefWidth="572.0" />
<CheckBox fx:id="italic" layoutX="14.0" layoutY="360.0" mnemonicParsing="false" styleClass="chckbox" text="Italic" />
<CheckBox fx:id="bold" layoutX="104.0" layoutY="360.0" mnemonicParsing="false" text="Bold" />
<CheckBox fx:id="underline" layoutX="180.0" layoutY="360.0" mnemonicParsing="false" text="Underline" />
<ChoiceBox fx:id="color" layoutX="270.0" layoutY="356.0" prefHeight="25.0" prefWidth="121.0" />
<ChoiceBox fx:id="size" layoutX="399.0" layoutY="356.0" prefHeight="25.0" prefWidth="121.0" />
</fx:root>
mainController.java
package textflow;
import java.io.IOException;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
public class mainController extends AnchorPane {
#FXML TextFlow tofl; //Problem here. If this line exists, the GUI is blank white. If I remove it, the GUI shows up. The program doesn't throw ANY errors, so it might just be a bug (either in NetBeans, or my head)
#FXML TextField txt;
#FXML Button addBtn;
#FXML CheckBox italic;
#FXML CheckBox bold;
#FXML CheckBox underline;
#FXML ChoiceBox color;
#FXML ChoiceBox size;
public mainController() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("main.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
}
}
}
TextFlow.java - the main class
package textflow;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class TextFlow extends Application {
#Override
public void start(Stage stage) throws Exception {
mainController customControl = new mainController();
stage.setScene(new Scene(customControl));
stage.setTitle("Custom Control");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The "#FXML TextFlow tofl;" in mainController.java is what is causing problems. I remove it, everything is fine. I add it, it's blank.
Take a look at the imports in mainController.java:
They don't contain an import for javafx.scene.text.TextFlow and textflow.TextFlow is used instead. You need to add an import to javafx.scene.text.TextFlow. In addition consider renaming your TextFlow class. Using the same type names as types in the API you use can easily lead to confusion.
When mainController's constructor is executed the fxml file is handled until FXMLLoader tries to inject the javafx.scene.text.TextFlow instance to the tofl field which results in a IOException because of the mismatched types.
Since you're simply ignoring the exception in the catch clause instead of handling it, the constructor completes normally and the partially loaded node is added to your scene. It's usually better to at least print the exception, unless you know the exception won't cause (or indicate) an issue, since this makes debugging much easier.
I've developed an application using JavaFX that, in part, uses a WebView. However, I've noticed that when either by the user or programmatically via JS, the WebView is scrolled to the bottom or just near the bottom, strange things seem to happen. I am specifically hoping for some way to stop this behavior, and still need to allow scrolling in both senses. It's similar to this question but they are not the same. The rest of my post explains what is happening.
If you scroll to the bottom and resize the window to be larger than previously and hover over other JavaFX controls in the window, they become white boxes.
To illustrate, suppose you have the following window:
Scroll to the bottom and resize the window to be larger than previously and then hover over the JavaFX button and TextBox, who both disappear when you do so:
This happens on at least Windows 10 with Java8u111 and Java8u51. I've made an example to demonstrate this:
example.Main.java
package example;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("Example.fxml"));
BorderPane rootWindow = (BorderPane) loader.load();
Scene scene = new Scene(rootWindow);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
example.ExampleController.java
package example;
import javafx.concurrent.Worker;
import javafx.fxml.FXML;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
public class ExampleController {
#FXML private WebView webView;
#FXML
private void initialize() {
WebEngine engine = webView.getEngine();
engine.load("https://stackoverflow.com");
engine.getLoadWorker().stateProperty().addListener( (o, oldVal, newVal) -> {
if (newVal == Worker.State.SUCCEEDED) {
engine.executeScript("window.scrollTo(0, document.body.scrollHeight);");
}
});
}
}
example.Example.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.web.WebView?>
<BorderPane prefHeight="400.0" prefWidth="500.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.111" fx:controller="example.ExampleController">
<center>
<WebView fx:id="webView" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</BorderPane.margin>
</WebView>
</center>
<bottom>
<HBox BorderPane.alignment="CENTER">
<children>
<TextField HBox.hgrow="ALWAYS" />
<Button alignment="TOP_LEFT" mnemonicParsing="false" text="Button" />
</children>
</HBox>
</bottom>
</BorderPane>
Is there a way I can stop this from happening or at least mitigate it?
I also encountered the same problem, and I found a solution:
Add a parameter to jvm:-Dprism.order=sw
see:https://news.kynosarges.org/2016/04/09/javafx-and-java_tool_options/?tdsourcetag=s_pctim_aiomsg
I'm creating a CSS stylesheet for a JavaFX 8 application.
I'm repeating these steps several times:
Edit the CSS
Run the application and see the changes
Stop the application
I found this approach very time-consuming and looking for something smarter.
Is it possibile to edit the CSS of my JavaFX application while running and see the result in real-time?
I'm looking for something like the Inspect tool of Google Chrome.
This can be partially reached by using Oracle Scene Builder. In fact I can load a CSS file and run the preview. Any change to the CSS file is correctly shown in the preview without the need to restart.
Unfortunately that's just a preview: many components are empty/uninitialized. Sure this is anyway very helpful, but many refinements require the real application running.
You will have to change using getStylesheets() / setStyle() etc.
In the example below I had to use a temp file as I am changing the CSS of the scene, when using into single components this is not necessary as you can change directly in the components.
You may download this example on gist.
Test.java
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Test extends Application{
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("doc.fxml"));
Parent root = (Parent)loader.load();
CSSController myController = loader.getController();
Scene scene = new Scene(root);
myController.setScene(scene);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
CSSController.java
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
public class CSSController implements Initializable{
private Scene scene;
#FXML TextArea cssContent;
#FXML Button defineCSSButton;
#Override
public void initialize(URL location, ResourceBundle resources) {
defineCSSButton.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent event) {
String css = cssContent.getText();
try{
File temp = new File("tempfile.css");
temp.delete();
temp.createNewFile();
BufferedWriter bw = new BufferedWriter(new FileWriter(temp));
bw.write(css);
bw.close();
String url = "tempfile.css";
scene.getStylesheets().add(temp.toURI().toString());
}catch(Exception e){
e.printStackTrace();
}
}
});
}
public void setScene(Scene scene) { this.scene = scene; }
}
doc.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.shape.*?>
<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" fx:controller="CSSController">
<children>
<TextArea fx:id="cssContent" layoutX="14.0" layoutY="26.0"
prefHeight="292.0" prefWidth="319.0" />
<Label layoutX="22.0" layoutY="6.0" text="Define your CSS here:" />
<Button fx:id="defineCSSButton" layoutX="14.1875" layoutY="333.5"
mnemonicParsing="false" text="Define CSS" />
<Line endY="400.0" layoutX="332.0" />
<Label layoutX="418.0" layoutY="15.0" text="Components:" />
<ChoiceBox layoutX="343.0" layoutY="48.0" prefWidth="150.0" />
<ColorPicker layoutX="343.3759765625" layoutY="86.0" />
<CheckBox layoutX="347.6650390625" layoutY="123.0"
mnemonicParsing="false" text="CheckBox" />
<MenuButton layoutX="343.37109375" layoutY="159.5"
mnemonicParsing="false" text="MenuButton">
<items>
<MenuItem mnemonicParsing="false" text="Action 1" />
<MenuItem mnemonicParsing="false" text="Unspecified Action" />
<MenuItem mnemonicParsing="false" text="Unspecified Action" />
<CheckMenuItem mnemonicParsing="false" text="Unspecified Action" />
</items>
</MenuButton>
<ProgressIndicator layoutX="347.9091796875" layoutY="200.01953125"
progress="0.0" />
<Slider layoutX="410.0" layoutY="213.01953125" />
<ToggleButton layoutX="348.7421875" layoutY="254.0"
mnemonicParsing="false" text="ToggleButton" />
</children>
</AnchorPane>
Css in the screenshot:
.label{
-fx-font: 15px "System Bold";
-fx-text-fill: #FF0000;
}
.button{
-fx-background-color:
#c3c4c4,
linear-gradient(#d6d6d6 50%, white 100%),
radial-gradient(center 50% -40%, radius 200%, #e6e6e6 45%, rgba(230,230,230,0) 50%);
-fx-background-radius: 30;
-fx-background-insets: 0,1,1;
-fx-text-fill: black;
-fx-effect: dropshadow( three-pass-box , rgba(0,0,0,0.6) , 3, 0.0 , 0 , 1 );
}