I am new to JavaFx and I am trying to create a tableview and fxml is created using scene builder. If I run the program, the table is not getting the values. I found that this question is somehow matching with my requirement (javaFX 2.2 - Not able to populate table from Controller), but my code is matching with that too. But still I am not able to get the values in the table.
I have referenced the following video : http://www.youtube.com/watch?v=HiZ-glk9_LE
My code is as follows,
MainView.java
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package controller;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class MainView extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
try {
AnchorPane page = FXMLLoader.load(MainView.class.getResource("MainView.fxml"));
Scene scene = new Scene(page);
primaryStage.setScene(scene);
primaryStage.setTitle("Sample Window");
primaryStage.setResizable(false);
primaryStage.show();
} catch (Exception e) {
}
}
}
MainView.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml" fx:controller="controller.MainViewController">
<children>
<SplitPane dividerPositions="0.535175879396985" focusTraversable="true" orientation="VERTICAL" prefHeight="400.0" prefWidth="600.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="100.0" prefWidth="160.0">
<children>
<TableView fx:id="tableID" prefHeight="210.0" prefWidth="598.0" tableMenuButtonVisible="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columns>
<TableColumn minWidth="20.0" prefWidth="40.0" text="ID" fx:id="tID" />
<TableColumn prefWidth="100.0" text="Date" fx:id="tDate" />
<TableColumn prefWidth="200.0" text="Name" fx:id="tName" />
<TableColumn prefWidth="75.0" text="Price" fx:id="tPrice" />
</columns>
</TableView>
</children>
</AnchorPane>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0" />
</items>
</SplitPane>
</children>
</AnchorPane>
MainViewController.java
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package controller;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import model.Table;
/**
* FXML Controller class
*
*/
public class MainViewController implements Initializable {
/**
* Initializes the controller class.
*/
#FXML
TableView<Table> tableID;
#FXML
TableColumn<Table, Integer> tID;
#FXML
TableColumn<Table, String> tName;
#FXML
TableColumn<Table, String> tDate;
#FXML
TableColumn<Table, String> tPrice;
int iNumber = 1;
ObservableList<Table> data =
FXCollections.observableArrayList(
new Table(iNumber++, "Dinesh", "12/02/2013", "20"),
new Table(iNumber++, "Vignesh", "2/02/2013", "40"),
new Table(iNumber++, "Satheesh", "1/02/2013", "100"),
new Table(iNumber++, "Dinesh", "12/02/2013", "16"));
#Override
public void initialize(URL url, ResourceBundle rb) {
// System.out.println("called");
tID.setCellValueFactory(new PropertyValueFactory<Table, Integer>("rID"));
tName.setCellValueFactory(new PropertyValueFactory<Table, String>("rName"));
tDate.setCellValueFactory(new PropertyValueFactory<Table, String>("rDate"));
tPrice.setCellValueFactory(new PropertyValueFactory<Table, String>("rPrice"));
tableID.setItems(data);
}
}
Table.java
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package model;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
public class Table {
SimpleIntegerProperty rID;
SimpleStringProperty rName;
SimpleStringProperty rDate;
SimpleStringProperty rPrice;
public Table(int rID, String rName, String rDate, String rPrice) {
this.rID = new SimpleIntegerProperty(rID);
this.rName = new SimpleStringProperty(rName);
this.rDate = new SimpleStringProperty(rDate);
this.rPrice = new SimpleStringProperty(rPrice);
System.out.println(rID);
System.out.println(rName);
System.out.println(rDate);
System.out.println(rPrice);
}
public Integer getrID() {
return rID.get();
}
public void setrID(Integer v) {
this.rID.set(v);
}
public String getrDate() {
return rDate.get();
}
public void setrDate(String d) {
this.rDate.set(d);
}
public String getrName() {
return rName.get();
}
public void setrName(String n) {
this.rDate.set(n);
}
public String getrPrice() {
return rPrice.get();
}
public void setrPrice(String p) {
this.rPrice.set(p);
}
}
Thanks in advance.
In a Table.java change all getters and setters names,
change getr* to getR*
change setr* to setR*
Thanks to #Uluk Biy. Whatever he mentioned, that needs to be changed and I found that I missed the <cellValueFactory> and <PropertyValueFactory> tags under the <TableColumn> tag for each columns in the FXML file which is as follows,
<TableColumn minWidth="20.0" prefWidth="40.0" text="ID" fx:id="tID" >
<cellValueFactory>
<PropertyValueFactory property="tID" />
</cellValueFactory>
</TableColumn>
Similar to this, all columns need to be updated like this.
After this change, the code is working fine. I am able to add the values into the row. :)
Related
I'm fairly new to JavaFX. I've been hopelessly trying to get this to work for so long and have no idea why it's not working. The items are not showing up on the tableview. I created the UI using scene builder. I've looked at many similar questions and nothing seems to have helped.
Simplified for minimal code:
Main:
package sample;
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{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Controller:
package sample;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import java.net.URL;
import java.util.ResourceBundle;
public class Controller implements Initializable {
ObservableList<Person> people = FXCollections.observableArrayList();
#FXML private TableView<Person> table;
#FXML private TableColumn<Person, SimpleStringProperty> c1;
#FXML private TableColumn<Person, SimpleStringProperty> c2;
#Override
public void initialize(URL location, ResourceBundle resources) {
c1.setCellValueFactory(new PropertyValueFactory<>("age"));
c2.setCellValueFactory(new PropertyValueFactory<>("name"));
people.add(new Person("2", "Sam"));
people.add(new Person("1", "Met"));
table.setItems(people);
}
}
Person class:
package sample;
import javafx.beans.property.SimpleStringProperty;
public class Person {
private SimpleStringProperty age;
private SimpleStringProperty name;
public Person(String age, String name) {
this.age = new SimpleStringProperty(age);
this.name = new SimpleStringProperty(name);
}
}
FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1">
<TableView fx:id="table" layoutX="51.0" layoutY="31.0" prefHeight="338.0" prefWidth="498.0">
<columns>
<TableColumn fx:id="c1" prefWidth="75.0" text="C1">
<cellValueFactory>
<PropertyValueFactory property="c1" />
</cellValueFactory>
</TableColumn>
<TableColumn fx:id="c2" prefWidth="75.0" text="C1">
<cellValueFactory>
<PropertyValueFactory property="c2" />
</cellValueFactory>
</TableColumn>
</columns>
</TableView>
</AnchorPane>
Thanks.
To make it work you need to implement a few changes. Read the comments in the code :
Person class must have public getters:
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Person {
private final SimpleStringProperty age;
private final SimpleStringProperty name;
public Person(String age, String name) {
this.age = new SimpleStringProperty(age);
this.name = new SimpleStringProperty(name);
}
//add getters to properties with the appropriate naming convention
public final StringProperty ageProperty() {
return age;
}
public final StringProperty nameProperty() {
return name;
}
}
In the fxml you must specify the controller. Also note the change in TableView :
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="xml_tabel_1.Controller"> <!-- need to specify the controller of the fxml -->
<TableView items="${controller.people}"> <!-- need to specify the name of the observable list -->
<columns>
<TableColumn prefWidth="75.0" text="age">
<cellValueFactory>
<PropertyValueFactory property="age" />
</cellValueFactory>
</TableColumn>
<TableColumn prefWidth="75.0" text="name">
<cellValueFactory>
<PropertyValueFactory property="name" />
</cellValueFactory>
</TableColumn>
</columns>
</TableView>
</AnchorPane>
All you need to do in the controller is to populate the observable list and have a public getter for it :
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.Initializable;
public class Controller implements Initializable {
private final ObservableList<Person> people = FXCollections.observableArrayList();
//all this was already set in fxml
//#FXML private TableView<Person> table;
//#FXML private TableColumn<Person, SimpleStringProperty> c1;
//#FXML private TableColumn<Person, SimpleStringProperty> c2;
#Override
public void initialize(URL location, ResourceBundle resources) {
people.add(new Person("2", "Sam"));
people.add(new Person("1", "Met"));
}
//add a getter to people
public ObservableList<Person> getPeople() {
return people ;
}
}
I was trying to recreate the look of the Library-List within the SceneBuilder, but I don't have any idea, which element I need to take.
How can I recreate this list?
Here is a rough draft using ControlsFx Awesome Fonts.
Main:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
*
* #author blj0011
*/
public class JavaFXApplication73 extends Application
{
#Override
public void start(Stage stage) throws Exception
{
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}
FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Accordion?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.111" fx:controller="javafxapplication73.FXMLDocumentController">
<children>
<Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
<Accordion prefHeight="200.0" prefWidth="320.0">
<panes>
<TitledPane animated="false" text="untitled 1">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<ListView fx:id="lvOne" layoutX="-19.0" layoutY="-50.0" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
</content>
</TitledPane>
<TitledPane animated="false" text="untitled 2">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" />
</content>
</TitledPane>
<TitledPane animated="false" text="untitled 3">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" />
</content>
</TitledPane>
</panes>
</Accordion>
</children>
</AnchorPane>
Controller:
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.util.Callback;
import org.controlsfx.glyphfont.FontAwesome;
/**
*
* #author blj0011
*/
public class FXMLDocumentController implements Initializable
{
#FXML ListView lvOne;
ObservableList<CustomItem> listViewData = FXCollections.observableArrayList();
#Override
public void initialize(URL url, ResourceBundle rb)
{
// TODO
lvOne.setItems(listViewData);
lvOne.setCellFactory(new Callback<ListView<CustomItem>, ListCell<CustomItem>>() {
#Override
public ListCell<CustomItem> call(ListView<CustomItem> listView)
{
return new ListViewCell();
}
});
CustomItem ci = new CustomItem();
ci.setLabelGlyph(FontAwesome.Glyph.FLASH);
ci.setString("entry one");
listViewData.add(ci);
CustomItem ci2 = new CustomItem();
ci2.setLabelGlyph(FontAwesome.Glyph.AMBULANCE);
ci2.setString("entry two");
listViewData.add(ci2);
}
}
ListView Cell:
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
/**
*
* #author blj0011
*/
public class ListViewCell extends ListCell<CustomItem>
{
#Override
public void updateItem(CustomItem item, boolean empty)
{
super.updateItem(item, empty);
if (empty || item == null)
{
setGraphic(null);
setText(null);
}
else
{
Label label = item.getLabel();
setGraphic(label);
}
}
}
CustomItem:
import javafx.scene.control.Label;
import org.controlsfx.glyphfont.FontAwesome;
import org.controlsfx.glyphfont.FontAwesome.Glyph;
/**
*
* #author blj0011
*/
public class CustomItem
{
private final Label label = new Label();
public void setLabelGlyph(Glyph glyph)
{
FontAwesome fa = new FontAwesome();
label.setGraphic(fa.create(glyph));
}
public void setString(String string)
{
label.setText(string);
}
public Label getLabel()
{
return label;
}
}
I am trying to populate filesnames in a tabular format using FXML.
I am able to display the table but the rows are not getting displayed.
Directory name will be selected by user during runtime.
.
Main.java
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.AnchorPane;
import javafx.fxml.FXMLLoader;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
AnchorPane root =(AnchorPane)FXMLLoader.load(getClass().getResource("Utility.fxml"));
Scene scene = new Scene(root,600,600);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.setTitle("testing");
primaryStage.show();
} catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
AppController.java
import java.io.File;
import java.util.Arrays;
import java.util.List;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.stage.DirectoryChooser;
public class AppController
{
#FXML private Label BrowseStatus;
#FXML private TextField TDpath;
#FXML private Button CreateH2H;
#FXML private TableView<String> FileListTable;
#FXML private TableColumn<FilesInDir,String> FileNameCol;
#FXML private ObservableList<String> fidlist;
#FXML
protected void handleBrowseWindowsExplorer(ActionEvent event){
DirectoryChooser TestDataDir = new DirectoryChooser();
TestDataDir.setTitle("Select path");
File selectedDir = TestDataDir.showDialog(null);
if(selectedDir == null){
BrowseStatus.setText("Nothing choosen");
TDpath.setText("");
} else {
TDpath.setText(selectedDir.getAbsolutePath());
FileListTable = new TableView<String>();
FileNameCol.setCellValueFactory(new PropertyValueFactory<FilesIndDir,String>("FileName"));
FileListTable.setPlaceholder(BrowseStatus);
BrowseStatus.setText("Folder has been selected");
File tFile = new File(TDpath.getText());
File[] listOfFiles = tFile.listFiles();
fidlist = FXCollections.observableArrayList();
List<String> fileNameList = null;
for (int i=0; i<listOfFiles.length; i++) {
fileNameList = Arrays.asList(listOfFiles[i].getName());
}
fidlist.addAll(fileNamesList);
FileListTable.setItems(fidlist);
}
}
}
Utility.fxml
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.collection.*?>
<?import javafx.collections.FXCollections?>
<?import javafx.geometry.*?>
<?import javafx.scene.chart.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
<?import javafx.scene.web.*?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<AnchorPane fx:controller="application.AppController" id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns:fx="http://javafx.com/fxml">
<children>
<GridPane>
<children>
<MenuBar maxWidth="-Infinity" prefWidth="800.0" GridPane.ColumnIndex="0" GridPane.RowIndex="0">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" text="Close" />
</items>
</Menu>
</menus>
</MenuBar>
<BorderPane GridPane.ColumnIndex="0" GridPane.RowIndex="1">
<top>
<TabPane PrefHeight="700.0" PrefWidth="900.0" tabClosingPolicy="UNAVAILABLE">
<Tab text="Files tab ">
<content>
<GridPane hgap="10" vgap="10">
<padding><Insets top="25" right="25" bottom="10" left="25" /></padding>
<children>
<Label text="Path :" GridPane.ColumnIndex="0" GridPane.RowIndex="1" />
<TextField fx:id="TDpath" GridPane.ColumnIndex="0" GridPane.RowIndex="1" />
<Button text="Browse" onAction="#handleBrowseWindowsExplorer" GridPane.ColumnIndex="3" GridPane.RowIndex="1" />
<VBox prefHeight="300.0" prefWidth="400.0" spacing="6.0" VBox.vgrow="ALWAYS" GridPane.ColumnIndex="0" GridPane.RowIndex="3" GridPane.columnSpan="4" >
<children>
<TableView fx:id="FileListTable" >
<placeholder><Label fx:id="BrowseStatus" text="No files in selected directory" /></placeholder>
<columns>
<TableColumn fx:id="FileNameCol" text="File Names" prefWidth="400">
<cellValueFactory>
<PropertyValueFactory property="FileName" />
</cellValueFactory>
</TableColumn>
</columns>
</TableView>
</children>
</VBox>
</children>
</GridPane>
</content>
</Tab>
</TabPane>
</top>
</BorderPane>
</children>
</GridPane>
</children>
</AnchorPane>
FilesInDir.java
import javafx.beans.property.SimpleStringProperty;
public class FilesInDir {
private final SimpleStringProperty FileName = new SimpleStringProperty();
public FilesInDir(String fName) {
setFileName(fName);
}
public String FileNameProperty() {
return FileName.get();
}
public void setFileName(String fName) {
this.Filename.set(fName);
}
}
In this answer I'll just ignore all the typos, since there seems to be a compilable version of the code and point out the other errors:
FilesInDir
If I got your intention, this class should contain the info for a file that should be displayed. Besides ignoring the naming convention of starting identifiers of class members with a lowercase letter, the real issue here is the FileNameProperty. The property method with the suffix Property has to return the property itself and PropertyValueFactory relies on that fact. It should look like this:
public StringProperty fileNameProperty() {
return FileName;
}
Also you did not use the class as type parameter of your TableView:
#FXML
private TableView<FilesInDir> FileListTable;
AppController.handleBrowseWindowsExplorer
The main issue is in this method:
There's no need to need to make fidlist a field, let alone annotate it with #FXML. In fact there's no need to create a new ObservableList at all.
You recreate the TableView, that was created and injected by the FXMLLoader and do not insert it to the scene graph, but you work with the new TableView, which is not the one that is displayed on screen.
If no file is selected, the TextField is emptied, but the items in the TableView from a previously selected directory remain, leading to inconsistent behaviour.
fileNameList = Arrays.asList(listOfFiles[i].getName()); in the for loop replaces the list with a new List containing a single element every time it's executed.
File tFile = new File(TDpath.getText()); recreates the file from the String that was created by converting the selected file to a String. That's just unnecessary; you should simply use selectedDir
Changing the method like this should work, assuming you fixed the points mentioned for FilesInDir too:
#FXML
protected void handleBrowseWindowsExplorer(ActionEvent event) {
DirectoryChooser TestDataDir = new DirectoryChooser();
TestDataDir.setTitle("Select path");
File selectedDir = TestDataDir.showDialog(null);
if (selectedDir == null) {
BrowseStatus.setText("Nothing choosen");
FileListTable.getItems().clear();
TDpath.setText("");
} else {
TDpath.setText(selectedDir.getAbsolutePath());
BrowseStatus.setText("Folder has been selected");
File[] listOfFiles = selectedDir.listFiles();
ArrayList<FilesInDir> fidlist = new ArrayList<>(listOfFiles.length);
for (File listOfFile : listOfFiles) {
fidlist.add(new FilesInDir(listOfFile.getName()));
}
FileListTable.getItems().setAll(fidlist);
}
}
Well, my question is simple.
I am building an application with Java Fx, and I have a TabPane.
When I open a new Tab, that Tab gets it's content by a fxml file.
tab.setContent((Node)FXMLLoader.load(this.getClass().getResource("/main/textEditor.fxml")))
Fine, that works well, it always loads the same file on all Tabs, so, all textarea on all tabs have the same id.
The problem is, with java, I can only get the information of the textarea of the first Tab.
How can i edit specifically the textarea of one tab in particular?
An example of what i want to do :
Main
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Rectangle2D;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Screen;
import javafx.stage.Stage;
public class Main extends Application{
public static void main(String[] args) {
Application.launch(Main.class, args);
}
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/tabPane/test.fxml"));
Screen screen = Screen.getPrimary();
Rectangle2D bounds = screen.getVisualBounds();
stage.setScene(new Scene(root));
stage.show();
}
}
test.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.net.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.layout.AnchorPane?>
<VBox prefHeight="400.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="tabPane.controller">
<children>
<MenuBar VBox.vgrow="NEVER">
<menus>
<Menu mnemonicParsing="false" onAction="#test" text="File">
<items>
<MenuItem fx:id="insert" mnemonicParsing="false" onAction="#test" text="Insert" />
</items>
</Menu>
</menus>
</MenuBar>
<AnchorPane maxHeight="-1.0" maxWidth="-1.0" prefHeight="-1.0" prefWidth="-1.0" VBox.vgrow="ALWAYS">
<children>
<Label alignment="CENTER" layoutX="155.0" layoutY="177.0" style="
" text="Drag components from Library hereā¦" textAlignment="CENTER" textFill="#9f9f9f" wrapText="false">
<font>
<Font size="18.0" />
</font>
</Label>
<TabPane fx:id="tabPane" prefHeight="375.0" prefWidth="640.0" tabClosingPolicy="UNAVAILABLE">
<tabs>
<Tab text="Untitled Tab 1">
<content>
<TextArea fx:id="textarea" prefHeight="200.0" prefWidth="200.0" text="a" />
</content>
</Tab>
<Tab text="Untitled Tab 2">
<content>
<TextArea fx:id="textarea1" prefHeight="200.0" prefWidth="200.0" text="a" />
</content>
</Tab>
</tabs>
</TabPane>
</children>
</AnchorPane>
</children>
<stylesheets>
<URL value="#../../../../BasicApplicatio11n_css/BasicApplication.css" />
controller.java
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TextArea;
public class controller implements Initializable{
#FXML
private TextArea textarea;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
}
public void test(ActionEvent event){
textarea.appendText("Text");
}
}
There are two tabs on this example, when the button is pressed, I want to add the text on the current selected tab.
There are a few different ways to do this. One way is to let the controller for the tab content expose the textProperty from the text area. Then in your "main controller", create a StringProperty field. When you create a new tab, just observe its selected property and update the string property field to point to the one from the current controller. Then you can easily load text into the "current" pane.
Here's a simple example of this:
EditorController:
import javafx.beans.property.StringProperty;
import javafx.fxml.FXML;
import javafx.scene.control.TextArea;
public class EditorController {
#FXML
private TextArea textArea ;
public StringProperty textProperty() {
return textArea.textProperty() ;
}
}
with textEditor.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.TextArea?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="EditorController">
<center>
<TextArea fx:id="textArea"/>
</center>
</BorderPane>
And then the MainController could look like:
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import javafx.beans.property.StringProperty;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.stage.FileChooser;
public class MainController {
#FXML
private TabPane tabPane ;
private StringProperty currentText ;
public void initialize() throws IOException {
// load an initial tab:
newTab();
}
#FXML
private void newTab() throws IOException {
Tab tab = new Tab("Untitled text");
FXMLLoader loader = new FXMLLoader(getClass().getResource("textEditor.fxml"));
tab.setContent(loader.load());
EditorController controller = loader.getController() ;
tab.selectedProperty().addListener((obs, wasSelected, isNowSelected) -> {
if (isNowSelected) {
currentText = controller.textProperty();
}
});
tabPane.getTabs().add(tab);
tabPane.getSelectionModel().select(tab);
}
#FXML
private void load() {
FileChooser chooser = new FileChooser();
File file = chooser.showOpenDialog(tabPane.getScene().getWindow());
if (file != null) {
Path path = file.toPath();
try {
currentText.set(String.join("\n", Files.readAllLines(path)));
} catch (IOException e) {
Alert alert = new Alert(AlertType.ERROR);
alert.setContentText("Unable to load file "+path);
alert.setTitle("Load error");
alert.showAndWait();
}
tabPane.getSelectionModel().getSelectedItem().setText(path.getFileName().toString());
}
}
}
with main.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="MainController">
<center>
<TabPane fx:id="tabPane"/>
</center>
<bottom>
<HBox alignment="CENTER" spacing="5">
<padding>
<Insets top="5" right="5" left="5" bottom="5" />
</padding>
<Button text="Load..." onAction="#load" />
<Button text="New" onAction="#newTab"/>
</HBox>
</bottom>
</BorderPane>
For completeness, a simple application class:
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 IOException {
Parent root = FXMLLoader.load(getClass().getResource("main.fxml"));
Scene scene = new Scene(root, 800, 800);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
There are other approaches, e.g. you could just change the button's onAction property when the tab selection changes, etc.
I am trying to create a custom control in JavaFX8. What I would like to achieve is an AnchorPane with a header and a footer that can each contain controls. I've noticed that any events I create on the control will not fire in "design mode". How would I implement dragging and dropping of new Nodes into my control using SceneBuilder?
Here is a simple example. I have this control.
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<fx:root minHeight="300" minWidth="300" type="javafx.scene.layout.AnchorPane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<AnchorPane fx:id="test" prefHeight="209.0" prefWidth="191.0">
<children>
<Button fx:id="button" layoutX="126" layoutY="90" onAction="#handleButtonAction" text="Click Me!" />
<Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
<TextField fx:id="textField" layoutX="14.0" layoutY="14.0" />
<HBox fx:id="hbox" layoutX="14.0" layoutY="40.0" prefHeight="100.0" prefWidth="100.0" style="-fx-background-color: RED;" />
</children>
</AnchorPane>
</children>
</fx:root>
Here is the controller:
///*
// * To change this license header, choose License Headers in Project Properties.
// * To change this template file, choose Tools | Templates
// * and open the template in the editor.
// */
package javafxbeancontroltest;
//
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
//
///**
// *
// * #author ajmiro
// */
public class FXMLDocumentController extends AnchorPane
{
#FXML
StringProperty labelText = new SimpleStringProperty("Initial Value");
public String getLabelText() { return labelText.get(); }
public void setLabelText(String newText) {labelText.set(newText);}
public StringProperty labetTextProperty() { return labelText; }
public Button getButton() {return button;}
#FXML
private AnchorPane test;
public AnchorPane getTest() {return test;}
#FXML
private Label label;
#FXML
public Button button;
#FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
//label.setText("Hello World!");
label.setText(getLabelText());
//label.setText(textField.getText());
}
public FXMLDocumentController() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/javafxbeancontroltest/FXMLDocument.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
How would I implement being able to drag a control onto the red HBOX at design time in SceneBuilder 2.0?