JavaFX / FXML UI does not look like it should - java

I have a UI I have made using Netbeans and Scene builder using Java FX / FXML. I have never had a problem with it before but for this project for some reason in Scene building my UI would look one way, even the windows preview would look identical to it, but when running it in netbeans it would look messed up. In netbeans, all I am doing is loading and calling it. I have no idea on what the issue can be and nothing is helping on Google.
working screen shot on scene builder and editing and netbeans
http://imgur.com/laZYjck
compile and run
http://imgur.com/NOMVBZe
main.java
public class main
{
public static void main(String[] args)
{
View view = new View();
view.launch();
}
}
view.java
public class View extends Application
{
#FXML
private Button login;
#Override
public void start(Stage primaryStage)
{
Parent login_page = null;
try {
login_page = FXMLLoader.load(getClass().getResource("FXMLViewLogin.fxml"));
}
catch (IOException ex)
{
}
primaryStage.setTitle("Welcome!");
primaryStage.setScene(new Scene(login_page));
primaryStage.show();
}
#FXML
private void login(ActionEvent event)
{}
}
FXMLViewLogin.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.net.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="520.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="view.ViewControllerLogin">
<children>
<Button fx:id="button1" defaultButton="true" layoutX="74.0" layoutY="296.0" text="Sign Up" />
<Label layoutX="198.0" layoutY="153.0" text="Password" />
<Label layoutX="187.0" layoutY="35.0" text="User Name" />
<TextField fx:id="password" layoutX="74.0" layoutY="204.0" />
<TextField fx:id="username" layoutX="74.0" layoutY="80.0" />
<Button fx:id="button" layoutX="323.0" layoutY="296.0" onAction="#login" text="Log In" />
</children>
</Pane>

Related

SceneBuilder cannot create instance of custom component with given set of properties

