I have a Java applet:
public abstract class FXApplet extends JApplet {
/**
* Initializes a Swing thread
*/
#Override
public void init() {
SwingUtilities.invokeLater(this::initSwing);
}
/**
* Initializes a JavaFX thread
*/
private void initSwing() {
JFXPanel panel = new JFXPanel();
add(panel);
Platform.runLater(() -> initFX(panel));
}
/**
* Here u can use JavaFX components
* #param panel Root panel
*/
abstract protected void initFX(JFXPanel panel);
}
public class FSSApplet extends FXApplet {
#Override
protected void initFX(JFXPanel panel) {
try {
ClassLoader classLoader = getClass().getClassLoader();
URL res = classLoader.getResource("views/fss.fxml");
Parent root = FXMLLoader.load(res);
Scene scene = new Scene(root);
panel.setScene(scene);
} catch (IOException e) {
e.printStackTrace();
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle("Ошибка");
alert.setHeaderText("Критическая ошибка");
alert.setContentText("Неудалось загрузить форму");
alert.showAndWait();
}
}
}
But when I am running my applet in the browser it shows a gray box only. But if I use Swing components the browser shows all perfectly.
My FXML form:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<GridPane maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity"
prefHeight="400.0" prefWidth="600.0"
fx:controller="com.contedevel.fss.controller.FSSController"
xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1">
<columnConstraints>
<ColumnConstraints hgrow="NEVER" minWidth="200.0" prefWidth="200.0" />
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="ALWAYS" />
</rowConstraints>
<children>
<VBox prefHeight="200.0" prefWidth="100.0">
<children>
<Label text="Label" fx:id="txtResult"/>
<Button mnemonicParsing="false" onAction="#handleFindAction" text="Find" />
</children>
</VBox>
</children>
</GridPane>
HTML:
<div class="page">
<applet code="com.contedevel.fss.applet.FSSApplet.class" width="100%" height="100%">Загрузка аплета</applet>
</div>
In short JavaFX doesn't work and doesn't show any errors. Where can the problem be in?
P.S. I use Java 8 and old Firefox browser. It supports applets.
Related
Below I have the code to launch my JavaFX GUI for a project I am working on. However when I go to execute the classes, it gets stuck. All it prints is Starting MCPY GUI and just sits there any help?
Launcher class
public class MCPY {
public static void main(String args[]) {
System.out.println("Starting MCPY GUI...");
Main.main(args);
}
}
Main
package com.mcpy.gui;
import java.io.IOException;
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 {
#Override
public void start(Stage primaryStage) throws Exception{
FXMLLoader loader = new FXMLLoader(getClass().getResource("styles/Main.fxml"));
Parent root;
try {
root = loader.load();
} catch (IOException ioe) {
// log exception
return;
}
//init the connection to the controller class
MainController MainController = loader.getController();
MainController.setMain(this);
//load the scene
primaryStage.setTitle("Minecraft Launcher Python");
primaryStage.setScene(new Scene(root, 800, 500));
primaryStage.show();
};
public static void main(String[] args) {
launch(args);
}
Main.FXML
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.control.Button?>
<TitledPane animated="false" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" text="Minecraft Launcher Python Login Screen" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.mcpy.gui.MainController">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<ImageView fitHeight="135.0" fitWidth="119.0" layoutX="14.0" layoutY="14.0" pickOnBounds="true" preserveRatio="true">
<image>
</image>
</ImageView>
<Button id="play" layoutX="231.0" layoutY="176.0" mnemonicParsing="false" onAction="#playButtonActionEvent" text="Play" />
<Button id="login" layoutX="313.0" layoutY="176.0" mnemonicParsing="false" onAction="#loginButtonEvent" text="Login" />
<Button id="create_account" layoutX="77.0" layoutY="176.0" mnemonicParsing="false" onAction="#create_accountButtonEvent" text="Create Account" />
</children></AnchorPane>
</content>
</TitledPane>
MainController
package com.mcpy.gui;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import com.mcpy.gui.Play;
import com.mcpy.gui.Login;
import com.mcpy.gui.CreateAccount;
/* Logic for the main gui. DO NOT EDIT. */
public class MainController {
#SuppressWarnings("unused")
private Main main;
public void setMain(Main main) {
this.main = main;
}
#FXML
private static Button login;
#FXML
private static Button create_account;
#FXML
private static Button play;
#FXML
public void loginButtonEvent(ActionEvent lbe) {
String[] args = (null);
Login.main(args);
};
#FXML
public void create_accountButtonEvent(ActionEvent cabe) {
String[] args = (null);
CreateAccount.main(args);
};
#FXML
public void playButtonActionEvent(ActionEvent pbae) {
Play.play_mc();
}
}
All of the code is here. The Launcher (MCPY.java) the main gui and its respecitve controller and the stylesheet (Main.java, MainController.java and Main.FXML)
EDIT: I have applied the FXML changes suggested by #naimdjon, however upon clicking the button this error is produced: https://pastebin.com/8EV9wfnm
You have multiple namespace declaration in your xml and imports were missing. Change your fxml to this (removed image for testing), this shows a window:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.control.Button?>
<TitledPane fx:controller="com.mcpy.gui.MainController" animated="false"
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0"
text="Minecraft Launcher Python Login Screen"
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<ImageView fitHeight="135.0" fitWidth="119.0" layoutX="14.0" layoutY="14.0" pickOnBounds="true" preserveRatio="true">
<image>
</image>
</ImageView>
<Button id="play" layoutX="231.0" layoutY="176.0" mnemonicParsing="false" text="Play" />
<Button id="login" layoutX="313.0" layoutY="176.0" mnemonicParsing="false" text="Login" />
<Button id="create_account" layoutX="77.0" layoutY="176.0" mnemonicParsing="false" text="Create Account" />
</children></AnchorPane>
</content>
</TitledPane>
UPDATE
Upon clicking on the button, you seem to be calling the launch() method. You can't call launch() method more than once in a Java FX application.
I'm writing a program which consists of two different scenes, each one is designed with an FXML file and each of them has its own controller. My initial scene works fine, and it appears in the center of the screen, but when I try to load the second scene from the controller of the first one, I get that it doesn't appears in the center of the screen like the other one does.
Can anyone please help me? It is freaking me out!
Here's some code:
#Override
public void start(Stage primaryStage) {
try {
//Create an FXMLLoader
FXMLLoader rootLoader = new FXMLLoader(getClass().getResource("MainScene.fxml"));
//Instantiate a new controller with parameter and sets it to the FXMLLoader
MainController mainController = new MainController(primaryStage);
rootLoader.setController(mainController);
//Sets the layout
Group root = rootLoader.load();
Scene startScene = new Scene(root);
//Sets the stage's scene
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.setScene(startScene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
This is from the Main.
public void initialize() {
FXMLLoader playSceneLoader = new FXMLLoader(getClass().getResource("PlayScene.fxml"));
try {
Group playSceneLayout = playSceneLoader.load();
playScene = new Scene(playSceneLayout, Screen.getPrimary().getBounds().getMaxX(), Screen.getPrimary().getBounds().getMaxY());
playScene.setFill(Color.TRANSPARENT);
} catch (IOException e) {
e.printStackTrace();
}
}
This is from the first controller which create the initial scene of the program.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.Group?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>
<Group xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<GridPane prefHeight="300.0" prefWidth="500.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<AnchorPane prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: #A47888#A47888;">
<children>
<Label fx:id="playLabel" layoutX="90.0" layoutY="129.0" onMouseClicked="#startLabelClicked" text="Play" textFill="#77354c">
<font>
<Font name="AvidOmnes Light" size="41.0" />
</font>
</Label>
</children>
</AnchorPane>
<AnchorPane prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: #77354C#77354C;" GridPane.columnIndex="1">
<children>
<Label fx:id="titleLabel" layoutX="77.0" layoutY="129.0" text="Titolo" textFill="#a47888">
<font>
<Font name="AvidOmnes Light" size="40.0" />
</font>
</Label>
<Label fx:id="closeLabel" layoutX="232.0" layoutY="6.0" onMouseClicked="#closeRoot" text="X" textFill="#a47888" />
</children>
</AnchorPane>
</children>
</GridPane>
</children>
</Group>
This is the FXML file of the initial page.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.Group?>
<?import javafx.scene.shape.Circle?>
<Group xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.PlayController">
<children>
<Circle fx:id="startCircle" fill="DODGERBLUE" onMouseClicked="#startCircleClicked" radius="100.0" stroke="BLACK" strokeType="INSIDE" />
</children>
</Group>
And this is the second scene's one.
That's absolutely normal that you get only a slice of your Circle as you do not define center coordinate and then is by default located in the position (0, 0) of the Group.
In order to see it in top-left corner of your screen, you have to maximize your Stage as soon as you click on your Label.
Here is an example: (as you were stingy of information about your code I improvise, so the important modification is in the startLabelClicked)
public class MainController {
private Stage mainStage;
private Scene playScene;
public MainController(Stage pMainStage) {
mainStage = pMainStage;
}
#FXML
public void initialize() {
FXMLLoader playSceneLoader = new FXMLLoader(getClass().getResource("PlayScene.fxml"));
try {
Parent playSceneLayout = playSceneLoader.load();
playScene = new Scene(playSceneLayout, Screen.getPrimary().getBounds().getMaxX(), Screen.getPrimary().getBounds().getMaxY());
playScene.setFill(Color.TRANSPARENT);
} catch (IOException e) {
e.printStackTrace();
}
}
#FXML
private void startLabelClicked() {
mainStage.setScene(playScene);
// This line will help you to extend your stage, which contains your scene.
mainStage.setMaximized(true);
}
#FXML
private void closeRoot() {
System.out.println("Closing.");
Platform.exit();
}
}
Without adjusting the x and y properties of the circle, the center of the circle is positioned at the top left of the scene. Since javafx does not display anything outside of the scene, you're left with the bottom right quater of a circle.
To display a circle completely in a scene with in the top left corner of a scene, you should put the circle in a layout that does some layout. E.g. AnchorPane with topAnchor and leftAnchor properties set for the circle would work, but the simplest way of accomplishing the desired result is to use a StackPane with a top left alignment:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.shape.Circle?>
<StackPane alignment="TOP_LEFT" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.PlayController">
<children>
<Circle fx:id="startCircle" fill="DODGERBLUE" onMouseClicked="#startCircleClicked" radius="100.0" stroke="BLACK" strokeType="INSIDE" />
</children>
</StackPane>
I'm trying to change from one screen to another in full screen model but only the first screen is on full screen, when I change to another screen the full screen dosn't work.
Here's my code:
Main
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.setFullScreen(true);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
sample.fmxl
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.text.Text?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
<StackPane prefHeight="200.0" prefWidth="200.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="First Screen" textAlignment="CENTER" />
</children>
</HBox>
</children>
</StackPane>
<StackPane layoutY="163.0" prefHeight="200.0" prefWidth="600.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
<children>
<HBox alignment="CENTER" prefHeight="200.0" prefWidth="600.0">
<children>
<Button fx:id="next" mnemonicParsing="false" onAction="#nextScreen" text="Next" />
</children>
</HBox>
</children>
</StackPane>
</children>
</AnchorPane>
FirstScreenController
public class Controller implements Initializable {
#FXML
private Button next;
#Override
public void initialize(URL location, ResourceBundle resources) {
}
public void nextScreen(ActionEvent actionEvent) throws Exception {
SecondScreenController secondScreen = new SecondScreenController();
Stage stage = (Stage) next.getScene().getWindow();
stage.setFullScreen(true);
secondScreen.start(stage);
}
public void start(Stage window) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
Scene scene = new Scene(root);
window.setScene(scene);
window.show();
}
}
sample2.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.text.Text?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.SecondScreenController">
<children>
<StackPane prefHeight="200.0" prefWidth="200.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Second Screen" textAlignment="CENTER" />
</children>
</HBox>
</children>
</StackPane>
<StackPane layoutY="163.0" prefHeight="200.0" prefWidth="600.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
<children>
<HBox alignment="CENTER" prefHeight="200.0" prefWidth="600.0">
<children>
<Button fx:id="back" mnemonicParsing="false" onAction="#backScreen" text="Back" />
</children>
</HBox>
</children>
</StackPane>
</children>
</AnchorPane>
SecondScreenController
public class SecondScreenController implements Initializable {
#FXML
private Button back;
#Override
public void initialize(URL location, ResourceBundle resources) {
}
public void start(Stage window) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("sample2.fxml"));
Scene scene = new Scene(root);
window.setScene(scene);
window.show();
}
public void backScreen(ActionEvent actionEvent) throws Exception {
Controller firstScreen = new Controller();
Stage stage = (Stage) back.getScene().getWindow();
stage.setFullScreen(true);
firstScreen.start(stage);
}
}
When I press the button Full Screen mode stop working, even if I go back to the first screen. Any idea how to solve this?
Add a window.setFullScreen(true); in SecondScreenController.java before window.show();.
Also add window.setFullScreen(true); in Controller.java in start() before window.show();
I am creating a basic game launcher in JavaFX with SceneBuilder. Since SceneBuilder works in FXML, my launcher layout is in FXML. I have a method in my main class that I want to call on a button click. I read that you could use
#methodName
In the button's
onAction
property, but this does not work.
My main Java class:
#FXML
private void launchGame(ActionEvent e) {
System.out.println("Launching...");
}
#Override
public void start(Stage primaryStage) throws IOException {
Parent root = FXMLLoader.load(Main.class.getResource("launcher.fxml"));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.setTitle("First Week Login");
primaryStage.setResizable(false);
primaryStage.sizeToScene();
primaryStage.show();
}
My FXML file:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.text.Text?>
<?import javafx.scene.web.WebView?>
<AnchorPane xmlns:fx="http://javafx.com/fxml/1"
xmlns="http://javafx.com/javafx/8.0.102">
<children>
<BorderPane prefHeight="493.0" prefWidth="664.0" styleClass="background"
stylesheets="#launcher.css">
<bottom>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0"
BorderPane.alignment="CENTER">
<children>
<Button alignment="CENTER" mnemonicParsing="false"
text="Launch Game" onAction="#launchGame" />
</children>
</HBox>
</bottom>
<top>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0"
BorderPane.alignment="CENTER">
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0"
styleClass="title" text="First Week" />
</children>
</HBox>
</top>
<center>
<WebView prefHeight="200.0" prefWidth="200.0"
BorderPane.alignment="CENTER" />
</center>
</BorderPane>
</children>
</AnchorPane>
You need to create a separate Controller class and specify it in top AnchorPane tag with fx:controller="packageName.Classname"
Like this:
<AnchorPane xmlns:fx="http://javafx.com/fxml/1"
xmlns="http://javafx.com/javafx/8.0.102"
fx:controller="com.packageName.Controller">
The called method should be inside the specified Controller class.
com.packageName is just an example, you should use the name of the package where you put the Controller class or no package name if it's not in any package.
I made a TextField in FXML. I want to add Button in this TextField like clear button. How can I implement this?
You could use an AnchorPane to wrap the TextField and the Button and set the anchors to have the TextField to fill the entire AnchorPane and the Button to be anchored to the right-side.
Example:
<AnchorPane prefHeight="24.0" prefWidth="322.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<TextField prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<Button graphicTextGap="0.0" minHeight="10.0" minWidth="13.0" mnemonicParsing="false" prefHeight="20.0" prefWidth="22.0" style="-fx-background-color: #7085FF;
-fx-background-radius: 30;
-fx-background-insets: 0;" text="x" textFill="WHITE" AnchorPane.bottomAnchor="4.0" AnchorPane.rightAnchor="4.0" AnchorPane.topAnchor="4.0">
<font>
<Font size="9.0" />
</font>
</Button>
</children>
</AnchorPane>
The output is like:
If you need it more than once (and most probably you will), it is a good idea to have it separately in another FXML file with the corresponding controller class that also handles the action of the Button.
Example with separated FXML:
ButtonedTextField.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.*?>
<?import javafx.scene.text.Font?>
<AnchorPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="application.ButtonedTextField">
<children>
<TextField fx:id="textField" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<Button fx:id="button" graphicTextGap="0.0" minHeight="10.0" minWidth="13.0" mnemonicParsing="false" prefHeight="20.0" prefWidth="22.0" style="-fx-background-color: #7085FF;
-fx-background-radius: 30;
-fx-background-insets: 0;" text="x" textFill="WHITE" AnchorPane.bottomAnchor="4.0" AnchorPane.rightAnchor="4.0" AnchorPane.topAnchor="4.0">
<font>
<Font size="9.0" />
</font>
</Button>
</children>
</AnchorPane>
ButtonedTextField.java (controller)
public class ButtonedTextField implements Initializable {
public #FXML TextField textField;
private #FXML Button button;
#Override
public void initialize(URL location, ResourceBundle resources) {
button.setOnAction(e -> textField.setText(""));
}
}
And then you can include this control to another FXML:
ButtonedTextFieldTest.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.*?>
<TabPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="application.ButtonedTextFieldTest">
<tabs>
<Tab text="Untitled Tab">
<content>
<AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<fx:include fx:id="buttonedTextField" source="ButtonedTextField.fxml" prefWidth="200.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="2.0" />
</children>
</AnchorPane>
</content>
</Tab>
</tabs>
</TabPane>
ButtonedTextFieldTest.java (controller of including FXML)
public class ButtonedTextFieldTest implements Initializable {
private #FXML AnchorPane buttonedTextField;
private #FXML ButtonedTextField buttonedTextFieldController;
#Override
public void initialize(URL location, ResourceBundle resources) {
buttonedTextFieldController.textField.textProperty().addListener((ov, oldVal, newVal) -> {
System.out.println(newVal);
});
}
}
Notes:
You can customize the Button as you wish (maybe it is the easier to set the graphic)
The placement and the styling can be further customized.
As you can see in the last class, the control itself and its controller can be also injected! The convention is to have the controller injected is to use the "Controller" postfix after the ID of the inected control.
I have used the CustomTextField class from the ControlsFX project for this kind of functionality before. ControlsFX lacks good documentation, but the CustomTextField class is quite easy to use:
CustomTextField textfield = new CustomTextField
textfield.setRight(new Button());