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());
Related
I have a simple JavaFX application, a BorderLayout with an AnchorPane and inside two panes, one contains a HBox and a VBox with a TextArea and a ListView. I would like them to increase in width, as I increase the window size. I have tried Vgrow/Hgrow = 'ALWAYS' and Max Width/Max Height = 'MAX_VALUE' on the the controls but nothing works.- (I use Scene Builder to create the fxml)
The FXML is the following:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>
<BorderPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1">
<center>
<AnchorPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="200.0" BorderPane.alignment="CENTER">
<children>
<Pane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="200.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" />
<Pane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="200.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="200.0">
<children>
<HBox maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="200.0">
<children>
<VBox maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="200.0" HBox.hgrow="ALWAYS">
<children>
<TextArea maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="200.0" VBox.vgrow="ALWAYS" />
<ListView maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="200.0" VBox.vgrow="ALWAYS" />
</children>
</VBox>
</children>
</HBox>
</children>
</Pane>
</children>
</AnchorPane>
</center>
</BorderPane>
My java application class (HelloApplication):
package com.example.demo;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class HelloApplication extends Application {
#Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
Scene scene = new Scene(fxmlLoader.load());
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
UPDATE: I removed the unnecessary AnchorPane and other Panes, kept only a VBox and placed it in another BorderLayout, take a look, now seems perfect :)
Don't hard-code sizes, and don't use layout panes such as Pane and AnchorPane that rely on hard-coded sizes except in very rare circumstances.
(You may sometimes need to set the max size to Double.MAX_VALUE to allow a control to grow beyond its preferred size, but even that is not necessary in this example, as far as I can tell.)
Your FXML has an empty Pane and at least two redundant wrapper containers which only wrap one node (the other Pane and the AnchorPane). Remove all of these and the hard-coded values and it will work:
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.*?>
<BorderPane xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1">
<center>
<HBox>
<children>
<VBox HBox.hgrow="ALWAYS">
<children>
<TextArea VBox.vgrow="ALWAYS" />
<ListView VBox.vgrow="ALWAYS" />
</children>
</VBox>
</children>
</HBox>
</center>
</BorderPane>
Depending on your real use-case, you may not need the HBox either:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.*?>
<BorderPane xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1">
<center>
<VBox>
<children>
<TextArea VBox.vgrow="ALWAYS" />
<ListView VBox.vgrow="ALWAYS" />
</children>
</VBox>
</center>
</BorderPane>
I want to use JFXDecorator to fancy a look of a Window of my application. But using it brokes an auto-resize of components. This is what my code looks like
#Override
public void start(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("ApplicationView.fxml"));
Parent root = loader.load();
JFXDecorator decorator = new JFXDecorator(stage, root);
decorator.setCustomMaximize(true);
stage.setTitle("Weather API");
stage.setScene(new Scene(decorator));
String cssURI = getClass().getResource("stylesheet/style.css").toExternalForm();
decorator.getStylesheets().add(cssURI);
stage.show();
}
And this is the effect, look at the split-pane.
Without JFXDecorator works normally with code like below.
#Override
public void start(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("ApplicationView.fxml"));
Parent root = loader.load();
stage.setTitle("Weather API");
stage.setScene(new Scene(root));
String cssURI = getClass().getResource("stylesheet/style.css").toExternalForm();
stage.show();
}
I tried to set AncorPane properties of main pane similar to childs so maybe it will resising but it failed. My FXML looks like that
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="480.0" prefWidth="640.0" stylesheets="#stylesheet/style.css" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.161">
<children>
<SplitPane dividerPositions="0.29797979797979796" layoutX="220.0" layoutY="129.0" prefHeight="480.0" prefWidth="640.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
</items>
</SplitPane>
</children>
</AnchorPane>
How can I fix it? Thank You.
Get rid of the AnchorPane and make the SplitPane the root node.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.layout.AnchorPane?>
<SplitPane dividerPositions="0.29797979797979796" prefHeight="480.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
</items>
</SplitPane>
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 am trying to add columns to a table view like this:
#FXML
private TableView tblView;
//private Label tblViewTitle;
#FXML
public void showTable(ActionEvent e) throws Exception{
Stage TableView = new Stage();
Parent root = FXMLLoader.load(getClass().getResource("tableView.fxml"));
TableView.setTitle("Table");
TableView.setScene(new Scene(root));
//tblViewTitle.setText("test");
//For dynamic calculate later on
TableColumn clm1 = new TableColumn("Test");
TableColumn clm2 = new TableColumn("Test");
TableColumn clm3 = new TableColumn("Test");
TableColumn clm4 = new TableColumn("Test");
tblView.getColumns().addAll(clm1, clm2, clm3, clm4);
TableView.show();
}
The fxml file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.101" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
<TableView fx:id="tblView" editable="true" layoutX="84.0" layoutY="94.0" prefHeight="306.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="94.0" />
<Label fx:id="tblViewTitle" layoutX="14.0" layoutY="26.0" prefHeight="49.0" prefWidth="181.0">
<font>
<Font size="39.0" />
</font>
</Label>
</children>
</AnchorPane>
I'm getting a nullPointerException when I'm trying to add the columns to the table view and I don't understand why.
Is it that I can't add columns because the table view is not an object?