I created this custom component:
public class IconButton extends Button {
#FXML private ImageView imageView;
private IconButtonState state;
private String fullIconUrl;
private String outlineIconUrl;
public IconButton(#NamedArg("fullIconUrl") String fullIconUrl,
#NamedArg("outlineIconUrl") String outlineIconUrl) {
URL url = getClass().getResource(View.ICON_BUTTON.getFileName());
FXMLLoader loader = new FXMLLoader(url);
loader.setRoot(this);
loader.setController(this);
state = IconButtonState.NOT_INITIALIZED;
this.fullIconUrl = fullIconUrl;
this.outlineIconUrl = outlineIconUrl;
try {
loader.load();
} catch (IOException exception) {
exception.printStackTrace();
throw new RuntimeException(exception);
}
}
#FXML
public void initialize() {
this.state = IconButtonState.ACTIVE;
String url = buildUrl(fullIconUrl);
Image image = new Image(url);
imageView.setImage(image);
}
}
<!-- icon-button.fxml -->
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<fx:root mnemonicParsing="false" prefHeight="65.0" prefWidth="98.0" style="-fx-background-color: transparent;" type="Button" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1">
<graphic>
<ImageView fx:id="imageView" fitHeight="64.0" fitWidth="48.0" pickOnBounds="true" preserveRatio="true">
</ImageView>
</graphic>
</fx:root>
Then, I instantiated my IconButton component in another fxml file like this:
<!-- home.fxml -->
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.layout.*?>
<?import agill.deshopp.components.*?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="768.0" prefWidth="1024.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1">
<top>
<HBox styleClass="app-bar" stylesheets="#../css/home.css">
<padding>
<Insets bottom="15.0" top="15.0" />
</padding>
<children>
<IconButton fullIconUrl="form-full" outlineIconUrl="form-outline"></IconButton>
<IconButton fullIconUrl="message-full" outlineIconUrl="message-outline"></IconButton>
<IconButton fullIconUrl="chart-full" outlineIconUrl="chart-outline"></IconButton>
<Region HBox.hgrow="ALWAYS"></Region>
<IconButton fullIconUrl="settings-full" outlineIconUrl="settings-outline"></IconButton>
</children>
</HBox>
</top>
<center>
<Pane BorderPane.alignment="CENTER" />
</center>
</BorderPane>
The code runs fine and the screen renders as expected. However, I can't open the file in SceneBuilder. It prompts me with this exception:
java.lang.RuntimeException: Cannot create instance of agill.deshopp.components.IconButton with given set of properties: [fullIconUrl, outlineIconUrl]
javafx.fxml.LoadException:
/home/allan/IdeaProjects/california/src/main/resources/agill/deshopp/fxml/home.fxml:14
How do I fix this?
The code posted in the question is not mre and can not be invoked.
However the following code is an mre. It runs with no exceptions.
Fxml files can be edited using ScreenBuilder.
Modify it to your needs to find out what's wrong in the code posted in the question.
Note that form-full throws exception so I used form_full and that the fxml assignment should include $ sign: fullIconUrl="$form_full".
package fx_tests.test;
import java.io.IOException;
import java.net.URL;
import javafx.beans.NamedArg;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
public class IconButton extends Button {
#FXML private ImageView imageView;
private final String fullIconUrl;
public IconButton(#NamedArg("fullIconUrl") String fullIconUrl) {
this.fullIconUrl = fullIconUrl;
URL url = getClass().getResource("icon-button.fxml");
FXMLLoader loader = new FXMLLoader(url);
loader.setRoot(this);
loader.setController(this);
try {
loader.load();
} catch (IOException exception) {
exception.printStackTrace();
}
}
#FXML
public void initialize() {
Image image = new Image(fullIconUrl);
imageView.setImage(image);
}
}
Home.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.layout.*?>
<?import fx_tests.test.*?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="168.0"
prefWidth="124.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1">
<top>
<HBox>
<padding>
<Insets bottom="15.0" top="15.0" />
</padding>
<children>
<IconButton fullIconUrl="$form_full"></IconButton>
</children>
</HBox>
</top>
<center>
<Pane BorderPane.alignment="CENTER" />
</center>
</BorderPane>
icon-button.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<fx:root mnemonicParsing="false" prefHeight="65.0" prefWidth="98.0" style="-fx-background-color: transparent;"
type="Button" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1">
<graphic>
<ImageView fx:id="imageView" fitHeight="64.0" fitWidth="48.0" pickOnBounds="true" preserveRatio="true">
</ImageView>
</graphic>
</fx:root>
Test with:
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 {
private static final String IMAGE = "https://www.shareicon.net/data/128x128/2015/03/28/14104_animal_256x256.png";
#Override
public void start(Stage currentStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("Home.fxml"));
loader.getNamespace().put("form_full", IMAGE);
Parent root=loader.load();
currentStage.setScene(new Scene(root));
currentStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
When you create a custom component in JavaFX, SceneBuilder need to know the definition of this component so it can load it. I have a few custom components of my own and had to export them as a jar, and import them into SceneBuilder. Here is an answer that gives instructions on how to do this:
Adding a custom component to SceneBuilder 2.0
One catch. SceneBuilder only supports up to Java 11. So your custom component must be built and exported to a jar with this version. I had problems with Java 14 and had to backport my specific JavaFX components to Java 11. Good luck!

Javafx doesn't display a nested component

To continue this post, I implemented part of the solution that was suggested.
I have my main panel and I want to drew on it a component which is a different class (steerwheel).
My main controller :
public class WindowController {
#FXML SteerWheel steerwheel;
... other componenets..
}
My new component :
public SteeringWheel() {
myLabel = new Label();
innerCircle = new Circle();
backgroundCircle = new Circle();
System.out.println("steerwheel created.");
}
.. other methods..
My mainwindow.fxml file :
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?>
<?import view.SteerWheel?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/9.0.1" fx:controller="view.WindowController">
<center>
<SteerWheel fx:id="steerwheel" />
</center>
</BorderPane>
and my steerwheel.fxml file :
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.shape.Circle?>
<?import javafx.scene.text.Font?>
<AnchorPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="view.SteerWheel"
prefHeight="400.0" prefWidth="600.0">
<Label fx:id="mylabel" prefHeight="30.0" prefWidth="102.0" text="mytest" translateY="30" translateX="90">
<StackPane >
<Circle fx:id="innerCircle" fill="darkgray" radius="170" />
<Circle fx:id="backgroundCircle " fill="black" radius="80" />
</StackPane>
</AnchorPane>
My main code that loads the fxml files (in a different file from all mentioned) :
public class Main extends Application {
public static Stage primaryStage;
#Override
public void start(Stage primary_stage) {
this.primaryStage=primary_stage;
FXMLLoader fxl=new FXMLLoader();
try {
BorderPane root = fxl.load(getClass().getResource("mainwindow.fxml").openStream());
WindowController wc=fxl.getController();
Scene scene = new Scene(root,700,700);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
I'm seeing the constructor`s output but to the console but the component isn't displayed on the window.
Update
I tried to add a call for the fxml file of the steerwheel in my Window.fxml :
<BorderPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/9.0.1" fx:controller="view.WindowController">
<center>
<VBox maxHeight="-Infinity" prefHeight="450.0" prefWidth="400.0" BorderPane.alignment="TOP_CENTER">
<children>
<fx:include source="steerwheel.fxml" fx:id="steerwheel" />
</children>
</VBox>
</center>
</BorderPane>
Now I'm getting the following error :
Caused by: java.lang.IllegalArgumentException: Can not set view.steerWheel field view.WindowController.steerWheel to javafx.scene.layout.AnchorPane
I found the following post that described the same issue I had :
Passing data from one controller to another in javafx. java.lang.IllegalArgumentException
#fabian also answered there how to solve the issue.
The solution I implemented :
My main fxml file :
<BorderPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/9.0.1" fx:controller="view.WindowController">
<center>
<VBox maxHeight="-Infinity" prefHeight="450.0" prefWidth="400.0" BorderPane.alignment="TOP_CENTER">
<children>
<fx:include fx:id="steerwheel" source="steerwheel.fxml" />
</children>
</VBox>
</center>
</BorderPane>
In the controler of the fxml file I added an AnchorPane object that named after the fx:id and I renamed the steerWheel obj to steerwheelController :
public class WindowController {
#FXML AnchorPane steerwheel;
#FXML steerWheel steerwheelController;
Afterwards, I had to use the setLocation method in my main in order to load the inner fxml file (otherwise I got an error..) :
FXMLLoader fxl=new FXMLLoader();
try {
fxl.setLocation(getClass().getResource("Window.fxml"));
BorderPane root = fxl.load();
WindowController wc=fxl.getController();
Hoping it will help someone :)

Javafx Path to a specific folder and select the file entered on textfield

I wasn't very clear on my previous question, and I just rephrased it. Here is what I trying to achieve.
I want to define a path to a folder;
on the FROM ->TextField, Customer will enter the image name which already exist in the folder;
Click on a button and the file name will be added to the path and populate it to the imageView without manually browsing to the folder.
So, how can I do that? Thanks
ImageViewerController .java
public class ImageViewerController implements Initializable {
private Label label;
#FXML
private ImageView imageView;
#FXML
private TextField txt_Path;
private Image image;
String name;
#Override
public void initialize(URL url, ResourceBundle rb) {
}
#FXML
private void btn_Valide(ActionEvent event) {
loadImage();
}
private void loadImage(){
name = txt_Path.getText();
File file = new File("src/images/"+name);
Image image = new Image(file.toURI().toString());
imageView.setImage(image);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.*?>
<?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" prefHeight="521.0" prefWidth="660.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="imageviewer.ImageViewerController">
<center>
<Pane prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<children>
<Pane layoutX="24.0" layoutY="248.0" prefHeight="248.0" prefWidth="306.0" style="-fx-background-color: #EBDEF0;">
<children>
<ImageView fx:id="imageView" fitHeight="237.0" fitWidth="297.0" layoutX="7.0" layoutY="8.0" pickOnBounds="true" preserveRatio="true" />
</children>
</Pane>
<TextField fx:id="txt_Path" layoutX="24.0" layoutY="28.0" prefHeight="25.0" prefWidth="510.0" text="avatar.jpg" />
<Button layoutX="549.0" layoutY="28.0" mnemonicParsing="false" onAction="#btn_Valide" prefHeight="25.0" prefWidth="77.0" text="Valide" />
</children>
</Pane>
</center>
</BorderPane>

JavaFX create and use custom control with it's own functions

I have created a simple custom control as shown in picture:
when I click on "Click me" button the console shows me this message "The button was clicked!" by a function called doSomething, and this is the custom control's fxml file code:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<fx:root prefHeight="83.0" prefWidth="196.0" type="javafx.scene.layout.AnchorPane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<TextField fx:id="textField" layoutY="2.0" prefHeight="25.0" prefWidth="196.0" />
<Button layoutX="72.0" layoutY="29.0" mnemonicParsing="false" onAction="#doSomething" text="Click me" />
</children>
</fx:root>
And this is the controller of this custom control:
package control;
import java.io.IOException;
import javafx.beans.property.StringProperty;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
public class Controller extends AnchorPane {
#FXML private TextField textField;
public Controller() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("CustomControlView.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
public String getText() {
return textProperty().get();
}
public void setText(String value) {
textProperty().set(value);
}
public StringProperty textProperty() {
return textField.textProperty();
}
#FXML
protected void doSomething() {
System.out.println("The button was clicked!");
}
}
The control is working good and I can call it in another fxml file using "JavaFX scence builder" (as shown in picture) :
And this is the fxml file code:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="237.0" prefWidth="324.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<javafx.scene.layout.AnchorPane layoutX="64.0" layoutY="92.0" prefHeight="40.0" prefWidth="196.0">
<children>
<TextField fx:id="textField" layoutY="2.0" prefHeight="25.0" prefWidth="196.0" />
<Button layoutX="72.0" layoutY="29.0" mnemonicParsing="false" onAction="#doSomething" text="Click me" />
</children>
</javafx.scene.layout.AnchorPane>
<Label layoutX="75.0" layoutY="14.0" text="Trying the custom control:">
<font>
<Font size="15.0" />
</font>
</Label>
</children>
</AnchorPane>
But the problem is that I have to redefine the doSomething function of the custom control button !!!I mean when I added my custom conrol to another fxml file all the functions of this custom control should work without redefining it just like Swing.
Am I wrong ?
The problem is that the Scene Builder just copies the code of your custom control into the new control rather than linking it. To use your custom control you have to use the fx:include FXML tag.
So the FXML file should look something like:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="237.0" prefWidth="324.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<fx:include source="yourCustomControl.fxml" />
<Label layoutX="75.0" layoutY="14.0" text="Trying the custom control:">
<font>
<Font size="15.0" />
</font>
</Label>
</children>
</AnchorPane>
However, you have to do this manually. As far as I know, the Scene Builder is not capable of doing it.

How do i restart an application in JavaFx, built with FXML?

Say I have a window, with a button. And everytime that button is pressed I want the current window to be disposed and a new one to be shown.
In Swing, that was easy, but I can't find the syntax for it in JavaFx?
So in this case, with my example code, how do I do this?
public class Main extends Application {
Parent root;
Scene scene;
#Override
public void start(Stage primaryStage) throws Exception {
root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.sizeToScene();
primaryStage.setResizable(false);
primaryStage.show();
root.setOnMouseClicked((MouseEvent mouseEvent) -> {
if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
if (mouseEvent.getClickCount() == 2) {
Stage stage = new Stage();
stage.setScene(primaryStage.getScene());
stage.show();
primaryStage.close();
}
}
});
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Trying to create a new window: http://sv.tinypic.com/r/1jkq4w/8
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.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
<?import javafx.scene.text.*?>
<VBox prefHeight="430.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="blackjack.FXMLDocumentController">
<children>
<AnchorPane maxHeight="-1.0" maxWidth="-1.0" prefHeight="-1.0" prefWidth="-1.0" VBox.vgrow="ALWAYS">
<children>
<Label fx:id="labelPlayerTotal" layoutX="510.0" layoutY="335.0" prefHeight="15.0" prefWidth="121.0" text="Playertotal:" />
<Label fx:id="labelDealerTotal" layoutX="510.0" layoutY="359.0" prefHeight="15.0" prefWidth="112.0" text="Dealertotal:" />
<TextArea fx:id="dealerArea" layoutY="29.0" prefHeight="159.0" prefWidth="503.0" />
<TextArea fx:id="playerArea" layoutY="244.0" prefHeight="159.0" prefWidth="503.0" />
<Button fx:id="stayButton" layoutX="512.0" layoutY="173.0" mnemonicParsing="false" onAction="#drawCardForDealer" prefHeight="25.0" prefWidth="72.0" text="STAY" />
<Button fx:id="hitButton" layoutX="512.0" layoutY="130.0" mnemonicParsing="false" onAction="#drawCardForPlayer" prefHeight="25.0" prefWidth="72.0" text="HIT" />
<Label fx:id="labelWinner" layoutX="104.0" layoutY="208.0" prefHeight="15.0" prefWidth="296.0" />
<MenuBar fx:id="helpBar">
<menus>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem mnemonicParsing="false" onAction="#aboutApplication" text="About" />
</items>
</Menu>
</menus>
</MenuBar>
</children>
</AnchorPane>
</children>
</VBox>
You can just hide (i.e. dispose) the window by calling hide() or close() on it.
And you can just show a new window with exactly the same code you used before:
primaryStage.close();
Stage stage = new Stage();
root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
scene = new Scene(root);
stage.setScene(scene);
stage.sizeToScene();
stage.setResizable(false);
stage.show();
But this seems like way too much for what you want to achieve. Why not just replace the root of the existing scene, and use the existing stage?
try {
scene.setRoot(FXMLLoader.load(getClass().getResource("FXMLDocument.fxml")));
} catch (Exception exc) {
exc.printStackTrace();
throw new RuntimeException(exc);
}
Note though that (either way you do this) you have now replaced the root of the scene; the new root does not have the same mouse handler associated with it. If you use the second method, you can just put the handler on the scene (which doesn't change) instead. Or, perhaps better, is that you can define the listener in the FXML and controller:
<VBox prefHeight="430.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="blackjack.FXMLDocumentController"
fx:id="root"
onMouseClicked="reload">
<!-- ... -->
</VBox>
And the controller:
package blackjack ;
public class FXMLDocumentController {
// ...
#FXML
private VBox root ;
// ...
#FXML
private void reload() throws Exception {
// Really, it would be way better here to reset the whole UI to its initial
// state, instead of reloading it from scratch. This should work as a
// quick hack though.
Scene scene = root.getScene();
scene.setRoot(FXMLLoader.load(Main.class.getResource("FXMLDocument.fmxl")));
}
// ...
}

Categories