I am fairly new to javafx and have been following a tutorial (http://code.makery.ch/library/javafx-8-tutorial/) where all my code has come from.
I am having an issue with populating a table with an xml file which I believe is because I want to switch scene first and then display the table on this new scene. In the guide they do it on just the first scene that loads, which if I do I can get to work fine, but when I want the table data to be viewable on a different scene, it doesn't seem to work. All I did was change where some of the code was located within the class to try to reflect this as I didn't want it on my first scene but now it won't display.
LibraryApp
package libraryapp;
import java.io.File;
import java.io.IOException;
import java.util.prefs.Preferences;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import libraryapp.model.Book;
import libraryapp.model.BookListWrapper;
import libraryapp.view.HomeOverviewController;
import libraryapp.view.RootLayoutController;
public class LibraryApp extends Application {
private Stage primaryStage;
private BorderPane rootLayout;
/**
* The data as an observable list of Books.
*/
private ObservableList<Book> bookData = FXCollections.observableArrayList();
/**
* Constructor
*/
public LibraryApp() {
// Add some sample data
bookData.add(new Book("Hans", "Muster"));
bookData.add(new Book("Ruth", "Mueller"));
bookData.add(new Book("Heinz", "Kurz"));
bookData.add(new Book("Cornelia", "Meier"));
bookData.add(new Book("Werner", "Meyer"));
bookData.add(new Book("Lydia", "Kunz"));
bookData.add(new Book("Anna", "Best"));
bookData.add(new Book("Stefan", "Meier"));
bookData.add(new Book("Martin", "Mueller"));
}
/**
* Returns the data as an observable list of Books.
* #return
*/
public ObservableList<Book> getBookData() {
return bookData;
}
#Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("LibraryApp");
initRootLayout();
showHomeOverview();
}
/**
* Initializes the root layout and tries to load the last opened
* person file.
*/
public void initRootLayout() {
try {
// Load root layout from fxml file.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(LibraryApp.class.getResource("view/RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
// Give the controller access to the main app.
RootLayoutController controller = loader.getController();
controller.setLibraryApp(this);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
// Try to load last opened person file.
File file = getBookFilePath();
if (file != null) {
loadBookDataFromFile(file);
}
}
/**
* Shows the book overview inside the root layout.
*/
public void showHomeOverview() {
try {
// Load home overview.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(LibraryApp.class.getResource("view/HomeOverview.fxml"));
AnchorPane homeOverview = (AnchorPane) loader.load();
// Set home overview into the center of root layout.
rootLayout.setCenter(homeOverview);
// Give the controller access to the main app.
HomeOverviewController controller = loader.getController();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Returns the main stage.
* #return
*/
public Stage getPrimaryStage() {
return primaryStage;
}
public static void main(String[] args) {
launch(args);
}
/**
* Returns the book file preference, i.e. the file that was last opened.
* The preference is read from the OS specific registry. If no such
* preference can be found, null is returned.
*
* #return
*/
public File getBookFilePath() {
Preferences prefs = Preferences.userNodeForPackage(LibraryApp.class);
String filePath = prefs.get("filePath", null);
if (filePath != null) {
return new File(filePath);
} else {
return null;
}
}
/**
* Sets the file path of the currently loaded file. The path is persisted in
* the OS specific registry.
*
* #param file the file or null to remove the path
*/
public void setBookFilePath(File file) {
Preferences prefs = Preferences.userNodeForPackage(LibraryApp.class);
if (file != null) {
prefs.put("filePath", file.getPath());
// Update the stage title.
primaryStage.setTitle("LibraryApp - " + file.getName());
} else {
prefs.remove("filePath");
// Update the stage title.
primaryStage.setTitle("LibraryApp");
}
}
/**
* Loads book data from the specified file. The current book data will
* be replaced.
*
* #param file
*/
public void loadBookDataFromFile(File file) {
try {
JAXBContext context = JAXBContext
.newInstance(BookListWrapper.class);
Unmarshaller um = context.createUnmarshaller();
// Reading XML from the file and unmarshalling.
BookListWrapper wrapper = (BookListWrapper) um.unmarshal(file);
bookData.clear();
bookData.addAll(wrapper.getBooks());
// Save the file path to the registry.
setBookFilePath(file);
} catch (Exception e) { // catches ANY exception
Alert alert = new Alert(AlertType.ERROR);
alert.setTitle("Error");
alert.setHeaderText("Could not load data");
alert.setContentText("Could not load data from file:\n" + file.getPath());
alert.showAndWait();
}
}
/**
* Saves the current book data to the specified file.
*
* #param file
*/
public void saveBookDataToFile(File file) {
try {
JAXBContext context = JAXBContext
.newInstance(BookListWrapper.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
// Wrapping our book data.
BookListWrapper wrapper = new BookListWrapper();
wrapper.setBooks(bookData);
// Marshalling and saving XML to the file.
m.marshal(wrapper, file);
// Save the file path to the registry.
setBookFilePath(file);
} catch (Exception e) { // catches ANY exception
Alert alert = new Alert(AlertType.ERROR);
alert.setTitle("Error");
alert.setHeaderText("Could not save data");
alert.setContentText("Could not save data to file:\n" + file.getPath());
alert.showAndWait();
}
}
}
HomeOverViewController
package libraryapp.view;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.layout.AnchorPane;
import libraryapp.view.BrowseController;
public class HomeOverviewController implements Initializable {
#FXML
private AnchorPane homePane;
#FXML
private void goToBrowse(ActionEvent event) throws IOException {
AnchorPane pane = FXMLLoader.load(getClass().getResource("Browse.fxml"));
homePane.getChildren().setAll(pane);
}
#FXML
private void goToManageAccount(ActionEvent event) throws IOException {
AnchorPane pane = FXMLLoader.load(getClass().getResource("ManageAccount.fxml"));
homePane.getChildren().setAll(pane);
}
#FXML
public void logout(ActionEvent event) throws IOException {
AnchorPane pane = FXMLLoader.load(getClass().getResource("Login.fxml"));
homePane.getChildren().setAll(pane);
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
BrowseController
package libraryapp.view;
import java.io.File;
import java.io.IOException;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.AnchorPane;
import libraryapp.LibraryApp;
import libraryapp.model.Book;
public class BrowseController {
#FXML
private TableView<Book> bookTable;
#FXML
private TableColumn<Book, String> titleColumn;
#FXML
private Label titleLabel;
#FXML
private Label authorLabel;
#FXML
private Label isbnLabel;
#FXML
private Label quantityLabel;
#FXML
private AnchorPane browsePane;
// Reference to the main application.
private LibraryApp libraryApp;
/**
* The constructor.
* The constructor is called before the initialize() method.
*/
public BrowseController() {
}
/**
* Initializes the controller class. This method is automatically called
* after the fxml file has been loaded.
*/
#FXML
private void initialize() {
// Initialize the book table
titleColumn.setCellValueFactory(
cellData -> cellData.getValue().titleProperty());
// Clear person details.
showBookDetails(null);
// Listen for selection changes and show the person details when changed.
bookTable.getSelectionModel().selectedItemProperty().addListener(
(observable, oldValue, newValue) -> showBookDetails(newValue));
}
/**
* Is called by the main application to give a reference back to itself.
*
* #param libraryApp
*/
public void setLibraryApp(LibraryApp libraryApp) {
this.libraryApp = libraryApp;
// Add observable list data to the table
bookTable.setItems(libraryApp.getBookData());
}
private void showBookDetails(Book book) {
if (book != null) {
// Fill the labels with info from the book object.
titleLabel.setText(book.getTitle());
authorLabel.setText(book.getAuthor());
isbnLabel.setText(book.getIsbn());
quantityLabel.setText(Integer.toString(book.getQuantity()));
} else {
// Book is null, remove all the text.
titleLabel.setText("");
authorLabel.setText("");
isbnLabel.setText("");
quantityLabel.setText("");
}
}
/**
* Called when the user clicks on the borrow button.
*/
#FXML
private void handleDeleteBook() {
int selectedIndex = bookTable.getSelectionModel().getSelectedIndex();
if (selectedIndex >= 0) {
bookTable.getItems().remove(selectedIndex);
} else {
// Nothing selected.
Alert alert = new Alert(AlertType.WARNING);
alert.initOwner(libraryApp.getPrimaryStage());
alert.setTitle("No Selection");
alert.setHeaderText("No book Selected");
alert.setContentText("Please select a book.");
alert.showAndWait();
}
}
#FXML
public void logout(ActionEvent event) throws IOException {
File bookFile = libraryApp.getBookFilePath();
libraryApp.saveBookDataToFile(bookFile);
AnchorPane pane = FXMLLoader.load(getClass().getResource("Login.fxml"));
browsePane.getChildren().setAll(pane);
}
}
The idea is that I want to press a button which calls goToBrowse which will load the Browse scene and then populate the table there with the data from the xml file. It goes to browse scene fine but does not populate the table.
Please excuse any messy code and any bad naming conventions as I am pretty new to this javafx stuff and have been trying to follow the tutorial that was mentioned before and tweak it to what I thought would be correct.
I believe it is the setLibraryApp that I want to be calling in the BrowseController, but what I have tried doesn't seem to work.
Related
I have the need to have a selection listener and select method on a pane to be able to monitor and present a highlight when a node is clicked on.
I did the following:
public class PaneWithSelectionListener extends Pane {
private ObjectProperty<Annotation> selectedAnnotation = new SimpleObjectProperty<>();
public PaneWithSelectionListener() {
super();
selectedAnnotation.addListener((obs, oldAnno, newAnno) -> {
if (oldAnno != null) {
oldAnno.setStyle("");
}
if (newAnno != null) {
newAnno.setStyle("-fx-border-color: blue;-fx-border-insets: 5;-fx-border-width: 1;-fx-border-style: dashed;");
}
});
setOnMouseClicked(e->selectAnnotation(null));
}
public void selectAnnotation(Annotation ann){
selectedAnnotation.set(ann);
}
}
And this works great - however I am not able to work with SceneBuilder anymore since my FXML references this PaneWithSelectionListener rather than Pane. I am not sure how to get my custom pane into SceneBuilder. I have looked at other questions and they are all a combination of FXML and Controllers - where this is just a Pane.
Does anyone know of a way to do this, or perhaps swap the Pane for a PaneWithSelectionListener at initialization time?
Thanks
If the issue is just to make your custom class available in SceneBuilder, you can do so with the following steps:
Bundle your custom class (and any supporting classes, such as Annotation) as a jar file
In SceneBuilder, activate the drop-down button next to "Library" in the top of the left pane:
Choose "Import JAR/FXML File..."
Select the Jar file created from step 1
Make sure the class you need access to in SceneBuilder (PaneWithSelectionListener) is checked
Press "Import Component"
PaneWithSelectionListener will now appear in SceneBuilder under "Custom" in the left pane:
You'll notice the drop-down in SceneBuilder has a "Custom Library Folder" option, from which you can open the folder where the jar files are stored. For a quick option, you can just copy jar files to this folder and (after a short delay), the contained classes will appear in the "Custom" list.
I created a CustomCB a combo box which is of type a userObject. In my case I have used <APerson> as userObject. Entire project and the TESTER are here. First one is CustomCB, the components and the JAR file generated out of this code is added to the Library. This can be loaded in SCENE BUILDER. Thereafter it is available for scene design.
Then of course, you have a tester CustomCB2, which also can use a FXML instead of the way I have done.
I actually want the items starting with the text I type in the ComboBox to appear in the list. But I don't know how to do it. Because the FIRST NAME or LAST NAME of the PERSON class can start with 'Pe'. If I find a solution, I will post it here.
This is the Custom Component.
package customCB;
/*
* 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.
*/
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
/**
*
* #author Hornigold Arthur
*/
public class APerson {
private final StringProperty firstName;
private final StringProperty lastName;
private final IntegerProperty familyID;
private final IntegerProperty personID;
public APerson() {
this(null, null, 0,0);
}
/**
* Constructor with some initial data.
*
* #param familyID
* #param familyName
*/
public APerson (String firstName, String lastName, int familyID, int personID) {
this.firstName = new SimpleStringProperty(firstName);
this.lastName = new SimpleStringProperty(lastName);
this.familyID = new SimpleIntegerProperty(familyID);
this.personID = new SimpleIntegerProperty(personID);
}
public int getFamilyID() {
return familyID.get();
}
public void setFamilyID(int FamilyID) {
this.familyID.set(FamilyID);
}
public IntegerProperty familyIDProperty() {
return familyID;
}
public int getPersonID() {
return personID.get();
}
public void setPersonID(int PersonID) {
this.personID.set(PersonID);
}
public IntegerProperty personIDProperty() {
return personID;
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String FirstName) {
this.firstName.set(FirstName);
}
public StringProperty firstNameProperty() {
return firstName;
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String LastName) {
this.lastName.set(LastName);
}
public StringProperty lastNameProperty() {
return lastName;
}
public String toString() {
String name = getFirstName() + " " + getLastName()+ " [" + getFamilyID() +"]";
return name;
}
}
This is the FXML for the Custom Component.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.layout.VBox?>
<fx:root stylesheets="#application.css" type="javafx.scene.layout.VBox" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1">
<ComboBox fx:id="myCustomCombo" editable="true" onAction="#cbOnAction" prefWidth="300.0" style="-fx-background-color: white;" />
</fx:root>
This is the controller for this FXML but do not mention it in FXML file. It throws error.
package customCB;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import org.controlsfx.control.textfield.TextFields;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListView;
import javafx.scene.layout.VBox;
public class CustomComboController extends VBox{
#FXML
private ResourceBundle resources;
#FXML
private URL location;
#FXML
private ComboBox<APerson> myCustomCombo;
#FXML
void cbOnAction(ActionEvent event) {
}
#FXML
void initialize() {
assert myCustomCombo != null : "fx:id=\"myCustomCombo\" was not injected: check your FXML file 'CustomLvFXML.fxml'.";
}
public CustomComboController() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("customCombo.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
public void setCBValues(javafx.collections.ObservableList<APerson> values) {
myCustomCombo.setItems(values);
myCustomCombo.setEditable(true);
TextFields.bindAutoCompletion(myCustomCombo.getEditor(), myCustomCombo.getItems());
}
}
Download controlsfx-8.40.12.jar from WEB and include this in the BUILD PATH as library.
Now create a jar file for this project. "CustomCB.jar".
This JAR file has to be included as custom control in Scene Builder. I use version 10.0.
Now that it is part of Scene builder you can use this component in designing, unless you can do it the way I have done in my TEST CODE. You need to include "CustomCB.jar" as part of the library for building.
This is the code for the tester.
package customCB2;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
public class Main extends Application {
static private javafx.collections.ObservableList<APerson> fathers = javafx.collections.FXCollections.observableArrayList();
static private javafx.collections.ObservableList<APerson> mothers = javafx.collections.FXCollections.observableArrayList();
#Override
public void start(Stage stage) throws Exception {
CustomComboController customControl2 = new CustomComboController();
CustomComboController customControl3 = new CustomComboController();
loadFathers();
loadMothers();
customControl2.setCBValues(fathers);
customControl3.setCBValues(mothers);
VBox root = new VBox();
root.getChildren().addAll(customControl2, customControl3);
stage.setScene(new Scene(root));
stage.setTitle("Custom Control Combo box");
stage.setWidth(300);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
private void loadFathers() {
fathers.clear();
fathers.add(new APerson("Hornigold","Arthur",1,63));
fathers.add(new APerson("Andrews","Sundareson",2,60));
fathers.add(new APerson("Christopher","Easweradoss",3,57));
fathers.add(new APerson("Arthur","Kennedy",4,55));
}
private void loadMothers() {
mothers.clear();
mothers.add(new APerson("Victoria","Arthur",1,95));
mothers.add(new APerson("Eliza", "Daniel",1,60));
mothers.add(new APerson("Nesammal", "Rivington",2,57));
mothers.add(new APerson("Ratnammal","Andews",1,55));
}
}
It needs lot of improvements. If anyone can improvise, please add it here.
I am trying to populate a TableView called CustomerTableViewusing a ComboBox called ComboBoxSelectCustomer. Basically the user selects a customer from the list of customers inside the ComboBox and than the TableView will populate with data that matches that customer's name. I have multiple tables in an SQL file with each customer but for some reason when I select a customer name from the combobox, nothing happens on the TableView, it just remains empty. There are no errors or any issues with the code, I just think that the way it is setup is whats causing the problem. Please review my code and advise me on how I can set these methods up in a better way to have the ComboBox trigger an SQL statement to populate the TableView
//MainController
/*
* 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 supremeinkcalcmk2;
import java.net.URL;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javax.swing.DefaultComboBoxModel;
/**
* FXML Controller class
*
*/
public class MainController implements Initializable {
#FXML
public ComboBox<String> ComboBoxSelectCustomer;
#FXML
private TableView CustomerTableView;
#FXML
private TableColumn<BaseColor, String> BaseColor;
#FXML
private TableColumn<BaseColor, String> Price;
Connection connection;
/**
* Initializes the controller class.
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
//Customer combo box
ComboBoxSelectCustomer.setOnAction(e -> System.out.println(ComboBoxSelectCustomer.getValue()));
buildDataComboBox();
buildDataTableView();
}
public void buildDataTableView() {
//viewtable db connect
ObservableList<BaseColor> dataCustomerViewTable = FXCollections.observableArrayList();
BaseColor.setCellValueFactory(new PropertyValueFactory<BaseColor, String>("BaseColor"));
Price.setCellValueFactory(new PropertyValueFactory<BaseColor, String>("Price"));
connection = SqlConnection.CustomerConnection();
try {
//problem
String SQL = "Select BaseColor, Price FROM " + ComboBoxSelectCustomer.getValue();
connection = SqlConnection.CustomerConnection();
ResultSet rs = connection.createStatement().executeQuery(SQL);
while (rs.next()) {
BaseColor BS = new BaseColor();
BS.BaseColor.set(rs.getString("BaseColor"));
BS.Price.set(rs.getString("Price"));
dataCustomerViewTable.add(BS);
}
CustomerTableView.setItems(dataCustomerViewTable);
} catch (Exception e) {
}
}
//combobox sql connection and fill data
public void buildDataComboBox() {
ObservableList<String> dataComboBox = FXCollections.observableArrayList();
connection = SqlConnection.CustomerConnection();
try {
String SQL = "Select Name From CustomerList";
ResultSet rs = connection.createStatement().executeQuery(SQL);
while (rs.next()) {
dataComboBox.add(rs.getString("Name"));
}
ComboBoxSelectCustomer.setItems(dataComboBox);
} catch (Exception e) {
e.printStackTrace();
System.out.println("Error Building ComboBox Data");
}
if (connection == null) {
System.exit(1);
System.out.println("Connection failed");
}
}
public boolean isDbConnected() {
try {
return connection.isClosed();
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
}
Created a setOnAction event on ComboBoxSelectionCustomer which allowed the TableView to populate whenever the user changes options on the ComboBox.
ComboBoxSelectCustomer.setOnAction((event) -> {
});
I want to move to next stage after Timer but when I run the page is frozen.
I want some help please to resolve this problem, I'm new in JavaFX .
I want to go to next screen after a specific time that I choose because this screen is a load screen
this is my code:
/*
* 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 chapitreapp;
import ressources.FadeInLeftTransition;
import ressources.FadeInRightTransition;
import ressources.FadeInTransition;
import ressources.config;
import ressources.config2;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.concurrent.TimeUnit;
import javafx.application.Platform;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import org.springframework.beans.*;
import org.springframework.context.*;
/**
* FXML Controller class
*
* #author anas
*/
public class LoadController implements Initializable {
#FXML
private Text lblWelcome;
#FXML
private Text lblRudy;
#FXML
private VBox vboxBottom;
#FXML
private Label lblClose;
Stage stage;
#FXML
private ImageView imgLoading;
/**
* Initializes the controller class.
* #param url
* #param rb
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
longStart();
lblClose.setOnMouseClicked((MouseEvent event) -> {
Platform.exit();
System.exit(0);
});
// TODO
}
private void longStart() {
Service<ApplicationContext> service = new Service<ApplicationContext>() {
#Override
protected Task<ApplicationContext> createTask() {
return new Task<ApplicationContext>() {
#Override
protected ApplicationContext call() throws Exception {
ApplicationContext appContex = config.getInstance().getApplicationContext();
int max = appContex.getBeanDefinitionCount();
updateProgress(0, max);
for (int k = 0; k < max; k++) {
try
{
Thread.sleep(50);
updateProgress(k+1, max);
}
catch(InterruptedException e)
{
System.exit(0);
}
}
return appContex;
}
};
}
};
service.start();
service.setOnRunning((WorkerStateEvent event) -> {
new FadeInLeftTransition(lblWelcome).play();
new FadeInRightTransition(lblRudy).play();
new FadeInTransition(vboxBottom).play();
});
service.setOnSucceeded((WorkerStateEvent event) -> {
config2 config = new config2();
config.newStage(stage, lblClose, "/chapitreapp/FXMLDocument.fxml", "Sample Apps", true, StageStyle.UNDECORATED, false);
});
}
}
where did I go wrong?
Something along these lines, in your onSucceeded event handler, or a method that it calls...
try {
URL url = this.getClass().getResource("nextScene.fxml");
if (url != null) {
FXMLLoader loader = new FXMLLoader(url);
Parent root = loader.load(url);
Scene newScene = new Scene(root);
this.getStage().setScene(newScene);
} else {
System.out.println("URL was null");
}
} catch (Exception e) {
System.out.println(e);
}
In your controller, you will need to have some means of setting the stage, either via a constructor that accepts the Stage object or via a setStage() method. I've used a getStage() method above to access the Stage and set the new Scene object on it.
You could also use the static FXMLLoader load method: Parent root = FXMLLoader.load(url);
This may also be of benefit: https://blogs.oracle.com/acaicedo/entry/managing_multiple_screens_in_javafx1
I have the need to have a selection listener and select method on a pane to be able to monitor and present a highlight when a node is clicked on.
I did the following:
public class PaneWithSelectionListener extends Pane {
private ObjectProperty<Annotation> selectedAnnotation = new SimpleObjectProperty<>();
public PaneWithSelectionListener() {
super();
selectedAnnotation.addListener((obs, oldAnno, newAnno) -> {
if (oldAnno != null) {
oldAnno.setStyle("");
}
if (newAnno != null) {
newAnno.setStyle("-fx-border-color: blue;-fx-border-insets: 5;-fx-border-width: 1;-fx-border-style: dashed;");
}
});
setOnMouseClicked(e->selectAnnotation(null));
}
public void selectAnnotation(Annotation ann){
selectedAnnotation.set(ann);
}
}
And this works great - however I am not able to work with SceneBuilder anymore since my FXML references this PaneWithSelectionListener rather than Pane. I am not sure how to get my custom pane into SceneBuilder. I have looked at other questions and they are all a combination of FXML and Controllers - where this is just a Pane.
Does anyone know of a way to do this, or perhaps swap the Pane for a PaneWithSelectionListener at initialization time?
Thanks
If the issue is just to make your custom class available in SceneBuilder, you can do so with the following steps:
Bundle your custom class (and any supporting classes, such as Annotation) as a jar file
In SceneBuilder, activate the drop-down button next to "Library" in the top of the left pane:
Choose "Import JAR/FXML File..."
Select the Jar file created from step 1
Make sure the class you need access to in SceneBuilder (PaneWithSelectionListener) is checked
Press "Import Component"
PaneWithSelectionListener will now appear in SceneBuilder under "Custom" in the left pane:
You'll notice the drop-down in SceneBuilder has a "Custom Library Folder" option, from which you can open the folder where the jar files are stored. For a quick option, you can just copy jar files to this folder and (after a short delay), the contained classes will appear in the "Custom" list.
I created a CustomCB a combo box which is of type a userObject. In my case I have used <APerson> as userObject. Entire project and the TESTER are here. First one is CustomCB, the components and the JAR file generated out of this code is added to the Library. This can be loaded in SCENE BUILDER. Thereafter it is available for scene design.
Then of course, you have a tester CustomCB2, which also can use a FXML instead of the way I have done.
I actually want the items starting with the text I type in the ComboBox to appear in the list. But I don't know how to do it. Because the FIRST NAME or LAST NAME of the PERSON class can start with 'Pe'. If I find a solution, I will post it here.
This is the Custom Component.
package customCB;
/*
* 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.
*/
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
/**
*
* #author Hornigold Arthur
*/
public class APerson {
private final StringProperty firstName;
private final StringProperty lastName;
private final IntegerProperty familyID;
private final IntegerProperty personID;
public APerson() {
this(null, null, 0,0);
}
/**
* Constructor with some initial data.
*
* #param familyID
* #param familyName
*/
public APerson (String firstName, String lastName, int familyID, int personID) {
this.firstName = new SimpleStringProperty(firstName);
this.lastName = new SimpleStringProperty(lastName);
this.familyID = new SimpleIntegerProperty(familyID);
this.personID = new SimpleIntegerProperty(personID);
}
public int getFamilyID() {
return familyID.get();
}
public void setFamilyID(int FamilyID) {
this.familyID.set(FamilyID);
}
public IntegerProperty familyIDProperty() {
return familyID;
}
public int getPersonID() {
return personID.get();
}
public void setPersonID(int PersonID) {
this.personID.set(PersonID);
}
public IntegerProperty personIDProperty() {
return personID;
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String FirstName) {
this.firstName.set(FirstName);
}
public StringProperty firstNameProperty() {
return firstName;
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String LastName) {
this.lastName.set(LastName);
}
public StringProperty lastNameProperty() {
return lastName;
}
public String toString() {
String name = getFirstName() + " " + getLastName()+ " [" + getFamilyID() +"]";
return name;
}
}
This is the FXML for the Custom Component.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.layout.VBox?>
<fx:root stylesheets="#application.css" type="javafx.scene.layout.VBox" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1">
<ComboBox fx:id="myCustomCombo" editable="true" onAction="#cbOnAction" prefWidth="300.0" style="-fx-background-color: white;" />
</fx:root>
This is the controller for this FXML but do not mention it in FXML file. It throws error.
package customCB;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import org.controlsfx.control.textfield.TextFields;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListView;
import javafx.scene.layout.VBox;
public class CustomComboController extends VBox{
#FXML
private ResourceBundle resources;
#FXML
private URL location;
#FXML
private ComboBox<APerson> myCustomCombo;
#FXML
void cbOnAction(ActionEvent event) {
}
#FXML
void initialize() {
assert myCustomCombo != null : "fx:id=\"myCustomCombo\" was not injected: check your FXML file 'CustomLvFXML.fxml'.";
}
public CustomComboController() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("customCombo.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
public void setCBValues(javafx.collections.ObservableList<APerson> values) {
myCustomCombo.setItems(values);
myCustomCombo.setEditable(true);
TextFields.bindAutoCompletion(myCustomCombo.getEditor(), myCustomCombo.getItems());
}
}
Download controlsfx-8.40.12.jar from WEB and include this in the BUILD PATH as library.
Now create a jar file for this project. "CustomCB.jar".
This JAR file has to be included as custom control in Scene Builder. I use version 10.0.
Now that it is part of Scene builder you can use this component in designing, unless you can do it the way I have done in my TEST CODE. You need to include "CustomCB.jar" as part of the library for building.
This is the code for the tester.
package customCB2;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
public class Main extends Application {
static private javafx.collections.ObservableList<APerson> fathers = javafx.collections.FXCollections.observableArrayList();
static private javafx.collections.ObservableList<APerson> mothers = javafx.collections.FXCollections.observableArrayList();
#Override
public void start(Stage stage) throws Exception {
CustomComboController customControl2 = new CustomComboController();
CustomComboController customControl3 = new CustomComboController();
loadFathers();
loadMothers();
customControl2.setCBValues(fathers);
customControl3.setCBValues(mothers);
VBox root = new VBox();
root.getChildren().addAll(customControl2, customControl3);
stage.setScene(new Scene(root));
stage.setTitle("Custom Control Combo box");
stage.setWidth(300);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
private void loadFathers() {
fathers.clear();
fathers.add(new APerson("Hornigold","Arthur",1,63));
fathers.add(new APerson("Andrews","Sundareson",2,60));
fathers.add(new APerson("Christopher","Easweradoss",3,57));
fathers.add(new APerson("Arthur","Kennedy",4,55));
}
private void loadMothers() {
mothers.clear();
mothers.add(new APerson("Victoria","Arthur",1,95));
mothers.add(new APerson("Eliza", "Daniel",1,60));
mothers.add(new APerson("Nesammal", "Rivington",2,57));
mothers.add(new APerson("Ratnammal","Andews",1,55));
}
}
It needs lot of improvements. If anyone can improvise, please add it here.
i have a question for this sample code.
import java.io.File;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class CopyOfTreeViewSample extends Application {
public static Image folderCollapseImage=new Image(ClassLoader.getSystemResourceAsStream("treeviewsample/folder.png"));
public static Image folderExpandImage=new Image(ClassLoader.getSystemResourceAsStream("treeviewsample/folder-open.png"));
public static Image fileImage=new Image(ClassLoader.getSystemResourceAsStream("treeviewsample/text-x-generic.png"));
public static Image rootImage = new Image(ClassLoader.getSystemResourceAsStream("treeviewsample/computer.png"));
private TreeView treeView;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Sample");
stage.setWidth(300);
stage.setHeight(500);
VBox vbox = new VBox();
vbox.setLayoutX(20);
vbox.setLayoutY(20);
TreeItem<String> root = new SimpleFileTreeItem(Paths.get("C:\\Users\\Jake"), true);
treeView = new TreeView<String>(root);
Button b = new Button("Change");
b.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
// TODO Auto-generated method stub
////// How do i this section write code?//////
}
});
vbox.getChildren().addAll(treeView,b);
vbox.setSpacing(10);
((Group) scene.getRoot()).getChildren().add(vbox);
stage.setScene(scene);
stage.show();
}
public class SimpleFileTreeItem extends TreeItem<String> {
private boolean isRoot = false;
private boolean isFirstTimeChildren = true;
private boolean isFirstTimeLeaf = true;
private boolean isLeaf;
private boolean isDirectory;
public boolean isDirectory(){return(this.isDirectory);}
private String fullPath;
public String getFullPath(){return(this.fullPath);}
public SimpleFileTreeItem(Path f, Boolean flag) {
super(f.toString());
fullPath = f.toString();
isRoot = flag;
if(!isRoot)
{
if(Files.isDirectory(f))
{
isDirectory = true;
this.setGraphic(new ImageView(folderCollapseImage));
}
else
{
isDirectory = false;
this.setGraphic(new ImageView(fileImage));
}
//set the value
if(!fullPath.endsWith(File.separator)){
String value=f.toString();
int indexOf=value.lastIndexOf(File.separator);
if(indexOf>0){
this.setValue(value.substring(indexOf+1));
}else{
this.setValue(value);
}
}
this.addEventHandler(TreeItem.branchExpandedEvent(),new EventHandler(){
#Override
public void handle(Event e){
SimpleFileTreeItem source=(SimpleFileTreeItem)e.getSource();
if(source.isDirectory()&&source.isExpanded()){
ImageView iv=(ImageView)source.getGraphic();
iv.setImage(folderExpandImage);
}
}
});
this.addEventHandler(TreeItem.branchCollapsedEvent(),new EventHandler(){
#Override
public void handle(Event e){
SimpleFileTreeItem source=(SimpleFileTreeItem)e.getSource();
if(source.isDirectory()&&!source.isExpanded()){
ImageView iv=(ImageView)source.getGraphic();
iv.setImage(folderCollapseImage);
}
}
});
}
else
{
this.setExpanded(true);
if(Files.isDirectory(f))
{
isDirectory = true;
this.setGraphic(new ImageView(rootImage));
}
else
{
isDirectory = false;
this.setGraphic(new ImageView(fileImage));
}
}
}
#Override
public ObservableList<TreeItem<String>> getChildren() {
if (isFirstTimeChildren) {
isFirstTimeChildren = false;
/*
* First getChildren() call, so we actually go off and determine the
* children of the File contained in this TreeItem.
*/
super.getChildren().setAll(buildChildren(this));
}
return super.getChildren();
}
#Override
public boolean isLeaf() {
if (isFirstTimeLeaf) {
isFirstTimeLeaf = false;
File f = new File(fullPath);
isLeaf = f.isFile();
}
return isLeaf;
}
/**
* Returning a collection of type ObservableList containing TreeItems, which
* represent all children available in handed TreeItem.
*
* #param TreeItem
* the root node from which children a collection of TreeItem
* should be created.
* #return an ObservableList<TreeItem<File>> containing TreeItems, which
* represent all children available in handed TreeItem. If the
* handed TreeItem is a leaf, an empty list is returned.
*/
private ObservableList<TreeItem<String>> buildChildren(TreeItem<String> TreeItem) {
File f = new File(fullPath);
if (f != null && f.isDirectory()) {
File[] files = f.listFiles();
if (files != null) {
ObservableList<TreeItem<String>> children = FXCollections
.observableArrayList();
for (File childFile : files) {
children.add(new SimpleFileTreeItem(childFile.toPath(), false));
}
return children;
}
}
return FXCollections.emptyObservableList();
}
}
I want to select the file that corresponds to the path when the button is pressed .
my eclipse project path is c:\java\samplecode.
I was trying to solve by using Absolutepath the result is c:\java\samplecode\samplefile.txt
i want this path.(c:\Users\jake\samplefile.txt)
Thank you for advice and tips.
Using the setup you have, you should be able to do
b.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
SimpleFileTreeItem<String> selectedItem = (SimpleFileTreeItem)treeView.getSelectionModel().getSelectedItem();
if (selectedItem != null) {
String pathString = selectedItem.getFullPath();
}
}
});
(If you also do
b.disableProperty().bind(
Bindings.isNull(treeView.getSelectionModel().selectedItemProperty()));
then you can safely skip the check for null in the handler.)
I think a better approach would be to make SimpleFileTreeItem a TreeItem<Path>. Then you just keep the Path as the value of the tree item, and you can use a cell factory to just display the file name.
Here is an example using this approach. I took out the images (so it can be executed without relying on external resources) and also a lot of the other unnecessary code.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Collectors;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class CopyOfTreeViewSample extends Application {
private TreeView<Path> treeView;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
stage.setTitle("Sample");
stage.setWidth(300);
stage.setHeight(500);
VBox vbox = new VBox();
vbox.setPadding(new Insets(20));
TreeItem<Path> root = new SimpleFileTreeItem(
Paths.get(System.getProperty("user.home")));
root.setExpanded(true);
treeView = new TreeView<Path>(root);
treeView.setCellFactory(treeView -> new TreeCell<Path>() {
#Override
public void updateItem(Path path, boolean empty) {
super.updateItem(path, empty);
if (empty) {
setText(null);
} else {
setText(path.getFileName().toString());
}
}
});
Button b = new Button("Change");
b.disableProperty().bind(Bindings.isNull(treeView.getSelectionModel().selectedItemProperty()));
b.setOnAction(event -> {
Path selectedPath = treeView.getSelectionModel().getSelectedItem().getValue() ;
// do something with selectedPath...
System.out.println(selectedPath);
});
vbox.getChildren().addAll(treeView, b);
vbox.setSpacing(10);
Scene scene = new Scene(vbox);
stage.setScene(scene);
stage.show();
}
public class SimpleFileTreeItem extends TreeItem<Path> {
private boolean isFirstTimeChildren = true;
private boolean isFirstTimeLeaf = true;
private boolean isLeaf;
public boolean isDirectory() {
return Files.isDirectory(getValue());
}
public SimpleFileTreeItem(Path f) {
super(f);
}
#Override
public ObservableList<TreeItem<Path>> getChildren() {
if (isFirstTimeChildren) {
isFirstTimeChildren = false;
/*
* First getChildren() call, so we actually go off and determine
* the children of the File contained in this TreeItem.
*/
super.getChildren().setAll(buildChildren());
}
return super.getChildren();
}
#Override
public boolean isLeaf() {
if (isFirstTimeLeaf) {
isFirstTimeLeaf = false;
isLeaf = Files.exists(getValue()) && ! Files.isDirectory(getValue());
}
return isLeaf;
}
/**
* Returning a collection of type ObservableList containing TreeItems,
* which represent all children of this TreeITem.
*
*
* #return an ObservableList<TreeItem<File>> containing TreeItems, which
* represent all children available in this TreeItem. If the
* handed TreeItem is a leaf, an empty list is returned.
*/
private ObservableList<TreeItem<Path>> buildChildren() {
if (Files.isDirectory(getValue())) {
try {
return Files.list(getValue())
.map(SimpleFileTreeItem::new)
.collect(Collectors.toCollection(() -> FXCollections.observableArrayList()));
} catch (IOException e) {
e.printStackTrace();
return FXCollections.emptyObservableList();
}
}
return FXCollections.emptyObservableList();
}
}
}