Issue
I know a little about javafx and trying everything I can. I'm facing certain issues with reflecting changes in "entriesList" which is basically list of "FeedBox" objects which I'm displaying in timeline tab. I'm having very hard time implementing observableList.
I've read to use Bindings.bindContentBidirectional for binding "entiesList" with observableArrayList "entries". By changing "entries" I want to reflect it to "entiesList". Don't know whether it is right approach or not. If you can suggest anything better it would be awesome. And also haven't found proper way to update "textField" attribute in observableList to edit entry.
Here is picture of what I'm trying to do
FeedBox is VBox with date,time and text fields.
Controller class
public class Controller {
public static ObservableList<Node> entries;
@FXML
VBox entriesList;
public void initialize(){
entries = FXCollections.observableArrayList();
try {
ConnectionClass connectionClass = new ConnectionClass();
Connection conn = connectionClass.getConnection();
Statement statement = conn.createStatement();
ResultSet list = statement.executeQuery("SELECT * FROM timeline WHERE user='Kiran' ORDER BY ID DESC;" );
while (list.next()){
entries.add(new FeedBox(list.getString("ID"),list.getString("date"),list.getString("time"),list.getString("text")));
}
entriesList.getChildren().addAll(entries);
Bindings.bindContentBidirectional(entries,entriesList.getChildren());
System.out.println(entriesList.getChildren());
Bindings.bindContent(entries, entriesList.getChildren());
statement.close();
conn.close();
}catch (SQLException e){
e.printStackTrace();
System.out.println("SQLException");
}
}
}
FeedBox class
public class FeedBox extends Region {
private String id;
private VBox feedbox;
private Text dateField,timeField;
private TextArea textField;
private Button editEntry;
public FeedBox(String feed_id,String date,String time,String text){
id = new String(feed_id);
dateField = new Text(date);
timeField = new Text(time);
textField = new TextArea(text);
editEntry = new Button("Edit");
dateField.setTextAlignment(TextAlignment.LEFT);
dateField.setFont(Font.font("Times New Roman Italic",14));
timeField.setTextAlignment(TextAlignment.LEFT);
timeField.setFont(Font.font("Times New Roman Italic",14));
textField.setPrefSize(200,200);
textField.setEditable(false);
editEntry.setVisible(false);
editEntry.addEventHandler(MouseEvent.MOUSE_CLICKED,e ->OnClick_editEntry());
HBox header = new HBox(15,editEntry,dateField,timeField);
header.setPadding(new Insets(5,15,5,10));
header.fillHeightProperty();
header.setAlignment(Pos.TOP_RIGHT);
feedbox = new VBox(10,header,textField);
feedbox.setPadding(new Insets(10,10,10,10));
feedbox.setPrefSize(700,150);
feedbox.addEventHandler(MouseEvent.MOUSE_ENTERED,e->setEditEntryVisibility(true));
feedbox.addEventHandler(MouseEvent.MOUSE_EXITED,e->setEditEntryVisibility(false));
feedbox.setId(id);
getChildren().add(feedbox);
}
public String toString(){
return textField.getText();
}
public void setEditEntryVisibility(boolean flag){
editEntry.setVisible(flag);
}
public void OnClick_editEntry(){
try {
Dialog<ButtonType> editEntryWindow = new Dialog<>();
editEntryWindow.initOwner(feedbox.getScene().getWindow());
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/FXMLFiles/EditEntryDialog.fxml"));
editEntryWindow.getDialogPane().getButtonTypes().add(ButtonType.OK);
editEntryWindow.getDialogPane().getButtonTypes().add(ButtonType.CANCEL);
EditEntryController editEntryController = new EditEntryController(this.id,editEntryWindow);
loader.setController(editEntryController);
editEntryWindow.getDialogPane().setContent(loader.load());
Optional<ButtonType> res = editEntryWindow.showAndWait();
if(res.isPresent() && res.get()==ButtonType.OK){
editEntryController.OnClick_OKButton(this);
}
}catch (IOException ex){
ex.printStackTrace();
}
}
public void setTextField(String text){
textField.setText(text);
}
NewEntryController class
public void OnClick_OKButton(){
String TABLE_NAME="timeline";
String USER_NAME="Kiran";
String TEXT_DATA=textArea.getText();
String DATE= LocalDate.now().toString();
String TIME = formatter.format(LocalTime.now());
String ID;
try {
ConnectionClass connectionClass = new ConnectionClass();
Connection conn = connectionClass.getConnection();
Statement statement = conn.createStatement();
statement.execute("INSERT INTO "+ TABLE_NAME + " (user,date,time,text) VALUES('" + USER_NAME + "','" + DATE + "','"+ TIME + "','" + TEXT_DATA + "')" );
ResultSet res = statement.executeQuery("SELECT ID FROM timeline WHERE DATE='"+DATE+"' AND TIME='"+TIME+"' AND USER='"+USER_NAME+"';");
res.next();
ID = res.getString("ID");
Controller.entries.add(0,new FeedBox(ID,DATE,TIME,TEXT_DATA));
System.out.println(Controller.entries);
statement.close();
conn.close();
}catch (SQLException e){
System.out.println("MySQL db conn error");
e.printStackTrace();
}
System.out.println("NewEntry Window closed with OK button");
}
EditEntryController class
public void OnClick_OKButton(FeedBox feedBox){
String TABLE_NAME="timeline";
String USER_NAME="Kiran";
String TEXT_DATA = textArea.getText();
try {
ConnectionClass connectionClass = new ConnectionClass();
Connection conn = connectionClass.getConnection();
Statement statement = conn.createStatement();
statement.execute("UPDATE timeline SET text=" + "'" + TEXT_DATA + "'" + " WHERE ID=" + id + " AND user=" + "'"+USER_NAME + "';");
statement.close();
conn.close();
}catch (SQLException e){
System.out.println("MySQL db conn error");
e.printStackTrace();
}
int index=Controller.entries.indexOf(feedBox);
Controller.entries.add(index,new FeedBox(id,dateText.getText(),timeText.getText(),textArea.getText()));
Controller.entries.remove(index+1);
System.out.println("onClick:Button@OKButton");
System.out.println("EditEntry Dialog closed with OK button");
System.out.println(Controller.entries);
}
I'm also having this stack trace; while adding FeedBox object in entries in NewEntryController it is added in list two times as shown below stack trace. However it is displayed right in scene(only once).
Exception in thread "JavaFX Application Thread" java.lang.UnsupportedOperationException
at java.base/java.util.Collections$UnmodifiableCollection.add(Collections.java:1058)
at javafx.base/javafx.collections.ListChangeBuilder.nextRemove(ListChangeBuilder.java:204)
at javafx.base/javafx.collections.ObservableListBase.nextRemove(ObservableListBase.java:150)
at javafx.base/javafx.collections.ModifiableObservableListBase.remove(ModifiableObservableListBase.java:181)
at java.base/java.util.AbstractList$Itr.remove(AbstractList.java:387)
at java.base/java.util.AbstractList.removeRange(AbstractList.java:598)
at javafx.base/javafx.collections.ModifiableObservableListBase.removeRange(ModifiableObservableListBase.java:121)
at java.base/java.util.AbstractList$SubList.removeRange(AbstractList.java:811)
at java.base/java.util.AbstractList.clear(AbstractList.java:243)
at javafx.base/javafx.collections.ModifiableObservableListBase$SubObservableList.clear(ModifiableObservableListBase.java:350)
at javafx.base/com.sun.javafx.binding.ContentBinding$ListContentBinding.onChanged(ContentBinding.java:114)
at javafx.base/com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at javafx.base/com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.base/com.sun.javafx.collections.VetoableListDecorator.lambda$new$0(VetoableListDecorator.java:76)
at javafx.base/com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at javafx.base/com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.base/javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.base/javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.base/javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.base/javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at javafx.base/com.sun.javafx.collections.ObservableListWrapper.remove(ObservableListWrapper.java:167)
at javafx.base/com.sun.javafx.collections.VetoableListDecorator.remove(VetoableListDecorator.java:168)
at javafx.base/com.sun.javafx.binding.BidirectionalContentBinding$ListContentBinding.onChanged(BidirectionalContentBinding.java:135)
at javafx.base/com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
at javafx.base/com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.base/javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.base/javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.base/javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.base/javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at javafx.base/javafx.collections.ModifiableObservableListBase.remove(ModifiableObservableListBase.java:183)
at App.EditEntryController.OnClick_OKButton(EditEntryController.java:82)
at App.FeedBox.OnClick_editEntry(FeedBox.java:102)
at App.FeedBox.lambda$new$0(FeedBox.java:47)
at javafx.base/com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
at javafx.graphics/javafx.scene.Scene$ClickGenerator.postProcess(Scene.java:3564)
at javafx.graphics/javafx.scene.Scene$ClickGenerator.access$8200(Scene.java:3492)
at javafx.graphics/javafx.scene.Scene$MouseHandler.process(Scene.java:3860)
at javafx.graphics/javafx.scene.Scene$MouseHandler.access$1200(Scene.java:3579)
at javafx.graphics/javafx.scene.Scene.processMouseEvent(Scene.java:1849)
at javafx.graphics/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2588)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:397)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:389)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:434)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:390)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:433)
at javafx.graphics/com.sun.glass.ui.View.handleMouseEvent(View.java:556)
at javafx.graphics/com.sun.glass.ui.View.notifyMouse(View.java:942)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
at java.base/java.lang.Thread.run(Thread.java:835)
onClick:Button@OKButton
EditEntry Dialog closed with OK button
[hello world, hello world, nice one, hey there, you good?]
Solution
Controller class
Bindings.bindContentBidirectional(entriesList.getChildren(),entries);
By using entriesList.getChildren() as base list and entries as observableList fixed problems with all edit and new entry related problems.
Thanks @avi It was certainly problem with parameters.
Still open for suggestions on code optimization or alternate implementation of anything that can be improved.
Answered By - It's K
Answer Checked By - Marie Seifert (JavaFixing Admin)