So I am making a small program with JavaFX to familiarize myself with it.
I'm pretty sure there is some basic understanding of how javafx works that seems to elude me though, since I'm having some issues I can't find the solution for. Despite researching them thoroughly on google.
Currently I have a setup where I use eclipse and scenebuilder 1.1 (since 2.0 gave me all kinds of trouble).
I have a pretty simple setup with a main application which loads the initial main application window.
public class Main extends Application {
@Override
public void start(final Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/application/ApplicationWindow.fxml"));
Scene scene = new Scene(root);
stage.getIcons().add(new Image("/application/bug3.png"));
stage.setResizable(true);
stage.setTitle("Simple Bugtracker");
stage.setMinHeight(500);
stage.setMinWidth(800);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) { launch(args); }
}
It seems to work fine. I then created a controller class, which contains the properly fx:id'et gui elements as field values, which works fine aswell I can manipulate them with java code.
I'm having two issues so far though.
1) When I delete something from one of my listviews, I have managed to fix the update issue so it removes it from the listview right away by adding a if null scenario. But when I create a new instance of my object type, the listview doesnt update until I restart the program?
2) Second I'm having trouble with a simple int field value in my controller class, I wanna use its current value in a method im calling (set on a button in scenebuilder), but it always seems to insist that even though the value is set correctly, it's still it's original value from when it was instantiated during launch.
This is my quite large, controller class.
public class MyController implements Initializable {
// Logic related fields
public ProjectList<Project> projectList = new ProjectList<Project>();
public int currentProjectIndex = -1;
public Bug currentBug;
// Listview buffers
public ObservableList<Project> projectsListBuffer = FXCollections.observableArrayList();
public ObservableList<Bug> unsolvedListBuffer = FXCollections.observableArrayList();
public ObservableList<Bug> solvedListBuffer = FXCollections.observableArrayList();
// GUI related fields
@FXML public ListView<Project> projectsListView;
@FXML public ListView<Bug> unsolvedListView;
@FXML public ListView<Bug> solvedListView;
@FXML public TextArea topDisplayArea;
@FXML public Button btnCreateProject;
@FXML public TextField titleFieldCreateProject;
@FXML public TextArea descriptionAreaCreateProject;
@FXML public AnchorPane createProjectWindow;
@FXML public AnchorPane projectsListViewAnchor;
@FXML public Label projectTitleLabel;
@FXML public Button createBugButton;
@FXML public TextField titleFieldCreateBug;
@FXML public TextArea descriptionAreaCreateBug;
public Stage createProjectStage;
// public Stage createBugStage;
@Override
public void initialize(URL arg0, ResourceBundle arg1) {
// load data from file system
try {
loadData();
} catch (IOException e) {
e.printStackTrace();
}
// Instantiate gui field values
// projectsListView = new ListView();
// unsolvedListView = new ListView();
// solvedListView = new ListView();
//
//
// topDisplayArea = new TextArea();
// btnCreateProject = new Button();
//
// titleFieldCreateProject = new TextField();
// descriptionAreaCreateProject = new TextArea();
//
// createProjectWindow = new AnchorPane();
// projectsListViewAnchor = new AnchorPane();
//
// projectTitleLabel = new Label();
// createBugButton = new Button();
//
// titleFieldCreateBug = new TextField();
// descriptionAreaCreateBug = new TextArea();
updateListBuffers();
projectsListView.setPrefHeight( getScreenH() );
projectsListView.setItems(projectsListBuffer);
unsolvedListView.setPrefHeight( getScreenH() );
unsolvedListView.setItems(unsolvedListBuffer);
// settings on necessary gui items
topDisplayArea.setPrefHeight( getScreenH() );
topDisplayArea.setPrefWidth( getScreenW() );
topDisplayArea.setEditable(false);
topDisplayArea.setBackground(null); // something to be done here for transparent logo in background of all project descriptions etc.
// ved dobbeltklik i projektlisten, vælg project og sæt titel
projectsListView.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent click) {
if (click.getClickCount() == 2) {
//Use ListView's getSelected Item
currentProjectIndex = projectsListView.getSelectionModel().getSelectedIndex();
Project currentProject = projectList.get(projectsListView.getSelectionModel().getSelectedIndex());
projectTitleLabel.setText(currentProject.getTitle());
System.out.println( "Selected project:"+currentProject.getTitle());
solvedListView.setItems(unsolvedListBuffer);
for (Bug b : currentProject.solvedBugs) {
System.out.println(b.getTitle()+"\n"+b.getErrorDescription());
}
updateListBuffers();
}
}
});
// ved dobbeltklik i uløste bugs listen, sæt top display område
unsolvedListView.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent click) {
if (click.getClickCount() == 2) {
//Use ListView's getSelected Item
currentBug = unsolvedListView.getSelectionModel().getSelectedItem();
topDisplayArea.setText(currentBug.getErrorDescription());
}
}
});
solvedListView.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent click) {
if (click.getClickCount() == 2) {
//Use ListView's getSelected Item
currentBug = solvedListView.getSelectionModel().getSelectedItem();
topDisplayArea.setText(currentBug.getErrorDescription());
}
}
});
// custom listview cell for the projects listview
projectsListView.setCellFactory(new Callback<ListView<Project>, ListCell<Project>>() {
@Override
public ListCell<Project> call(ListView<Project> p) {
ListCell<Project> cell = new ListCell<Project>() {
@Override
protected void updateItem(Project t, boolean bln) {
super.updateItem(t, bln);
if (t != null) {
// program a custom cell with several items in it
Text text = new Text();
Text text2 = new Text();
text.wrappingWidthProperty().bind(p.widthProperty().subtract(15));
text.setText(t.getTitle());
text2.wrappingWidthProperty().bind(p.widthProperty().subtract(15));
text2.setText(t.getCreationDate().toLocaleString());
text.setFont(Font.font ("Verdana", 12));
text2.setFont(Font.font ("Verdana", 10));
text.setFill(Color.BLACK);
text2.setFill(Color.TEAL);
AnchorPane pane = new AnchorPane();
pane.setPrefHeight(90);
pane.setPrefWidth(300);
ImageView imageView = new ImageView();
imageView.setImage(new Image("/application/project1.png"));
imageView.setFitHeight(60);
imageView.setFitWidth(60);
Image imageOk = new Image(getClass().getResourceAsStream("/application/selectionicon.png"));
Button deleteButton = new Button("Delete");
deleteButton.setLayoutX(233);
deleteButton.setLayoutY(60);
text.setLayoutX(70);
text.setLayoutY(30);
text2.setLayoutX(70);
text2.setLayoutY(50);
pane.getChildren().addAll(imageView, text, text2, deleteButton);
// delete actionevent
deleteButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
Alert alert = new Alert(AlertType.CONFIRMATION);
alert.setTitle("Confirm deletion");
alert.setHeaderText("Are you sure you want to delete this project?");
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == ButtonType.OK){
int selIndex = projectsListView.getSelectionModel().getSelectedIndex();
if (selIndex>-1) {
projectsListBuffer.remove(selIndex);
projectList.remove(selIndex);
projectsListView.setItems(projectsListBuffer);
projectList.save();
}
} else {
System.out.println("DENIED!!");
}
}
});
setPrefWidth(0);
setGraphic(pane);
} else {
setText(null);
setGraphic(null);
}
}
};
return cell;
}
});
// custom listview cell for the unsolved bugs listview
unsolvedListView.setCellFactory(new Callback<ListView<Bug>, ListCell<Bug>>() {
@Override
public ListCell<Bug> call(ListView<Bug> p) {
ListCell<Bug> cell = new ListCell<Bug>() {
@Override
protected void updateItem(Bug t, boolean bln) {
super.updateItem(t, bln);
if (t != null) {
// program a custom cell with several items in it
Text text = new Text();
Text text2 = new Text();
text.wrappingWidthProperty().bind(p.widthProperty().subtract(15));
text.setText(t.getTitle());
text2.wrappingWidthProperty().bind(p.widthProperty().subtract(15));
text2.setText(t.getCreationDate().toLocaleString());
text.setFont(Font.font ("Verdana", 12));
text2.setFont(Font.font ("Verdana", 10));
text.setFill(Color.BLACK);
text2.setFill(Color.TEAL);
AnchorPane pane = new AnchorPane();
pane.setPrefHeight(90);
pane.setPrefWidth(300);
ImageView imageView = new ImageView();
imageView.setImage(new Image("/application/bug3.png"));
imageView.setFitHeight(60);
imageView.setFitWidth(60);
Image imageOk = new Image(getClass().getResourceAsStream("/application/selectionicon.png"));
Button selectButton = new Button("Select");
Button deleteButton = new Button("Delete");
selectButton.setLayoutX(233);
selectButton.setLayoutY(60);
deleteButton.setLayoutX(180);
deleteButton.setLayoutY(60);
text.setLayoutX(70);
text.setLayoutY(30);
text2.setLayoutX(70);
text2.setLayoutY(50);
pane.getChildren().addAll(imageView, text, text2);
deleteButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
projectsListBuffer.remove(projectsListView.getSelectionModel().getSelectedIndex());
projectList.remove(projectsListView.getSelectionModel().getSelectedIndex());
projectsListView.setItems(projectsListBuffer);
projectList.save();
}
});
setPrefWidth(0);
setGraphic(pane);
} else {
setText(null);
setGraphic(null);
}
}
};
return cell;
}
});
}
// loads and show the create project window from it's fxml file (CreateProjectWindow.fxml)
public void showCreateProjectWindow() {
try {
Parent root1 = FXMLLoader.load(getClass().getResource("/application/CreateProjectWindow.fxml"));
createProjectStage = new Stage();
Scene scene = new Scene(root1);
createProjectStage.setScene(scene);
createProjectStage.setMinWidth(374);
createProjectStage.setMinHeight(416);
createProjectStage.setResizable(false);
createProjectStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
// actionevent method that creates a new project MANGLER AT FIKSE DET SÅ LISTVIEWET OPDATERER SIG MED DET SAMME
public void createProject() {
String title = titleFieldCreateProject.getText();
String description = descriptionAreaCreateProject.getText();
Project project = new Project(title, description, new Date());
projectList.add(project);
projectsListBuffer.add(project);
projectList.save();
updateListBuffers();
projectsListView.setItems(projectsListBuffer);
}
// loads and show the create project window from it's fxml file (CreateProjectWindow.fxml)
public void showCreateBugWindow() {
try {
Parent root1 = FXMLLoader.load(getClass().getResource("/application/CreateBugWindow.fxml"));
createProjectStage = new Stage();
Scene scene = new Scene(root1);
createProjectStage.setScene(scene);
createProjectStage.setMinWidth(374);
createProjectStage.setMinHeight(416);
createProjectStage.setResizable(false);
createProjectStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
// actionevent method that creates a new bug MANGLER AT FIKSE DET SÅ LISTVIEWET OPDATERER SIG MED DET SAMME
public void createBug() {
if (currentProjectIndex >-1) {
String title = titleFieldCreateBug.getText();
String description = descriptionAreaCreateBug.getText();
System.out.println(title+"\n"+description);
Bug bug = new Bug(title, description, new Date());
projectList.get(currentProjectIndex).unsolvedBugs.add(bug);
unsolvedListBuffer.add(bug);
projectList.save();
updateListBuffers();
} else {
System.out.println("Failed creation.");
}
}
// load, clear and reload buffers
public void updateListBuffers() {
if (currentProjectIndex>-1) {
unsolvedListBuffer.clear();
for (int i=0; i<projectList.get(currentProjectIndex).unsolvedBugs.size(); i++) {
unsolvedListBuffer.add( projectList.get(currentProjectIndex).unsolvedBugs.get(i) );
}
solvedListBuffer.clear();
for (int i=0; i<projectList.get(currentProjectIndex).solvedBugs.size(); i++) {
solvedListBuffer.add( projectList.get(currentProjectIndex).solvedBugs.get(i) );
}
// unsolvedListView.setItems(null);
// solvedListView.setItems(null);
unsolvedListView.setItems(unsolvedListBuffer);
solvedListView.setItems(solvedListBuffer);
}
projectsListBuffer.clear();
for (int i=0; i<projectList.size(); i++) {
projectsListBuffer.add( projectList.get(i) );
}
// projectsListView.setItems(null);
projectsListView.setItems(projectsListBuffer);
}
// file system related methods
public void loadData() throws IOException {
File fil = new File("Project_Data.dat");
if ( !fil.exists() ) {
fil.createNewFile();
projectList = new ProjectList<Project>();
projectList.save();
} else {
projectList = ProjectList.load();
}
}
// practical methods
public double getScreenH() {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
return screenSize.getHeight();
}
public double getScreenW() {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
return screenSize.getWidth();
}
}
The value I'm having trouble with is the currentProjectIndex, it seems to save it's value correctly but when the "createBug()" method is run with the click of a button, it says it's still -1 (as when it was initialized)?
Also regarding the first issue, as you can see I'm calling a window to create a new project or bug and then running the createProject() or createBug() methods, via the click of a button. But it's like the field value in the controller (selectedProjectIndex) isn't saved when I run certain methods?
So in short I can succesfully create projects, save them to a file. But the listview doesnt update before the program is retarted.
Second I can't create any bugs, because the selectedProjectIndex is always perceived as -1 for some reason?
EDIT: Updated controller class with new suggestions.
Stacktrace when I try to open a new window using either showCreateProjectWindow() or showCreateBugWindow() methods.
/C:/Users/Giuseppe/Dropbox/Java/BugTracker/bin/application/CreateProjectWindow.fxml
at javafx.fxml.FXMLLoader.constructLoadException(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.load(Unknown Source)
at application.MyController.showCreateProjectWindow(MyController.java:320)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.reflect.misc.Trampoline.invoke(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.reflect.misc.MethodUtil.invoke(Unknown Source)
at javafx.fxml.FXMLLoader$MethodHandler.invoke(Unknown Source)
at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source)
at javafx.event.Event.fireEvent(Unknown Source)
at javafx.scene.control.MenuItem.fire(Unknown Source)
at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.doSelect(Unknown Source)
at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.lambda$createChildren$341(Unknown Source)
at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer$$Lambda$313/1964728071.handle(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source)
at javafx.event.Event.fireEvent(Unknown Source)
at javafx.scene.Scene$MouseHandler.process(Unknown Source)
at javafx.scene.Scene$MouseHandler.access$1500(Unknown Source)
at javafx.scene.Scene.impl_processMouseEvent(Unknown Source)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$350(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$$Lambda$282/1128114225.get(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(Unknown Source)
at com.sun.glass.ui.View.handleMouseEvent(Unknown Source)
at com.sun.glass.ui.View.notifyMouse(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$145(Unknown Source)
at com.sun.glass.ui.win.WinApplication$$Lambda$36/2117255219.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NullPointerException
at application.MyController.updateListBuffers(MyController.java:399)
at application.MyController.initialize(MyController.java:114)
... 65 more